diff --git a/DEPS b/DEPS
index 3208f77..3dc57fe 100644
--- a/DEPS
+++ b/DEPS
@@ -40,11 +40,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '21171e50f486a7234e1d8edeb0977719c81d5d3b',
+  'skia_revision': '50f7a1e4abea043b57a39ea1da53a0697bfa1f01',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '7b7658d8c800e8a42d2c0b5bc9bbe63155a69a22',
+  'v8_revision': '5c85b29ca3c3d887e9fbf660311f9e94a0e0d3fa',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 1161de84..b2d62f5e 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -2134,6 +2134,64 @@
 
   return results
 
+
+def _CheckEntriesInWATCHLISTSAreSorted(contents, input_api, output_api):
+  watchlists_start_re = input_api.re.compile(r"^  'WATCHLISTS'")
+  entry_re = input_api.re.compile(r"^    '([\dA-Za-z_]+)'")
+
+  watchlist_definitions = []
+  watchlists = []
+
+  in_watchlists = False
+  for line in contents.split('\n'):
+    if not in_watchlists and watchlists_start_re.match(line) is not None:
+      in_watchlists = True
+      continue
+
+    m = entry_re.match(line)
+    if m is not None:
+      name = m.group(1)
+      if not in_watchlists:
+        watchlist_definitions.append(name)
+      else:
+        watchlists.append(name)
+
+  results = []
+
+  sorted_watchlist_definitions = sorted(watchlist_definitions)
+  if sorted_watchlist_definitions != watchlist_definitions:
+    results.append(output_api.PresubmitError(
+        'WATCHLIST_DEFINITIONS entries are not sorted'))
+
+  sorted_watchlists = sorted(watchlists)
+  if sorted_watchlists != watchlists:
+    results.append(output_api.PresubmitError(
+        'WATCHLISTS entries are not sorted'))
+
+  if watchlist_definitions != watchlists:
+    results.append(output_api.PresubmitError(
+        'WATCHLIST_DEFINITIONS doesn\'t match WATCHLISTS'))
+
+  return results
+
+
+def _CheckWATCHLISTS(input_api, output_api):
+  for f in input_api.AffectedFiles(include_deletes=False):
+    if f.LocalPath() == 'WATCHLISTS':
+      contents = input_api.ReadFile(f, 'r')
+
+      try:
+        input_api.ast.literal_eval(contents)
+      except ValueError:
+        return [output_api.PresubmitError('Cannot parse WATCHLISTS' + e)]
+      except TypeError:
+        return [output_api.PresubmitError('Cannot parse WATCHLISTS' + e)]
+
+      return _CheckEntriesInWATCHLISTSAreSorted(contents, input_api, output_api)
+
+  return []
+
+
 def _AndroidSpecificOnUploadChecks(input_api, output_api):
   """Groups checks that target android code."""
   results = []
@@ -2195,6 +2253,7 @@
   results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
   results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
   results.extend(_CheckForRelativeIncludes(input_api, output_api))
+  results.extend(_CheckWATCHLISTS(input_api, output_api))
 
   if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
     results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
@@ -2472,19 +2531,6 @@
   return master
 
 
-def GetDefaultTryConfigs(bots):
-  """Returns a list of ('bot', set(['tests']), filtered by [bots].
-  """
-
-  builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
-
-  # Build up the mapping from tryserver master to bot/test.
-  out = dict()
-  for bot, tests in builders_and_tests.iteritems():
-    out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
-  return out
-
-
 def CheckChangeOnCommit(input_api, output_api):
   results = []
   results.extend(_CommonChecks(input_api, output_api))
diff --git a/WATCHLISTS b/WATCHLISTS
index 042d5add..51d20d74 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -199,6 +199,389 @@
       'filepath': 'build/android/binary_size/|'\
                   'tools/binary_size/',
     },
+    'blink': {
+      'filepath': 'third_party/WebKit/',
+    },
+    'blink_accessibility': {
+      'filepath': 'third_party/WebKit/.*(accessibility|AXObjectCache|WebAX)'
+    },
+    'blink_animation': {
+      'filepath': 'third_party/WebKit/.*([Aa]nimat|[Tt]ransition)',
+    },
+    'blink_app_banner': {
+      'filepath': 'third_party/WebKit/Source/modules/app_banner' \
+                  '|third_party/WebKit/public/platform/modules/app_banner',
+    },
+    'blink_audio': {
+      'filepath': 'third_party/WebKit/Source/platform/audio' \
+                  '|third_party/WebKit/Source/modules/webaudio',
+    },
+    'blink_battery_status': {
+      'filepath': 'third_party/WebKit/Source/modules/battery/' \
+                  '|third_party/WebKit/LayoutTests/battery-status/' \
+                  '|third_party/WebKit/Source/core/frame/PlatformEvent(Controller|Dispatcher)'
+    },
+    'blink_bidi': {
+      'filepath': 'third_party/WebKit/Source/platform/text/.*Bidi' \
+                  '|third_party/WebKit/Source/core/rendering/.*Bidi',
+    },
+    'blink_bindings': {
+      'filepath': 'third_party/WebKit/Source/platform/bindings' \
+                  '|third_party/WebKit/Source/bindings',
+    },
+    'blink_bindings_serialization': {
+      'filepath': 'third_party/WebKit/Source/bindings/(core|modules)/v8/.*[Ss]erializ',
+    },
+    'blink_bluetooth': {
+      'filepath': 'third_party/WebKit/.*[Bb]luetooth'
+    },
+    'blink_canvas2d': {
+      'filepath': 'third_party/WebKit/Source/core/html/canvas' \
+                  '|third_party/WebKit/Source/core/html/HTMLCanvasElement' \
+                  '|third_party/WebKit/Source/modules/canvas2d' \
+                  '|third_party/WebKit/Source/platform/graphics/Canvas2D',
+    },
+    'blink_client_hints': {
+      'filepath': 'third_party/WebKit/Source/core/loader/AcceptClientHints*' \
+                  '|third_party/WebKit/Source/core/loader/FrameFetchContext*' \
+                  '|third_party/WebKit/Source/core/fetch/FetchContext*' \
+                  '|third_party/WebKit/Source/core/fetch/ImageResource*' \
+                  '|third_party/WebKit/Source/core/fetch/ResourceFetcher*'
+    },
+    'blink_clipboard': {
+      'filepath': 'third_party/WebKit/Source/core/clipboard' \
+                  '|third_party/WebKit/Source/core/page/.*Drag' \
+                  '|third_party/WebKit/Source/platform/.*Drag' \
+                  '|third_party/WebKit/Source/platform/clipboard' \
+                  '|third_party/WebKit/Source/web/.*Drag' \
+                  '|third_party/WebKit/public/platform/.*Drag' \
+                  '|third_party/WebKit/public/web/.*Drag',
+    },
+    'blink_css': {
+      'filepath': 'third_party/WebKit/Source/core/css',
+    },
+    'blink_css_flexbox': {
+      'filepath': 'third_party/WebKit/Source/core/rendering/.*Flex' \
+                  '|third_party/WebKit/LayoutTests/fast/deprecated-flexbox/' \
+                  '|third_party/WebKit/LayoutTests/css3/flexbox/' \
+                  '|third_party/WebKit/LayoutTests/ietestcenter/css3/flexbox/'
+    },
+    'blink_css_fragmentation_tests': {
+      'filepath': 'third_party/WebKit/LayoutTests/fast/multicol/' \
+                  '|third_party/WebKit/LayoutTests/fast/pagination/' \
+                  '|third_party/WebKit/LayoutTests/printing/'
+    },
+    'blink_css_grid_layout': {
+      'filepath': 'third_party/WebKit/Source/core/layout/.*Grid' \
+                  '|third_party/WebKit/Source/core/paint/.*Grid' \
+                  '|third_party/WebKit/Source/core/css/.*Grid' \
+                  '|third_party/WebKit/LayoutTests/fast/css-grid-layout/' \
+                  '|third_party/WebKit/LayoutTests/ietestcenter/css3/grid/' \
+                  '|third_party/WebKit/LayoutTests/platform/.*/fast/css-grid-layout/' \
+                  '|third_party/WebKit/LayoutTests/platform/.*/ietestcenter/css3/grid/'
+    },
+    'blink_css_regions': {
+      'filepath': 'third_party/WebKit/Source/core/rendering/.*(Region|FlowThread)' \
+                  '|third_party/WebKit/Source/core/dom/NodeRendering' \
+                  '|third_party/WebKit/Source/core/dom/.*NamedFlow' \
+                  '|third_party/WebKit/Source/core/css/.*Region' \
+                  '|third_party/WebKit/LayoutTests/compositing/regions/' \
+                  '|third_party/WebKit/LayoutTests/fast/regions/' \
+                  '|third_party/WebKit/LayoutTests/platform/chromium.*/fast/regions/'
+    },
+    'blink_custom_elements': {
+      'filepath': 'third_party/WebKit/Source/core/html/custom/' \
+                  '|third_party/WebKit/Source/bindings/core/v8/.*CustomElement',
+    },
+    'blink_device_orientation': {
+      'filepath': 'third_party/WebKit/Source/modules/device_orientation/' \
+                  '|third_party/WebKit/LayoutTests/device_orientation/' \
+                  '|third_party/WebKit/Source/core/frame/PlatformEvent(Controller|Dispatcher)' \
+                  '|third_party/WebKit/Source/core/frame/DeviceSingleWindowEventController'
+    },
+    'blink_devtools': {
+      'filepath': 'third_party/WebKit/.*(inspector|DevTools|devtools)',
+    },
+    'blink_dom': {
+      'filepath': 'third_party/WebKit/Source/core/dom/'
+    },
+    'blink_dom_events': {
+      'filepath': 'third_party/WebKit/Source/core/events/Event\.' \
+                  '|third_party/WebKit/Source/core/events/EventInit' \
+                  '|third_party/WebKit/Source/core/events/EventPath' \
+                  '|third_party/WebKit/Source/core/events/EventListener' \
+                  '|third_party/WebKit/Source/core/events/EventDispatcher' \
+                  '|third_party/WebKit/Source/core/events/EventDispatchMediator' \
+                  '|third_party/WebKit/Source/core/events/EventTarget' \
+                  '|third_party/WebKit/Source/core/events/.*EventContext'
+    },
+    'blink_events': {
+      'filepath': 'third_party/WebKit/Source/core/page/.*Event' \
+                  '|third_party/WebKit/Source/core/dom/.*Event' \
+                  '|third_party/WebKit/Source/core/css/.*Event' \
+                  '|third_party/WebKit/Source/platform/.*Event'
+    },
+    'blink_fetch': {
+      'filepath': 'third_party/WebKit/Source/platform/loader/fetch'
+    },
+    'blink_fetch_api': {
+      'filepath': 'third_party/WebKit/Source/core/xmlhttprequest/' \
+                  '|third_party/WebKit/Source/modules/beacon/' \
+                  '|third_party/WebKit/Source/modules/eventsource/' \
+                  '|third_party/WebKit/Source/modules/fetch/'
+    },
+    'blink_fileapi': {
+      'filepath': 'third_party/WebKit/Source/modules/filesystem/' \
+                  '|third_party/WebKit/Source/core/fileapi/' \
+                  '|third_party/WebKit/Source/platform/.*File' \
+                  '|third_party/WebKit/Source/web/.*File' \
+                  '|third_party/WebKit/LayoutTests/fast/file' \
+                  '|third_party/WebKit/public/.*File'
+    },
+    'blink_frames': {
+      'filepath': 'third_party/WebKit/Source/core/frame/'
+    },
+    'blink_geolocation': {
+      'filepath': 'third_party/WebKit/LayoutTests/geolocation-api/' \
+                  '|third_party/WebKit/Source/modules/geolocation/' \
+                  '|third_party/WebKit/Source/web/.*Geolocation' \
+                  '|third_party/WebKit/public/web/.*Geolocation'
+    },
+    'blink_heap': {
+      'filepath': 'third_party/WebKit/Source/platform/heap' \
+                  '|base/allocator/partition_allocator/'
+    },
+    'blink_html': {
+      'filepath': 'third_party/WebKit/Source/core/html/'
+    },
+    'blink_htmlparser': {
+      'filepath': 'third_party/WebKit/Source/core/html/parser/'
+    },
+    'blink_image_capture': {
+      'filepath': 'third_party/WebKit/Source/modules/imagecapture' \
+                  '|third_party/WebKit/LayoutTests/fast/imagecapture/' \
+                  '|third_party/WebKit/LayoutTests/imagecapture/'
+    },
+    'blink_indexed_db': {
+      'filepath': 'third_party/WebKit/Source/modules/indexeddb/' \
+                  '|third_party/WebKit/Source/web/.*IDB' \
+                  '|third_party/WebKit/LayoutTests/storage/indexeddb' \
+                  '|third_party/WebKit/public/platform/.*IDB'
+    },
+    'blink_input': {
+      'filepath': 'third_party/WebKit/Source/core/input/'
+    },
+    'blink_layers': {
+      'filepath': 'third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator' \
+                  '|third_party/WebKit/Source/platform/graphics/GraphicsLayer' \
+                  '|third_party/WebKit/Source/core/layout/Layer'
+    },
+    'blink_layout': {
+      'filepath': 'third_party/WebKit/Source/core/layout' \
+                  '|third_party/WebKit/Source/core/rendering'
+    },
+    'blink_layout_ng': {
+      'filepath': 'third_party/WebKit/Source/core/layout/ng',
+    },
+    'blink_loader': {
+      'filepath': 'third_party/WebKit/Source/core/loader/' \
+                  '|third_party/WebKit/Source/platform/loader/'
+    },
+    'blink_media': {
+      'filepath': 'third_party/WebKit/Source/core/css/mediaControls' \
+                  '|third_party/WebKit/Source/core/html/.*(Audio|Media|Video)' \
+                  '|third_party/WebKit/Source/core/html/shadow/MediaControl' \
+                  '|third_party/WebKit/Source/core/layout/LayoutMedia' \
+                  '|third_party/WebKit/Source/core/layout/LayoutTextTrackContainerElement' \
+                  '|third_party/WebKit/Source/modules/(encryptedmedia|mediasource)' \
+                  '|third_party/WebKit/Source/platform/drm/' \
+                  '|third_party/WebKit/Source/platform/graphics/media/' \
+                  '|third_party/WebKit/Source/web/.*Media' \
+                  '|third_party/WebKit/LayoutTests/media/' \
+                  '|third_party/WebKit/public/.*Media'
+    },
+    'blink_media_queries': {
+      'filepath': 'third_party/WebKit/Source/core/css/CSSMediaRule' \
+                    '|third_party/WebKit/Source/core/css/MediaList' \
+                    '|third_party/WebKit/Source/core/css/MediaQuery' \
+                    '|third_party/WebKit/Source/core/css/parser/MediaQuery'
+    },
+    'blink_mediastream': {
+      'filepath': 'third_party/WebKit/Source/modules/mediastream/' \
+                  '|third_party/WebKit/Source/platform/mediastream/' \
+                  '|third_party/WebKit/Source/platform/exported/WebMediaStream' \
+                  '|third_party/WebKit/Source/platform/exported/WebRTC' \
+                  '|third_party/WebKit/LayoutTests/fast/mediastream/'
+    },
+    'blink_modules': {
+      'filepath': 'third_party/WebKit/Source/modules'
+    },
+    'blink_navigator_content_utils': {
+      'filepath': 'third_party/WebKit/Source/modules/navigatorcontentutils' \
+                  '|third_party/WebKit/LayoutTests/fast/dom/navigatorcontentutils'
+    },
+    'blink_notifications': {
+      'filepath': 'third_party/WebKit/LayoutTests/http/tests/notifications' \
+                  '|third_party/WebKit/Source/modules/notifications' \
+                  '|third_party/WebKit/public/platform/modules/notifications'
+    },
+    'blink_out_of_process_frames': {
+      'filepath': 'third_party/WebKit/Source/core/frame/FrameOwner' \
+                  '|third_party/WebKit/Source/core/frame/Frame\.' \
+                  '|third_party/WebKit/Source/web/WebFrame' \
+                  '|third_party/WebKit/Source/web/WebRemoteFrameImpl'
+    },
+    'blink_owners': {
+      'filepath': 'third_party/WebKit/.*OWNERS',
+    },
+    'blink_paint': {
+      'filepath': 'third_party/WebKit/Source/core/paint/'
+    },
+    'blink_performance_timing': {
+      'filepath': 'third_party/WebKit/Source/core/timing/'
+    },
+    'blink_permissions': {
+      'filepath': 'third_party/WebKit/Source/modules/permissions/' \
+                  '|third_party/WebKit/public/platform/modules/permissions/',
+    },
+    'blink_platform': {
+      'filepath': 'third_party/WebKit/Source/platform'
+    },
+    'blink_platform_graphics': {
+      'filepath': 'third_party/WebKit/Source/platform/fonts' \
+                  '|third_party/WebKit/Source/platform/geometry' \
+                  '|third_party/WebKit/Source/platform/graphics'
+    },
+    'blink_preloadScanner': {
+      'filepath': 'third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner',
+    },
+    'blink_prerender': {
+      'filepath': 'third_party/WebKit/.*(Prerender|loader/LinkLoader|html/HTMLLinkElement)'
+    },
+    'blink_public_api': {
+      'filepath': 'third_party/WebKit/public'
+    },
+    'blink_push_messaging': {
+      'filepath': 'third_party/WebKit/LayoutTests/http/tests/push_messaging' \
+                  '|third_party/WebKit/Source/modules/push_messaging' \
+                  '|third_party/WebKit/public/platform/modules/push_messaging'
+    },
+    'blink_quota': {
+      'filepath': 'third_party/WebKit/Source/modules/quota/' \
+                  '|third_party/WebKit/Source/web/.*Quota' \
+                  '|third_party/WebKit/public/.*Quota'
+    },
+    'blink_scheduler': {
+      'filepath': 'third_party/WebKit/Source/platform/scheduler' \
+                  '|third_party/WebKit/Source/core/html/parser/.*Scheduler'
+    },
+    'blink_screen_orientation': {
+      'filepath': 'third_party/WebKit/Source/modules/screen_orientation/' \
+                  '|third_party/WebKit/public/platform/modules/screen_orientation',
+    },
+    'blink_script': {
+      'filepath': 'third_party/WebKit/Source/bindings/core/v8/.*Module.*' \
+                  '|third_party/WebKit/Source/bindings/core/v8/ScriptController.*' \
+                  '|third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.*' \
+                  '|third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.*'
+                  '|third_party/WebKit/Source/core/dom/.*Modul.*' \
+                  '|third_party/WebKit/Source/core/dom/.*Script.*' \
+                  '|third_party/WebKit/Source/core/html/HTMLScriptElement.*' \
+                  '|third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.*' \
+                  '|third_party/WebKit/Source/core/loader/modulescript/' \
+                  '|third_party/WebKit/Source/core/loader/resource/ScriptResource.*' \
+                  '|third_party/WebKit/Source/core/svg/SVGScriptElement.*' \
+                  '|third_party/WebKit/Source/core/xml/parser/XMLDocumentParser.*'
+    },
+    'blink_serviceworkers' : {
+      'filepath': 'third_party/WebKit/Source/modules/serviceworkers' \
+                  '|third_party/WebKit/LayoutTests/http/tests/serviceworker' \
+                  '|third_party/WebKit/LayoutTests/external/wpt/service-workers'
+    },
+    'blink_serviceworkers_tests' : {
+      'filepath': 'third_party/WebKit/LayoutTests/http/tests/serviceworker' \
+                  '|third_party/WebKit/LayoutTests/external/wpt/service-workers'
+    },
+    'blink_shadow_dom': {
+      'filepath': 'third_party/WebKit/Source/core/dom/.*Shadow' \
+                  '|third_party/WebKit/Source/core/dom/.*Slot' \
+                  '|third_party/WebKit/Source/core/dom/.*InsertionPoint' \
+                  '|third_party/WebKit/Source/core/dom/.*FlatTree'
+    },
+    'blink_spellcheck' : {
+      'filepath': 'third_party/WebKit/Source/core/editing/spellcheck'
+    },
+    'blink_spv2_layout_tests': {
+      'filepath': 'third_party/WebKit/LayoutTests/virtual/spv2'
+    },
+    'blink_streams': {
+      'filepath': 'third_party/WebKit/Source/core/streams/'
+    },
+    'blink_style': {
+      'filepath': 'third_party/WebKit/.*(style/|Style)',
+    },
+    'blink_svg': {
+      'filepath': 'third_party/WebKit/Source/core/(layout/)?svg',
+    },
+    'blink_track': {
+      'filepath': 'third_party/WebKit/Source/core/html/track/' \
+                  '|third_party/WebKit/Source/core/loader/TextTrack' \
+                  '|third_party/WebKit/Source/core/html/HTMLMediaElement' \
+                  '|third_party/WebKit/Source/core/html/HTMLTrackElement' \
+                  '|third_party/WebKit/Source/core/html/shadow/MediaControl' \
+                  '|third_party/WebKit/Source/core/css/mediaControl' \
+                  '|third_party/WebKit/LayoutTests/media/track/'
+    },
+    'blink_url_api': {
+      'filepath': 'third_party/WebKit/Source/core/url/'
+    },
+    'blink_vibration': {
+      'filepath': 'third_party/WebKit/LayoutTests/vibration/' \
+                  '|third_party/WebKit/Source/modules/vibration/'
+    },
+    'blink_viewport_interaction': {
+      'filepath': 'third_party/WebKit/Source/core/css/.*Viewport' \
+                  '|third_party/WebKit/Source/core/dom/ViewportArguments' \
+                  '|third_party/WebKit/Source/core/html/HTMLMetaElement' \
+                  '|third_party/WebKit/Source/core/page/FrameView' \
+                  '|third_party/WebKit/Source/core/page/scrolling'
+    },
+    'blink_w3ctests': {
+      'filepath': 'third_party/WebKit/LayoutTests/external/' \
+                  '|third_party/WebKit/Tools/Scripts/webkitpy/w3c/'
+    },
+    'blink_web': {
+      'filepath': 'third_party/WebKit/Source/web'
+    },
+    'blink_webcomponents': {
+      'filepath': 'third_party/WebKit/Source/core/dom/.*Shadow' \
+                  '|third_party/WebKit/Source/core/dom/.*Slot' \
+                  '|third_party/WebKit/Source/core/dom/.*InsertionPoint' \
+                  '|third_party/WebKit/Source/core/dom/.*FlatTree' \
+                  '|third_party/WebKit/Source/core/html/custom/' \
+                  '|third_party/WebKit/Source/core/html/imports/' \
+                  '|third_party/WebKit/Source/bindings/core/v8/.*CustomElement'
+    },
+    'blink_webp': {
+      'filepath': 'third_party/WebKit/Source/platform/image-decoders/webp' \
+                  '|third_party/WebKit/Source/platform/image-encoders/skia/WEBP'
+    },
+    'blink_websockets': {
+      'filepath': 'third_party/WebKit/Source/modules/websockets/' \
+                  '|third_party/WebKit/Source/platform/modules/websockets/'
+    },
+    'blink_workers': {
+      'filepath': 'third_party/WebKit/Source/core/workers' \
+                  '|third_party/WebKit/LayoutTests/http/tests/workers' \
+                  '|third_party/WebKit/LayoutTests/fast/workers' \
+                  '|third_party/WebKit/LayoutTests/external/wpt/workers'
+    },
+    'blink_wtf': {
+      'filepath': 'third_party/WebKit/Source/wtf',
+    },
+    'blink_xml': {
+      'filepath': 'third_party/WebKit/Source/core/xml/'
+    },
     'bookmarks': {
       'filepath': 'chrome/browser/bookmarks/' \
                   '|chrome/browser/extensions/api/bookmark_manager_private/' \
@@ -1178,10 +1561,6 @@
                   '/vr/|'\
                   'third_party/gvr',
     },
-    'webrtc_browser_tests': {
-      'filepath': 'chrome/browser/media/.*webrtc.*browsertest|'\
-                  'content/browser/media/.*webrtc.*browsertest',
-    },
     'web_share': {
       'filepath': 'chrome/android/java/src/org/chromium/chrome/browser/webshare/'\
                   '|chrome/android/javatests/src/org/chromium/chrome/browser/WebShare.*'\
@@ -1192,6 +1571,10 @@
                   '|third_party/WebKit/public/platform/modules/webshare/'\
                   '|third_party/WebKit/Source/modules/webshare/',
     },
+    'webrtc_browser_tests': {
+      'filepath': 'chrome/browser/media/.*webrtc.*browsertest|'\
+                  'content/browser/media/.*webrtc.*browsertest',
+    },
     'website_settings': {
       'filepath': 'chrome/browser/content_settings/'\
                   '|chrome/browser/ui/views/website_settings/'\
@@ -1219,390 +1602,6 @@
                   '|content/public/browser/host_zoom_map.h' \
                   '|content/public/browser/storage_partition.h'
     },
-
-    'blink': {
-      'filepath': 'third_party/WebKit/',
-    },
-    'blink_accessibility': {
-      'filepath': 'third_party/WebKit/.*(accessibility|AXObjectCache|WebAX)'
-    },
-    'blink_animation': {
-      'filepath': 'third_party/WebKit/.*([Aa]nimat|[Tt]ransition)',
-    },
-    'blink_app_banner': {
-      'filepath': 'third_party/WebKit/Source/modules/app_banner' \
-                  '|third_party/WebKit/public/platform/modules/app_banner',
-    },
-    'blink_audio': {
-      'filepath': 'third_party/WebKit/Source/platform/audio' \
-                  '|third_party/WebKit/Source/modules/webaudio',
-    },
-    'blink_battery_status': {
-      'filepath': 'third_party/WebKit/Source/modules/battery/' \
-                  '|third_party/WebKit/LayoutTests/battery-status/' \
-                  '|third_party/WebKit/Source/core/frame/PlatformEvent(Controller|Dispatcher)'
-    },
-    'blink_bidi': {
-      'filepath': 'third_party/WebKit/Source/platform/text/.*Bidi' \
-                  '|third_party/WebKit/Source/core/rendering/.*Bidi',
-    },
-    'blink_bindings': {
-      'filepath': 'third_party/WebKit/Source/platform/bindings' \
-                  '|third_party/WebKit/Source/bindings',
-    },
-    'blink_bindings_serialization': {
-      'filepath': 'third_party/WebKit/Source/bindings/(core|modules)/v8/.*[Ss]erializ',
-    },
-    'blink_bluetooth': {
-      'filepath': 'third_party/WebKit/.*[Bb]luetooth'
-    },
-    'blink_canvas2d': {
-      'filepath': 'third_party/WebKit/Source/core/html/canvas' \
-                  '|third_party/WebKit/Source/core/html/HTMLCanvasElement' \
-                  '|third_party/WebKit/Source/modules/canvas2d' \
-                  '|third_party/WebKit/Source/platform/graphics/Canvas2D',
-    },
-    'blink_client_hints': {
-      'filepath': 'third_party/WebKit/Source/core/loader/AcceptClientHints*' \
-                  '|third_party/WebKit/Source/core/loader/FrameFetchContext*' \
-                  '|third_party/WebKit/Source/core/fetch/FetchContext*' \
-                  '|third_party/WebKit/Source/core/fetch/ImageResource*' \
-                  '|third_party/WebKit/Source/core/fetch/ResourceFetcher*'
-    },
-    'blink_clipboard': {
-      'filepath': 'third_party/WebKit/Source/core/clipboard' \
-                  '|third_party/WebKit/Source/core/page/.*Drag' \
-                  '|third_party/WebKit/Source/platform/.*Drag' \
-                  '|third_party/WebKit/Source/platform/clipboard' \
-                  '|third_party/WebKit/Source/web/.*Drag' \
-                  '|third_party/WebKit/public/platform/.*Drag' \
-                  '|third_party/WebKit/public/web/.*Drag',
-    },
-    'blink_css': {
-      'filepath': 'third_party/WebKit/Source/core/css',
-    },
-    'blink_css_flexbox': {
-      'filepath': 'third_party/WebKit/Source/core/rendering/.*Flex' \
-                  '|third_party/WebKit/LayoutTests/fast/deprecated-flexbox/' \
-                  '|third_party/WebKit/LayoutTests/css3/flexbox/' \
-                  '|third_party/WebKit/LayoutTests/ietestcenter/css3/flexbox/'
-    },
-    'blink_css_fragmentation_tests': {
-      'filepath': 'third_party/WebKit/LayoutTests/fast/multicol/' \
-                  '|third_party/WebKit/LayoutTests/fast/pagination/' \
-                  '|third_party/WebKit/LayoutTests/printing/'
-    },
-    'blink_css_grid_layout': {
-      'filepath': 'third_party/WebKit/Source/core/layout/.*Grid' \
-                  '|third_party/WebKit/Source/core/paint/.*Grid' \
-                  '|third_party/WebKit/Source/core/css/.*Grid' \
-                  '|third_party/WebKit/LayoutTests/fast/css-grid-layout/' \
-                  '|third_party/WebKit/LayoutTests/ietestcenter/css3/grid/' \
-                  '|third_party/WebKit/LayoutTests/platform/.*/fast/css-grid-layout/' \
-                  '|third_party/WebKit/LayoutTests/platform/.*/ietestcenter/css3/grid/'
-    },
-    'blink_css_regions': {
-      'filepath': 'third_party/WebKit/Source/core/rendering/.*(Region|FlowThread)' \
-                  '|third_party/WebKit/Source/core/dom/NodeRendering' \
-                  '|third_party/WebKit/Source/core/dom/.*NamedFlow' \
-                  '|third_party/WebKit/Source/core/css/.*Region' \
-                  '|third_party/WebKit/LayoutTests/compositing/regions/' \
-                  '|third_party/WebKit/LayoutTests/fast/regions/' \
-                  '|third_party/WebKit/LayoutTests/platform/chromium.*/fast/regions/'
-    },
-    'blink_custom_elements': {
-      'filepath': 'third_party/WebKit/Source/core/html/custom/' \
-                  '|third_party/WebKit/Source/bindings/core/v8/.*CustomElement',
-    },
-    'blink_device_orientation': {
-      'filepath': 'third_party/WebKit/Source/modules/device_orientation/' \
-                  '|third_party/WebKit/LayoutTests/device_orientation/' \
-                  '|third_party/WebKit/Source/core/frame/PlatformEvent(Controller|Dispatcher)' \
-                  '|third_party/WebKit/Source/core/frame/DeviceSingleWindowEventController'
-    },
-    'blink_devtools': {
-      'filepath': 'third_party/WebKit/.*(inspector|DevTools|devtools)',
-    },
-    'blink_dom': {
-      'filepath': 'third_party/WebKit/Source/core/dom/'
-    },
-    'blink_dom_events': {
-      'filepath': 'third_party/WebKit/Source/core/events/Event\.' \
-                  '|third_party/WebKit/Source/core/events/EventInit' \
-                  '|third_party/WebKit/Source/core/events/EventPath' \
-                  '|third_party/WebKit/Source/core/events/EventListener' \
-                  '|third_party/WebKit/Source/core/events/EventDispatcher' \
-                  '|third_party/WebKit/Source/core/events/EventDispatchMediator' \
-                  '|third_party/WebKit/Source/core/events/EventTarget' \
-                  '|third_party/WebKit/Source/core/events/.*EventContext'
-    },
-    'blink_events': {
-      'filepath': 'third_party/WebKit/Source/core/page/.*Event' \
-                  '|third_party/WebKit/Source/core/dom/.*Event' \
-                  '|third_party/WebKit/Source/core/css/.*Event' \
-                  '|third_party/WebKit/Source/platform/.*Event'
-    },
-    'blink_fetch': {
-      'filepath': 'third_party/WebKit/Source/platform/loader/fetch'
-    },
-    'blink_fetch_api': {
-      'filepath': 'third_party/WebKit/Source/core/xmlhttprequest/' \
-                  '|third_party/WebKit/Source/modules/beacon/' \
-                  '|third_party/WebKit/Source/modules/eventsource/' \
-                  '|third_party/WebKit/Source/modules/fetch/'
-    },
-    'blink_fileapi': {
-      'filepath': 'third_party/WebKit/Source/modules/filesystem/' \
-                  '|third_party/WebKit/Source/core/fileapi/' \
-                  '|third_party/WebKit/Source/platform/.*File' \
-                  '|third_party/WebKit/Source/web/.*File' \
-                  '|third_party/WebKit/LayoutTests/fast/file' \
-                  '|third_party/WebKit/public/.*File'
-    },
-    'blink_frames': {
-      'filepath': 'third_party/WebKit/Source/core/frame/'
-    },
-    'blink_geolocation': {
-      'filepath': 'third_party/WebKit/LayoutTests/geolocation-api/' \
-                  '|third_party/WebKit/Source/modules/geolocation/' \
-                  '|third_party/WebKit/Source/web/.*Geolocation' \
-                  '|third_party/WebKit/public/web/.*Geolocation'
-    },
-    'blink_heap': {
-      'filepath': 'third_party/WebKit/Source/platform/heap' \
-                  '|base/allocator/partition_allocator/'
-    },
-    'blink_html': {
-      'filepath': 'third_party/WebKit/Source/core/html/'
-    },
-    'blink_htmlparser': {
-      'filepath': 'third_party/WebKit/Source/core/html/parser/'
-    },
-    'blink_image_capture': {
-      'filepath': 'third_party/WebKit/Source/modules/imagecapture' \
-                  '|third_party/WebKit/LayoutTests/fast/imagecapture/' \
-                  '|third_party/WebKit/LayoutTests/imagecapture/'
-    },
-    'blink_indexed_db': {
-      'filepath': 'third_party/WebKit/Source/modules/indexeddb/' \
-                  '|third_party/WebKit/Source/web/.*IDB' \
-                  '|third_party/WebKit/LayoutTests/storage/indexeddb' \
-                  '|third_party/WebKit/public/platform/.*IDB'
-    },
-    'blink_input': {
-      'filepath': 'third_party/WebKit/Source/core/input/'
-    },
-    'blink_layers': {
-      'filepath': 'third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator' \
-                  '|third_party/WebKit/Source/platform/graphics/GraphicsLayer' \
-                  '|third_party/WebKit/Source/core/layout/Layer'
-    },
-    'blink_layout': {
-      'filepath': 'third_party/WebKit/Source/core/layout' \
-                  '|third_party/WebKit/Source/core/rendering'
-    },
-    'blink_layout_ng': {
-      'filepath': 'third_party/WebKit/Source/core/layout/ng',
-    },
-    'blink_loader': {
-      'filepath': 'third_party/WebKit/Source/core/loader/' \
-                  '|third_party/WebKit/Source/platform/loader/'
-    },
-    'blink_media': {
-      'filepath': 'third_party/WebKit/Source/core/css/mediaControls' \
-                  '|third_party/WebKit/Source/core/html/.*(Audio|Media|Video)' \
-                  '|third_party/WebKit/Source/core/html/shadow/MediaControl' \
-                  '|third_party/WebKit/Source/core/layout/LayoutMedia' \
-                  '|third_party/WebKit/Source/core/layout/LayoutTextTrackContainerElement' \
-                  '|third_party/WebKit/Source/modules/(encryptedmedia|mediasource)' \
-                  '|third_party/WebKit/Source/platform/drm/' \
-                  '|third_party/WebKit/Source/platform/graphics/media/' \
-                  '|third_party/WebKit/Source/web/.*Media' \
-                  '|third_party/WebKit/LayoutTests/media/' \
-                  '|third_party/WebKit/public/.*Media'
-    },
-    'blink_media_queries': {
-      'filepath': 'third_party/WebKit/Source/core/css/CSSMediaRule' \
-                    '|third_party/WebKit/Source/core/css/MediaList' \
-                    '|third_party/WebKit/Source/core/css/MediaQuery' \
-                    '|third_party/WebKit/Source/core/css/parser/MediaQuery'
-    },
-    'blink_mediastream': {
-      'filepath': 'third_party/WebKit/Source/modules/mediastream/' \
-                  '|third_party/WebKit/Source/platform/mediastream/' \
-                  '|third_party/WebKit/Source/platform/exported/WebMediaStream' \
-                  '|third_party/WebKit/Source/platform/exported/WebRTC' \
-                  '|third_party/WebKit/LayoutTests/fast/mediastream/'
-    },
-    'blink_modules': {
-      'filepath': 'third_party/WebKit/Source/modules'
-    },
-    'blink_navigator_content_utils': {
-      'filepath': 'third_party/WebKit/Source/modules/navigatorcontentutils' \
-                  '|third_party/WebKit/LayoutTests/fast/dom/navigatorcontentutils'
-    },
-    'blink_notifications': {
-      'filepath': 'third_party/WebKit/LayoutTests/http/tests/notifications' \
-                  '|third_party/WebKit/Source/modules/notifications' \
-                  '|third_party/WebKit/public/platform/modules/notifications'
-    },
-    'blink_out_of_process_frames': {
-      'filepath': 'third_party/WebKit/Source/core/frame/FrameOwner' \
-                  '|third_party/WebKit/Source/core/frame/Frame\.' \
-                  '|third_party/WebKit/Source/web/WebFrame' \
-                  '|third_party/WebKit/Source/web/WebRemoteFrameImpl'
-    },
-    'blink_owners': {
-      'filepath': 'third_party/WebKit/.*OWNERS',
-    },
-    'blink_paint': {
-      'filepath': 'third_party/WebKit/Source/core/paint/'
-    },
-    'blink_performance_timing': {
-      'filepath': 'third_party/WebKit/Source/core/timing/'
-    },
-    'blink_permissions': {
-      'filepath': 'third_party/WebKit/Source/modules/permissions/' \
-                  '|third_party/WebKit/public/platform/modules/permissions/',
-    },
-    'blink_platform': {
-      'filepath': 'third_party/WebKit/Source/platform'
-    },
-    'blink_platform_graphics': {
-      'filepath': 'third_party/WebKit/Source/platform/fonts' \
-                  '|third_party/WebKit/Source/platform/geometry' \
-                  '|third_party/WebKit/Source/platform/graphics'
-    },
-    'blink_preloadScanner': {
-      'filepath': 'third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner',
-    },
-    'blink_prerender': {
-      'filepath': 'third_party/WebKit/.*(Prerender|loader/LinkLoader|html/HTMLLinkElement)'
-    },
-    'blink_public_api': {
-      'filepath': 'third_party/WebKit/public'
-    },
-    'blink_push_messaging': {
-      'filepath': 'third_party/WebKit/LayoutTests/http/tests/push_messaging' \
-                  '|third_party/WebKit/Source/modules/push_messaging' \
-                  '|third_party/WebKit/public/platform/modules/push_messaging'
-    },
-    'blink_quota': {
-      'filepath': 'third_party/WebKit/Source/modules/quota/' \
-                  '|third_party/WebKit/Source/web/.*Quota' \
-                  '|third_party/WebKit/public/.*Quota'
-    },
-    'blink_scheduler': {
-      'filepath': 'third_party/WebKit/Source/platform/scheduler' \
-                  '|third_party/WebKit/Source/core/html/parser/.*Scheduler'
-    },
-    'blink_screen_orientation': {
-      'filepath': 'third_party/WebKit/Source/modules/screen_orientation/' \
-                  '|third_party/WebKit/public/platform/modules/screen_orientation',
-    },
-    'blink_script': {
-      'filepath': 'third_party/WebKit/Source/bindings/core/v8/.*Module.*' \
-                  '|third_party/WebKit/Source/bindings/core/v8/ScriptController.*' \
-                  '|third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.*' \
-                  '|third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.*'
-                  '|third_party/WebKit/Source/core/dom/.*Modul.*' \
-                  '|third_party/WebKit/Source/core/dom/.*Script.*' \
-                  '|third_party/WebKit/Source/core/html/HTMLScriptElement.*' \
-                  '|third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.*' \
-                  '|third_party/WebKit/Source/core/loader/modulescript/' \
-                  '|third_party/WebKit/Source/core/loader/resource/ScriptResource.*' \
-                  '|third_party/WebKit/Source/core/svg/SVGScriptElement.*' \
-                  '|third_party/WebKit/Source/core/xml/parser/XMLDocumentParser.*'
-    },
-    'blink_serviceworkers' : {
-      'filepath': 'third_party/WebKit/Source/modules/serviceworkers' \
-                  '|third_party/WebKit/LayoutTests/http/tests/serviceworker' \
-                  '|third_party/WebKit/LayoutTests/external/wpt/service-workers'
-    },
-    'blink_serviceworkers_tests' : {
-      'filepath': 'third_party/WebKit/LayoutTests/http/tests/serviceworker' \
-                  '|third_party/WebKit/LayoutTests/external/wpt/service-workers'
-    },
-    'blink_shadow_dom': {
-      'filepath': 'third_party/WebKit/Source/core/dom/.*Shadow' \
-                  '|third_party/WebKit/Source/core/dom/.*Slot' \
-                  '|third_party/WebKit/Source/core/dom/.*InsertionPoint' \
-                  '|third_party/WebKit/Source/core/dom/.*FlatTree'
-    },
-    'blink_spellcheck' : {
-      'filepath': 'third_party/WebKit/Source/core/editing/spellcheck'
-    },
-    'blink_spv2_layout_tests': {
-      'filepath': 'third_party/WebKit/LayoutTests/virtual/spv2'
-    },
-    'blink_streams': {
-      'filepath': 'third_party/WebKit/Source/core/streams/'
-    },
-    'blink_style': {
-      'filepath': 'third_party/WebKit/.*(style/|Style)',
-    },
-    'blink_svg': {
-      'filepath': 'third_party/WebKit/Source/core/(layout/)?svg',
-    },
-    'blink_track': {
-      'filepath': 'third_party/WebKit/Source/core/html/track/' \
-                  '|third_party/WebKit/Source/core/loader/TextTrack' \
-                  '|third_party/WebKit/Source/core/html/HTMLMediaElement' \
-                  '|third_party/WebKit/Source/core/html/HTMLTrackElement' \
-                  '|third_party/WebKit/Source/core/html/shadow/MediaControl' \
-                  '|third_party/WebKit/Source/core/css/mediaControl' \
-                  '|third_party/WebKit/LayoutTests/media/track/'
-    },
-    'blink_url_api': {
-      'filepath': 'third_party/WebKit/Source/core/url/'
-    },
-    'blink_vibration': {
-      'filepath': 'third_party/WebKit/LayoutTests/vibration/' \
-                  '|third_party/WebKit/Source/modules/vibration/'
-    },
-    'blink_viewport_interaction': {
-      'filepath': 'third_party/WebKit/Source/core/css/.*Viewport' \
-                  '|third_party/WebKit/Source/core/dom/ViewportArguments' \
-                  '|third_party/WebKit/Source/core/html/HTMLMetaElement' \
-                  '|third_party/WebKit/Source/core/page/FrameView' \
-                  '|third_party/WebKit/Source/core/page/scrolling'
-    },
-    'blink_w3ctests': {
-      'filepath': 'third_party/WebKit/LayoutTests/external/' \
-                  '|third_party/WebKit/Tools/Scripts/webkitpy/w3c/'
-    },
-    'blink_web': {
-      'filepath': 'third_party/WebKit/Source/web'
-    },
-    'blink_webcomponents': {
-      'filepath': 'third_party/WebKit/Source/core/dom/.*Shadow' \
-                  '|third_party/WebKit/Source/core/dom/.*Slot' \
-                  '|third_party/WebKit/Source/core/dom/.*InsertionPoint' \
-                  '|third_party/WebKit/Source/core/dom/.*FlatTree' \
-                  '|third_party/WebKit/Source/core/html/custom/' \
-                  '|third_party/WebKit/Source/core/html/imports/' \
-                  '|third_party/WebKit/Source/bindings/core/v8/.*CustomElement'
-    },
-    'blink_webp': {
-      'filepath': 'third_party/WebKit/Source/platform/image-decoders/webp' \
-                  '|third_party/WebKit/Source/platform/image-encoders/skia/WEBP'
-    },
-    'blink_websockets': {
-      'filepath': 'third_party/WebKit/Source/modules/websockets/' \
-                  '|third_party/WebKit/Source/platform/modules/websockets/'
-    },
-    'blink_workers': {
-      'filepath': 'third_party/WebKit/Source/core/workers' \
-                  '|third_party/WebKit/LayoutTests/http/tests/workers' \
-                  '|third_party/WebKit/LayoutTests/fast/workers' \
-                  '|third_party/WebKit/LayoutTests/external/wpt/workers'
-    },
-    'blink_wtf': {
-      'filepath': 'third_party/WebKit/Source/wtf',
-    },
-    'blink_xml': {
-      'filepath': 'third_party/WebKit/Source/core/xml/'
-    },
   },
 
   ##############################################################################
@@ -2280,8 +2279,8 @@
                          'oka+watchvk@chromium.org',
                          'yhanada+watchvk@chromium.org'],
     'virtual_reality': ['feature-vr-reviews@chromium.org'],
-    'webrtc_browser_tests': ['phoglund+watch@chromium.org'],
     'web_share': ['mgiuca+watch@chromium.org'],
+    'webrtc_browser_tests': ['phoglund+watch@chromium.org'],
     'website_settings': ['markusheintz@chromium.org',
                          'msramek+watch@chromium.org',
                          'raymes+watch@chromium.org'],
diff --git a/android_webview/browser/aw_form_database_service_unittest.cc b/android_webview/browser/aw_form_database_service_unittest.cc
index 54ca3c0..f31e02d 100644
--- a/android_webview/browser/aw_form_database_service_unittest.cc
+++ b/android_webview/browser/aw_form_database_service_unittest.cc
@@ -14,7 +14,6 @@
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/autofill/core/common/form_field_data.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/l10n/l10n_util_android.h"
 
 using autofill::AutofillWebDataService;
 using autofill::FormFieldData;
@@ -32,7 +31,6 @@
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     env_ = AttachCurrentThread();
     ASSERT_TRUE(env_ != NULL);
-    ASSERT_TRUE(l10n_util::RegisterLocalizationUtil(env_));
 
     service_.reset(new AwFormDatabaseService(temp_dir_.GetPath()));
   }
diff --git a/ash/system/date/date_view.cc b/ash/system/date/date_view.cc
index 071d7e0..c6346be 100644
--- a/ash/system/date/date_view.cc
+++ b/ash/system/date/date_view.cc
@@ -123,10 +123,6 @@
   PreferredSizeChanged();
 }
 
-void BaseDateTimeView::OnLocaleChanged() {
-  UpdateText();
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 
 DateView::DateView(SystemTrayItem* owner)
diff --git a/ash/system/date/date_view.h b/ash/system/date/date_view.h
index 2386c08..a76fdee 100644
--- a/ash/system/date/date_view.h
+++ b/ash/system/date/date_view.h
@@ -52,7 +52,6 @@
 
   // views::View:
   void ChildPreferredSizeChanged(views::View* child) override;
-  void OnLocaleChanged() override;
 
   // Invokes UpdateText() when the displayed time should change.
   base::OneShotTimer timer_;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentApp.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentApp.java
index 4f367faf..ef248b7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentApp.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentApp.java
@@ -133,7 +133,7 @@
         result.add(CardType.UNKNOWN);
 
         Map<Integer, Integer> cardTypes = getCardTypes();
-        if (data == null || data.supportedTypes == null || data.supportedTypes.length == 0) {
+        if (!isBasicCardTypeSpecified(data)) {
             // Merchant website supports all card types.
             result.addAll(cardTypes.values());
         } else {
@@ -147,6 +147,11 @@
         return result;
     }
 
+    /** @return True if supported card type is specified in data for "basic-card" method. */
+    public static boolean isBasicCardTypeSpecified(PaymentMethodData data) {
+        return data != null && data.supportedTypes != null && data.supportedTypes.length != 0;
+    }
+
     private static Map<Integer, String> getNetworks() {
         Map<Integer, String> networks = new HashMap<>();
         networks.put(BasicCardNetwork.AMEX, "amex");
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
index 81ea3014..59805b59 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -892,10 +892,13 @@
         for (String methodName : methodNames) {
             PaymentDetailsModifier modifier = mModifiers.get(methodName);
 
-            Set<Integer> targetCardTypes =
-                    AutofillPaymentApp.convertBasicCardToTypes(modifier.methodData);
-            targetCardTypes.remove(CardType.UNKNOWN);
-            if (targetCardTypes.size() > 0 && !targetCardTypes.contains(cardType)) continue;
+            if (AutofillPaymentApp.isBasicCardTypeSpecified(modifier.methodData)) {
+                Set<Integer> targetCardTypes =
+                        AutofillPaymentApp.convertBasicCardToTypes(modifier.methodData);
+                targetCardTypes.remove(CardType.UNKNOWN);
+                assert targetCardTypes.size() > 0;
+                if (!targetCardTypes.contains(cardType)) continue;
+            }
 
             Set<String> targetCardNetworks =
                     AutofillPaymentApp.convertBasicCardToNetworks(modifier.methodData);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninActivity.java
index a7afc29..94eac23 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninActivity.java
@@ -35,17 +35,26 @@
     private static final String TAG = "AccountSigninActivity";
     private static final String INTENT_SIGNIN_ACCESS_POINT =
             "AccountSigninActivity.SigninAccessPoint";
-    private static final String INTENT_SELECT_ACCOUNT = "AccountSigninActivity.SelectAccount";
+    private static final String INTENT_SIGNIN_FLOW_TYPE = "AccountSigninActivity.SigninFlowType";
+    private static final String INTENT_ACCOUNT_NAME = "AccountSigninActivity.AccountName";
     private static final String INTENT_IS_DEFAULT_ACCOUNT =
             "AccountSigninActivity.IsDefaultAccount";
 
-    private AccountSigninView mView;
+    @IntDef({SIGNIN_FLOW_DEFAULT, SIGNIN_FLOW_CONFIRMATION_ONLY, SIGNIN_FLOW_ADD_NEW_ACCOUNT})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface SigninFlowType {}
+
+    private static final int SIGNIN_FLOW_DEFAULT = 0;
+    private static final int SIGNIN_FLOW_CONFIRMATION_ONLY = 1;
+    private static final int SIGNIN_FLOW_ADD_NEW_ACCOUNT = 2;
 
     @IntDef({SigninAccessPoint.SETTINGS, SigninAccessPoint.BOOKMARK_MANAGER,
             SigninAccessPoint.RECENT_TABS, SigninAccessPoint.SIGNIN_PROMO,
             SigninAccessPoint.NTP_CONTENT_SUGGESTIONS, SigninAccessPoint.AUTOFILL_DROPDOWN})
     @Retention(RetentionPolicy.SOURCE)
     public @interface AccessPoint {}
+
+    private AccountSigninView mView;
     @AccessPoint private int mAccessPoint;
 
     /**
@@ -56,6 +65,7 @@
     public static void startAccountSigninActivity(Context context, @AccessPoint int accessPoint) {
         Intent intent = new Intent(context, AccountSigninActivity.class);
         intent.putExtra(INTENT_SIGNIN_ACCESS_POINT, accessPoint);
+        intent.putExtra(INTENT_SIGNIN_FLOW_TYPE, SIGNIN_FLOW_DEFAULT);
         context.startActivity(intent);
     }
 
@@ -88,11 +98,23 @@
             String selectAccount, boolean isDefaultAccount) {
         Intent intent = new Intent(context, AccountSigninActivity.class);
         intent.putExtra(INTENT_SIGNIN_ACCESS_POINT, accessPoint);
-        intent.putExtra(INTENT_SELECT_ACCOUNT, selectAccount);
+        intent.putExtra(INTENT_SIGNIN_FLOW_TYPE, SIGNIN_FLOW_CONFIRMATION_ONLY);
+        intent.putExtra(INTENT_ACCOUNT_NAME, selectAccount);
         intent.putExtra(INTENT_IS_DEFAULT_ACCOUNT, isDefaultAccount);
         context.startActivity(intent);
     }
 
+    /**
+     * Starts AccountSigninActivity from "Add account" page.
+     * @param accessPoint {@link AccessPoint} for starting signin flow. Used in metrics.
+     */
+    public static void startFromAddAccountPage(Context context, @AccessPoint int accessPoint) {
+        Intent intent = new Intent(context, AccountSigninActivity.class);
+        intent.putExtra(INTENT_SIGNIN_ACCESS_POINT, accessPoint);
+        intent.putExtra(INTENT_SIGNIN_FLOW_TYPE, SIGNIN_FLOW_ADD_NEW_ACCOUNT);
+        context.startActivity(intent);
+    }
+
     @Override
     @SuppressFBWarnings("DM_EXIT")
     protected void onCreate(Bundle savedInstanceState) {
@@ -125,14 +147,28 @@
         int imageSize = getResources().getDimensionPixelSize(R.dimen.signin_account_image_size);
         ProfileDataCache profileDataCache =
                 new ProfileDataCache(this, Profile.getLastUsedProfile(), imageSize);
-        String selectAccount = getIntent().getStringExtra(INTENT_SELECT_ACCOUNT);
-        if (selectAccount == null) {
-            mView.initFromSelectionPage(profileDataCache, false, this, this);
-        } else {
-            boolean isDefaultAccount =
-                    getIntent().getBooleanExtra(INTENT_IS_DEFAULT_ACCOUNT, false);
-            mView.initFromConfirmationPage(profileDataCache, false, selectAccount, isDefaultAccount,
-                    AccountSigninView.UNDO_ABORT, this, this);
+
+        int flowType = getIntent().getIntExtra(INTENT_SIGNIN_FLOW_TYPE, -1);
+        switch (flowType) {
+            case SIGNIN_FLOW_DEFAULT:
+                mView.initFromSelectionPage(profileDataCache, false, this, this);
+                break;
+            case SIGNIN_FLOW_CONFIRMATION_ONLY: {
+                String accountName = getIntent().getStringExtra(INTENT_ACCOUNT_NAME);
+                if (accountName == null) {
+                    throw new IllegalArgumentException("Account name can't be null!");
+                }
+                boolean isDefaultAccount =
+                        getIntent().getBooleanExtra(INTENT_IS_DEFAULT_ACCOUNT, false);
+                mView.initFromConfirmationPage(profileDataCache, false, accountName,
+                        isDefaultAccount, AccountSigninView.UNDO_ABORT, this, this);
+                break;
+            }
+            case SIGNIN_FLOW_ADD_NEW_ACCOUNT:
+                mView.initFromAddAccountPage(profileDataCache, this, this);
+                break;
+            default:
+                throw new IllegalArgumentException("Unknown signin flow type: " + flowType);
         }
 
         if (getAccessPoint() == SigninAccessPoint.BOOKMARK_MANAGER
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninView.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninView.java
index 2b12e3a..03b53ec 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninView.java
@@ -168,10 +168,10 @@
      * Initializes the view from account selection page. After selecting the account, signin
      * confirmation page will be opened.
      *
-     * @param profileData    ProfileDataCache that will be used to retrieve user account info.
+     * @param profileData ProfileDataCache that will be used to retrieve user account info.
      * @param isChildAccount Whether this view is for a child account.
-     * @param delegate       The UI object creation delegate.
-     * @param listener       The account selection event listener.
+     * @param delegate The UI object creation delegate.
+     * @param listener The account selection event listener.
      */
     public void initFromSelectionPage(ProfileDataCache profileData, boolean isChildAccount,
             Delegate delegate, Listener listener) {
@@ -184,16 +184,37 @@
     }
 
     /**
+     * Initializes the view from account selection page. After selecting the account, signin
+     * confirmation page will be opened.
+     *
+     * @param profileData ProfileDataCache that will be used to retrieve user account info.
+     * @param delegate The UI object creation delegate.
+     * @param listener The account selection event listener.
+     */
+    public void initFromAddAccountPage(
+            ProfileDataCache profileData, Delegate delegate, Listener listener) {
+        setProfileDataCache(profileData);
+        mIsChildAccount = false; // Children profiles can't add accounts.
+        mUndoBehavior = UNDO_ABORT;
+        mDelegate = delegate;
+        mListener = listener;
+        showSigninPage();
+
+        RecordUserAction.record("Signin_AddAccountToDevice");
+        mListener.onNewAccount();
+    }
+
+    /**
      * Initializes the view from signin confirmation page. The account name should be provided by
      * the caller.
      *
-     * @param profileData      ProfileDataCache that will be used to retrieve user account info.
-     * @param isChildAccount   Whether this view is for a child account.
-     * @param accountName      An account that should be used for confirmation page and signin.
+     * @param profileData ProfileDataCache that will be used to retrieve user account info.
+     * @param isChildAccount Whether this view is for a child account.
+     * @param accountName An account that should be used for confirmation page and signin.
      * @param isDefaultAccount Whether {@param accountName} is a default account, used for metrics.
-     * @param undoBehavior     "Undo" button behavior (see {@link UndoBehavior}).
-     * @param delegate         The UI object creation delegate.
-     * @param listener         The account selection event listener.
+     * @param undoBehavior "Undo" button behavior (see {@link UndoBehavior}).
+     * @param delegate The UI object creation delegate.
+     * @param listener The account selection event listener.
      */
     public void initFromConfirmationPage(ProfileDataCache profileData, boolean isChildAccount,
             String accountName, boolean isDefaultAccount, @UndoBehavior int undoBehavior,
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java
index f5febda..76e1d44 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java
@@ -406,6 +406,7 @@
     @Test
     @MediumTest
     @Feature({"Download"})
+    @RetryOnFailure
     public void testDownloadCompletedIsCalled() throws InterruptedException {
         MockDownloadNotifier notifier = new MockDownloadNotifier(getTestContext());
         MockDownloadSnackbarController snackbarController = new MockDownloadSnackbarController();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndBasicCardWithModifiersTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndBasicCardWithModifiersTest.java
index dccbe90..2634375c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndBasicCardWithModifiersTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndBasicCardWithModifiersTest.java
@@ -221,7 +221,7 @@
                 "Mastercard"));
         assertEquals("USD $4.00", mPaymentRequestTestRule.getOrderSummaryTotal());
 
-        // select the other visa card with unknow type and verify modifier is not applied.
+        // select the other visa card with unknown type and verify modifier is not applied.
         mPaymentRequestTestRule.clickOnPaymentMethodSuggestionOptionAndWait(
                 1, mPaymentRequestTestRule.getReadyForInput());
         assertTrue(mPaymentRequestTestRule.getSelectedPaymentInstrumentLabel().startsWith("Visa"));
@@ -229,6 +229,55 @@
     }
 
     /**
+     * Verify modifier for mastercard (any card type) is applied for mastercard.
+     */
+    @Test
+    @MediumTest
+    @Feature({"Payments"})
+    public void testUpdateTotalAndInstrumentLabelWithMastercardModifiers()
+            throws InterruptedException, ExecutionException, TimeoutException {
+        // Mastercard card with complete set of information and unknown type.
+        String guid = mHelper.setCreditCard(new CreditCard("", "https://example.com",
+                true /* isLocal */, true /* isCached */, "Jon Doe", "5555555555554444",
+                "" /* obfuscatedNumber */, "12", "2050", "mastercard", R.drawable.mc_card,
+                CardType.UNKNOWN, mBillingAddressId, "" /* serverId */));
+        mHelper.setCreditCardUseStatsForTesting(guid, 1000, 5000);
+
+        // Credit mastercard with complete set of information.
+        mHelper.addServerCreditCard(new CreditCard("guid_1", "https://example.com",
+                false /* isLocal */, true /* isCached */, "Jon Doe", "5200828282828210",
+                "" /* obfuscatedNumber */, "12", "2050", "mastercard", R.drawable.mc_card,
+                CardType.CREDIT, mBillingAddressId, "server-id-1"));
+        mHelper.setCreditCardUseStatsForTesting("guid_1", 100, 5000);
+
+        // Visa card with complete set of information and unknown type.
+        mHelper.addServerCreditCard(new CreditCard("guid_2", "https://example.com",
+                false /* isLocal */, true /* isCached */, "Jon Doe", "4111111111111111",
+                "" /* obfuscatedNumber */, "12", "2050", "mastercard", R.drawable.mc_card,
+                CardType.UNKNOWN, mBillingAddressId, "server-id-2"));
+        mHelper.setCreditCardUseStatsForTesting("guid_2", 1, 5000);
+
+        mPaymentRequestTestRule.triggerUIAndWait(
+                "mastercard_any_supported_type", mPaymentRequestTestRule.getReadyToPay());
+        assertTrue(mPaymentRequestTestRule.getSelectedPaymentInstrumentLabel().startsWith(
+                "Mastercard"));
+        assertEquals("USD $4.00", mPaymentRequestTestRule.getOrderSummaryTotal());
+
+        // select the other credit Mastercard and verify modifier is applied.
+        mPaymentRequestTestRule.clickOnPaymentMethodSuggestionOptionAndWait(
+                1, mPaymentRequestTestRule.getReadyForInput());
+        assertTrue(mPaymentRequestTestRule.getSelectedPaymentInstrumentLabel().startsWith(
+                "Mastercard"));
+        assertEquals("USD $4.00", mPaymentRequestTestRule.getOrderSummaryTotal());
+
+        // select the other visa card with unknown type and verify modifier is not applied.
+        mPaymentRequestTestRule.clickOnPaymentMethodSuggestionOptionAndWait(
+                2, mPaymentRequestTestRule.getReadyForInput());
+        assertTrue(mPaymentRequestTestRule.getSelectedPaymentInstrumentLabel().startsWith("Visa"));
+        assertEquals("USD $5.00", mPaymentRequestTestRule.getOrderSummaryTotal());
+    }
+
+    /**
      * Verify native app can pay as expected when modifier is applied.
      */
     @Test
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index e1ac7d3e..051a5bb8 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -892,8 +892,7 @@
         {"Learning", kSpeculativeResourcePrefetchingLearning,
          arraysize(kSpeculativeResourcePrefetchingLearning), nullptr}};
 
-#if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MACOSX) || \
-    defined(OS_WIN)
+#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN)
 const FeatureEntry::FeatureParam kPauseBackgroundTabsMinimalEngagment[] = {
     {pausetabs::kFeatureName, pausetabs::kModeParamMinimal}};
 
@@ -1821,12 +1820,12 @@
      ENABLE_DISABLE_VALUE_TYPE(switches::kEnableTranslateNewUX,
                                switches::kDisableTranslateNewUX)},
 #endif  // OS_MACOSX
-#if defined(OS_LINUX) || defined(OS_WIN) || defined(OS_CHROMEOS)
+#if defined(OS_LINUX) || defined(OS_WIN)
     {"translate-2016q2-ui", flag_descriptions::kTranslate2016q2UiName,
      flag_descriptions::kTranslate2016q2UiDescription,
      kOsCrOS | kOsWin | kOsLinux,
      FEATURE_VALUE_TYPE(translate::kTranslateUI2016Q2)},
-#endif  // OS_LINUX || OS_WIN || OS_CHROMEOS
+#endif  // OS_LINUX || OS_WIN
     {"translate-lang-by-ulp", flag_descriptions::kTranslateLanguageByUlpName,
      flag_descriptions::kTranslateLanguageByUlpDescription, kOsAll,
      FEATURE_VALUE_TYPE(translate::kTranslateLanguageByULP)},
@@ -2915,8 +2914,7 @@
      flag_descriptions::kNewOmniboxAnswerTypesDescription, kOsAll,
      FEATURE_VALUE_TYPE(omnibox::kNewOmniboxAnswerTypes)},
 
-#if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MACOSX) || \
-    defined(OS_WIN)
+#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN)
     {"omnibox-entity-suggestions",
      flag_descriptions::kOmniboxEntitySuggestionsName,
      flag_descriptions::kOmniboxEntitySuggestionsDescription, kOsDesktop,
@@ -2927,8 +2925,7 @@
     {"enable-new-app-menu-icon", flag_descriptions::kEnableNewAppMenuIconName,
      flag_descriptions::kEnableNewAppMenuIconDescription, kOsDesktop,
      SINGLE_VALUE_TYPE(switches::kEnableNewAppMenuIcon)},
-#endif  // defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MACOSX) ||
-        // defined(OS_WIN)
+#endif  // defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN)
 
 #if defined(OS_ANDROID)
     {"enable-custom-feedback-ui",
@@ -2995,8 +2992,7 @@
      FEATURE_VALUE_TYPE(chrome::android::kCustomContextMenu)},
 #endif  // OS_ANDROID
 
-#if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MACOSX) || \
-    defined(OS_WIN)
+#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN)
     {pausetabs::kFeatureName, flag_descriptions::kPauseBackgroundTabsName,
      flag_descriptions::kPauseBackgroundTabsDescription, kOsDesktop,
      FEATURE_WITH_PARAMS_VALUE_TYPE(pausetabs::kFeature,
diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h
index e187362..697a8ff 100644
--- a/chrome/browser/browser_process_impl.h
+++ b/chrome/browser/browser_process_impl.h
@@ -137,7 +137,7 @@
   subresource_filter::ContentRulesetService*
   subresource_filter_ruleset_service() override;
 
-#if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
+#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
   void StartAutoupdateTimer() override;
 #endif
 
@@ -297,7 +297,7 @@
   std::unique_ptr<ChromeResourceDispatcherHostDelegate>
       resource_dispatcher_host_delegate_;
 
-#if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
+#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
   base::RepeatingTimer autoupdate_timer_;
 
   // Gets called by autoupdate timer to see if browser needs restart and can be
@@ -305,7 +305,7 @@
   void OnAutoupdateTimer();
   bool CanAutorestartForUpdate() const;
   void RestartBackgroundInstance();
-#endif  // defined(OS_WIN) || defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#endif  // defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
 
   // component updater is normally not used under ChromeOS due
   // to concerns over integrity of data shared between profiles,
diff --git a/chrome/browser/chromeos/login/lock_screen_utils.cc b/chrome/browser/chromeos/login/lock_screen_utils.cc
index cd395fc18..d57c2392 100644
--- a/chrome/browser/chromeos/login/lock_screen_utils.cc
+++ b/chrome/browser/chromeos/login/lock_screen_utils.cc
@@ -96,7 +96,9 @@
   chromeos::CrosSettings* cros_settings = chromeos::CrosSettings::Get();
   const base::ListValue* login_screen_input_methods = nullptr;
   if (!cros_settings->GetList(chromeos::kDeviceLoginScreenInputMethods,
-                              &login_screen_input_methods)) {
+                              &login_screen_input_methods) ||
+      login_screen_input_methods->empty()) {
+    StopEnforcingPolicyInputMethods();
     return;
   }
 
diff --git a/chrome/browser/chromeos/login/login_screen_policy_browsertest.cc b/chrome/browser/chromeos/login/login_screen_policy_browsertest.cc
index 48824f9..e22cf17 100644
--- a/chrome/browser/chromeos/login/login_screen_policy_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_screen_policy_browsertest.cc
@@ -105,6 +105,29 @@
   ASSERT_EQ(0U, imm->GetActiveIMEState()->GetAllowedInputMethods().size());
 }
 
+IN_PROC_BROWSER_TEST_F(LoginScreenPolicyTest, PolicyInputMethodsListEmpty) {
+  content::WindowedNotificationObserver(
+      chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
+      content::NotificationService::AllSources())
+      .Wait();
+
+  input_method::InputMethodManager* imm =
+      input_method::InputMethodManager::Get();
+  ASSERT_TRUE(imm);
+
+  ASSERT_EQ(0U, imm->GetActiveIMEState()->GetAllowedInputMethods().size());
+
+  em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
+  proto.mutable_login_screen_input_methods()->Clear();
+  EXPECT_TRUE(proto.has_login_screen_input_methods());
+  EXPECT_EQ(
+      0, proto.login_screen_input_methods().login_screen_input_methods_size());
+  RefreshDevicePolicyAndWaitForSettingChange(
+      chromeos::kDeviceLoginScreenInputMethods);
+
+  ASSERT_EQ(0U, imm->GetActiveIMEState()->GetAllowedInputMethods().size());
+}
+
 class LoginScreenLocalePolicyTest : public LoginScreenPolicyTest {
  protected:
   LoginScreenLocalePolicyTest() {}
diff --git a/chrome/browser/chromeos/login/ui/webui_login_view.cc b/chrome/browser/chromeos/login/ui/webui_login_view.cc
index 958970c9..dee953d 100644
--- a/chrome/browser/chromeos/login/ui/webui_login_view.cc
+++ b/chrome/browser/chromeos/login/ui/webui_login_view.cc
@@ -409,9 +409,6 @@
     observer.OnPositionRequiresUpdate();
 }
 
-void WebUILoginView::OnLocaleChanged() {
-}
-
 void WebUILoginView::ChildPreferredSizeChanged(View* child) {
   Layout();
   SchedulePaint();
diff --git a/chrome/browser/chromeos/login/ui/webui_login_view.h b/chrome/browser/chromeos/login/ui/webui_login_view.h
index 27084d6..0e3964b 100644
--- a/chrome/browser/chromeos/login/ui/webui_login_view.h
+++ b/chrome/browser/chromeos/login/ui/webui_login_view.h
@@ -126,7 +126,6 @@
 
   // Overridden from views::View:
   void Layout() override;
-  void OnLocaleChanged() override;
   void ChildPreferredSizeChanged(View* child) override;
   void AboutToRequestFocusFromTabTraversal(bool reverse) override;
 
diff --git a/chrome/browser/dom_distiller/tab_utils_browsertest.cc b/chrome/browser/dom_distiller/tab_utils_browsertest.cc
index c494ba3..289963b 100644
--- a/chrome/browser/dom_distiller/tab_utils_browsertest.cc
+++ b/chrome/browser/dom_distiller/tab_utils_browsertest.cc
@@ -86,7 +86,7 @@
   bool loaded_distiller_page_;
 };
 
-#if (defined(OS_LINUX) && defined(OS_CHROMEOS))
+#if defined(OS_CHROMEOS)
 #define MAYBE_TestSwapWebContents DISABLED_TestSwapWebContents
 #else
 #define MAYBE_TestSwapWebContents TestSwapWebContents
diff --git a/chrome/browser/download/chrome_download_manager_delegate.cc b/chrome/browser/download/chrome_download_manager_delegate.cc
index 57e7f29..e4d273b 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate.cc
@@ -875,7 +875,7 @@
         target_info->is_filetype_handled_safely)
       DownloadItemModel(item).SetShouldPreferOpeningInBrowser(true);
 
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if defined(OS_LINUX)
     if (item->GetOriginalMimeType() == "application/x-x509-user-cert")
       DownloadItemModel(item).SetShouldPreferOpeningInBrowser(true);
 #endif
diff --git a/chrome/browser/extensions/api/feedback_private/feedback_service.cc b/chrome/browser/extensions/api/feedback_private/feedback_service.cc
index 9411431..8d1fcef 100644
--- a/chrome/browser/extensions/api/feedback_private/feedback_service.cc
+++ b/chrome/browser/extensions/api/feedback_private/feedback_service.cc
@@ -10,11 +10,11 @@
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/feedback/system_logs/chrome_system_logs_fetcher.h"
-#include "chrome/common/chrome_content_client.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "extensions/browser/blob_reader.h"
 #include "extensions/browser/extensions_browser_client.h"
+#include "extensions/common/extensions_client.h"
 #include "net/base/network_change_notifier.h"
 
 using content::BrowserThread;
@@ -33,7 +33,7 @@
                                    const SendFeedbackCallback& callback) {
   feedback_data->set_locale(
       ExtensionsBrowserClient::Get()->GetApplicationLocale());
-  feedback_data->set_user_agent(GetUserAgent());
+  feedback_data->set_user_agent(ExtensionsClient::Get()->GetUserAgent());
 
   if (!feedback_data->attached_file_uuid().empty()) {
     // Self-deleting object.
diff --git a/chrome/browser/file_select_helper.cc b/chrome/browser/file_select_helper.cc
index 37cc99e..600c16773 100644
--- a/chrome/browser/file_select_helper.cc
+++ b/chrome/browser/file_select_helper.cc
@@ -78,7 +78,7 @@
   return selected_files;
 }
 
-void DeleteFiles(const std::vector<base::FilePath>& paths) {
+void DeleteFiles(std::vector<base::FilePath> paths) {
   for (auto& file_path : paths)
     base::DeleteFile(file_path, false);
 }
@@ -339,9 +339,11 @@
 }
 
 void FileSelectHelper::DeleteTemporaryFiles() {
-  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
-                          base::BindOnce(&DeleteFiles, temporary_files_));
-  temporary_files_.clear();
+  base::PostTaskWithTraits(
+      FROM_HERE,
+      {base::MayBlock(), base::TaskPriority::BACKGROUND,
+       base::TaskShutdownBehavior::BLOCK_SHUTDOWN},
+      base::BindOnce(&DeleteFiles, std::move(temporary_files_)));
 }
 
 void FileSelectHelper::CleanUp() {
@@ -476,9 +478,9 @@
       content::Source<RenderWidgetHost>(
           render_frame_host_->GetRenderViewHost()->GetWidget()));
 
-  BrowserThread::PostTask(
-      BrowserThread::FILE, FROM_HERE,
-      base::BindOnce(&FileSelectHelper::GetFileTypesOnFileThread, this,
+  base::PostTaskWithTraits(
+      FROM_HERE, {base::MayBlock()},
+      base::BindOnce(&FileSelectHelper::GetFileTypesInThreadPool, this,
                      base::Passed(&params)));
 
   // Because this class returns notifications to the RenderViewHost, it is
@@ -489,7 +491,7 @@
   AddRef();
 }
 
-void FileSelectHelper::GetFileTypesOnFileThread(
+void FileSelectHelper::GetFileTypesInThreadPool(
     std::unique_ptr<FileChooserParams> params) {
   select_file_types_ = GetFileTypesFromAcceptType(params->accept_types);
   select_file_types_->allowed_paths =
diff --git a/chrome/browser/file_select_helper.h b/chrome/browser/file_select_helper.h
index 7d1c694..5237d4e8 100644
--- a/chrome/browser/file_select_helper.h
+++ b/chrome/browser/file_select_helper.h
@@ -92,7 +92,7 @@
 
   void RunFileChooser(content::RenderFrameHost* render_frame_host,
                       std::unique_ptr<content::FileChooserParams> params);
-  void GetFileTypesOnFileThread(
+  void GetFileTypesInThreadPool(
       std::unique_ptr<content::FileChooserParams> params);
   void GetSanitizedFilenameOnUIThread(
       std::unique_ptr<content::FileChooserParams> params);
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 50703f2..f6079926 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2444,8 +2444,7 @@
 
 #endif  // defined(OS_WIN)
 
-#if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MACOSX) || \
-    defined(OS_WIN)
+#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN)
 
 const char kOmniboxEntitySuggestionsName[] = "Omnibox entity suggestions";
 const char kOmniboxEntitySuggestionsDescription[] =
@@ -2465,8 +2464,7 @@
 const char kEnableNewAppMenuIconDescription[] =
     "Use the new app menu icon with update notification animations.";
 
-#endif  // defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MACOSX) ||
-        // defined(OS_WIN)
+#endif  // defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN)
 
 #if defined(OS_CHROMEOS)
 
diff --git a/chrome/browser/interstitials/chrome_controller_client.cc b/chrome/browser/interstitials/chrome_controller_client.cc
index 736ee9c..ea9d7be 100644
--- a/chrome/browser/interstitials/chrome_controller_client.cc
+++ b/chrome/browser/interstitials/chrome_controller_client.cc
@@ -129,8 +129,8 @@
 ChromeControllerClient::~ChromeControllerClient() {}
 
 bool ChromeControllerClient::CanLaunchDateAndTimeSettings() {
-#if defined(OS_ANDROID) || defined(OS_CHROMEOS) || defined(OS_LINUX) || \
-    defined(OS_MACOSX) || defined(OS_WIN)
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_MACOSX) || \
+    defined(OS_WIN)
   return true;
 #else
   return false;
diff --git a/chrome/browser/io_thread_unittest.cc b/chrome/browser/io_thread_unittest.cc
index 93042c9..842f9c2 100644
--- a/chrome/browser/io_thread_unittest.cc
+++ b/chrome/browser/io_thread_unittest.cc
@@ -117,8 +117,9 @@
 
  protected:
   IOThreadTestWithIOThreadObject()
-      : thread_bundle_(content::TestBrowserThreadBundle::REAL_IO_THREAD |
-                       content::TestBrowserThreadBundle::DONT_CREATE_THREADS) {
+      : thread_bundle_(
+            content::TestBrowserThreadBundle::REAL_IO_THREAD |
+            content::TestBrowserThreadBundle::DONT_CREATE_BROWSER_THREADS) {
 #if BUILDFLAG(ENABLE_EXTENSIONS)
     event_router_forwarder_ = new extensions::EventRouterForwarder;
 #endif
@@ -153,7 +154,7 @@
     // Now that IOThread object is registered starting the threads will
     // call the IOThread::Init(). This sets up the environment needed for
     // these tests.
-    thread_bundle_.CreateThreads();
+    thread_bundle_.CreateBrowserThreads();
   }
 
   ~IOThreadTestWithIOThreadObject() override {
diff --git a/chrome/browser/profiles/profile_impl_io_data.cc b/chrome/browser/profiles/profile_impl_io_data.cc
index 241f8b93..1381afa 100644
--- a/chrome/browser/profiles/profile_impl_io_data.cc
+++ b/chrome/browser/profiles/profile_impl_io_data.cc
@@ -106,7 +106,7 @@
   }
 #endif  // #if !defined(OS_ANDROID)
 
-#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if defined(OS_ANDROID) || defined(OS_LINUX)
   return net::URLRequestContextBuilder::HttpCacheParams::DISK_SIMPLE;
 #else
   return net::URLRequestContextBuilder::HttpCacheParams::DISK_BLOCKFILE;
diff --git a/chrome/browser/resources/snippets_internals.html b/chrome/browser/resources/snippets_internals.html
index 0c2df4eb..c704187 100644
--- a/chrome/browser/resources/snippets_internals.html
+++ b/chrome/browser/resources/snippets_internals.html
@@ -113,6 +113,9 @@
     <button id="background-fetch-button" type="button">
       Fetch remote suggestions in the background
     </button>
+    <button id="push-dummy-suggestion-10-seconds-button" type="button">
+      Push dummy suggestion in 10 seconds
+    </button>
   </div>
 
   <div id="content-suggestions">
diff --git a/chrome/browser/resources/snippets_internals.js b/chrome/browser/resources/snippets_internals.js
index d9718326..e5a737f 100644
--- a/chrome/browser/resources/snippets_internals.js
+++ b/chrome/browser/resources/snippets_internals.js
@@ -38,6 +38,12 @@
       event.preventDefault();
     });
 
+    $('push-dummy-suggestion-10-seconds-button')
+        .addEventListener('click', function(event) {
+          chrome.send('pushDummySuggestionIn10Seconds');
+          event.preventDefault();
+        });
+
     window.addEventListener('focus', refreshContent);
     window.setInterval(refreshContent, 1000);
 
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index 0372c458..0eb9d41 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -666,7 +666,7 @@
   }
 #endif  // BUILDFLAG(ENABLE_APP_LIST)
 
-#if defined(OS_LINUX) || defined(OS_WIN) || defined(OS_CHROMEOS)
+#if defined(OS_LINUX) || defined(OS_WIN)
   // Dictionary sync is enabled by default.
   if (!disabled_types.Has(syncer::DICTIONARY)) {
     sync_service->RegisterDataTypeController(
@@ -674,7 +674,7 @@
             syncer::DICTIONARY, error_callback, this, syncer::GROUP_UI,
             BrowserThread::GetTaskRunnerForThread(BrowserThread::UI)));
   }
-#endif  // defined(OS_LINUX) || defined(OS_WIN) || defined(OS_CHROMEOS)
+#endif  // defined(OS_LINUX) || defined(OS_WIN)
 
 #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
   sync_service->RegisterDataTypeController(
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_context_menu_cocoa_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_context_menu_cocoa_controller.mm
index 708e470..bb6c1771 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_context_menu_cocoa_controller.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_context_menu_cocoa_controller.mm
@@ -71,6 +71,9 @@
     parent = bookmarkNode_->parent();
   }
 
+  // Close old menu if it's open.
+  // crbug.com/749213
+  [menuController_ cancel];
   Browser* browser = [bookmarkBarController_ browser];
   bookmarkContextMenuController_.reset(
       new BookmarkContextMenuController([bookmarkBarController_ browserWindow],
diff --git a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
index 1ec0a4b..5252411 100644
--- a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
+++ b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
@@ -568,7 +568,13 @@
             UTF16ToUTF8(omnibox_view->GetText()));
 }
 
-IN_PROC_BROWSER_TEST_F(OmniboxViewTest, Escape) {
+// Flaky on Windows and Linux. http://crbug.com/751543
+#if defined(OS_WIN) || defined(OS_LINUX)
+#define MAYBE_Escape DISABLED_Escape
+#else
+#define MAYBE_Escape Escape
+#endif
+IN_PROC_BROWSER_TEST_F(OmniboxViewTest, MAYBE_Escape) {
   ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIHistoryURL));
   chrome::FocusLocationBar(browser());
 
@@ -989,7 +995,13 @@
   EXPECT_FALSE(omnibox_view->model()->is_keyword_selected());
 }
 
-IN_PROC_BROWSER_TEST_F(OmniboxViewTest, AcceptKeywordBySpace) {
+// Flaky on Windows and Linux. http://crbug.com/751543
+#if defined(OS_WIN) || defined(OS_LINUX)
+#define MAYBE_AcceptKeywordBySpace DISABLED_AcceptKeywordBySpace
+#else
+#define MAYBE_AcceptKeywordBySpace AcceptKeywordBySpace
+#endif
+IN_PROC_BROWSER_TEST_F(OmniboxViewTest, MAYBE_AcceptKeywordBySpace) {
   OmniboxView* omnibox_view = NULL;
   ASSERT_NO_FATAL_FAILURE(GetOmniboxView(&omnibox_view));
 
diff --git a/chrome/browser/ui/sad_tab.cc b/chrome/browser/ui/sad_tab.cc
index f33f7f8c..465ab1e 100644
--- a/chrome/browser/ui/sad_tab.cc
+++ b/chrome/browser/ui/sad_tab.cc
@@ -8,6 +8,7 @@
 
 #include "base/metrics/histogram_macros.h"
 #include "base/time/time.h"
+#include "build/build_config.h"
 #include "chrome/browser/net/referrer.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
@@ -182,7 +183,7 @@
       // Only show incognito suggestion if not already in Incognito mode.
       if (!web_contents_->GetBrowserContext()->IsOffTheRecord())
         message_ids.insert(message_ids.begin(), IDS_SAD_TAB_RELOAD_INCOGNITO);
-#if defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if defined(OS_MACOSX) || defined(OS_LINUX)
       // Note: on macOS, Linux and ChromeOS, the first bullet is either one of
       // IDS_SAD_TAB_RELOAD_CLOSE_TABS or IDS_SAD_TAB_RELOAD_CLOSE_NOTABS
       // followed by one of the above suggestions.
diff --git a/chrome/browser/ui/views/payments/payment_request_item_list.cc b/chrome/browser/ui/views/payments/payment_request_item_list.cc
index f37c9d1..4ca139e 100644
--- a/chrome/browser/ui/views/payments/payment_request_item_list.cc
+++ b/chrome/browser/ui/views/payments/payment_request_item_list.cc
@@ -187,6 +187,7 @@
 
 void PaymentRequestItemList::Clear() {
   items_.clear();
+  selected_item_ = nullptr;
 }
 
 std::unique_ptr<views::View> PaymentRequestItemList::CreateListView() {
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
index 71f345e1..0474098 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -600,7 +600,7 @@
     else
       target_tabstrip->GetWidget()->SetCapture(attached_tabstrip_);
 
-#if !defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if !defined(OS_LINUX)
     // EndMoveLoop is going to snap the window back to its original location.
     // Hide it so users don't see this. Hiding a window in Linux aura causes
     // it to lose capture so skip it.
diff --git a/chrome/browser/ui/webui/snippets_internals_message_handler.cc b/chrome/browser/ui/webui/snippets_internals_message_handler.cc
index 96cd84a..399751b 100644
--- a/chrome/browser/ui/webui/snippets_internals_message_handler.cc
+++ b/chrome/browser/ui/webui/snippets_internals_message_handler.cc
@@ -14,6 +14,7 @@
 #include "base/command_line.h"
 #include "base/feature_list.h"
 #include "base/i18n/time_formatting.h"
+#include "base/json/json_reader.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/field_trial.h"
@@ -23,6 +24,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/android/chrome_feature_list.h"
 #include "chrome/browser/ntp_snippets/content_suggestions_service_factory.h"
@@ -35,17 +37,19 @@
 #include "components/ntp_snippets/pref_names.h"
 #include "components/ntp_snippets/remote/remote_suggestions_fetcher.h"
 #include "components/ntp_snippets/remote/remote_suggestions_provider.h"
+#include "components/ntp_snippets/remote/remote_suggestions_provider_impl.h"
 #include "components/ntp_snippets/switches.h"
 #include "components/offline_pages/core/offline_page_feature.h"
 #include "components/prefs/pref_service.h"
 #include "components/variations/variations_associated_data.h"
 #include "content/public/browser/web_ui.h"
 
-using ntp_snippets::ContentSuggestion;
 using ntp_snippets::Category;
 using ntp_snippets::CategoryInfo;
 using ntp_snippets::CategoryStatus;
+using ntp_snippets::ContentSuggestion;
 using ntp_snippets::KnownCategories;
+using ntp_snippets::RemoteSuggestion;
 using ntp_snippets::RemoteSuggestionsProvider;
 using ntp_snippets::UserClassifier;
 
@@ -149,6 +153,15 @@
   return result;
 }
 
+std::string TimeToJSONTimeString(const base::Time time) {
+  base::Time::Exploded exploded;
+  time.UTCExplode(&exploded);
+  return base::StringPrintf(
+      "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", exploded.year, exploded.month,
+      exploded.day_of_month, exploded.hour, exploded.minute, exploded.second,
+      exploded.millisecond);
+}
+
 }  // namespace
 
 SnippetsInternalsMessageHandler::SnippetsInternalsMessageHandler(
@@ -193,6 +206,12 @@
                  base::Unretained(this)));
 
   web_ui()->RegisterMessageCallback(
+      "pushDummySuggestionIn10Seconds",
+      base::Bind(&SnippetsInternalsMessageHandler::
+                     HandlePushDummySuggestionIn10Seconds,
+                 base::Unretained(this)));
+
+  web_ui()->RegisterMessageCallback(
       "refreshContent",
       base::Bind(&SnippetsInternalsMessageHandler::HandleRefreshContent,
                  base::Unretained(this)));
@@ -348,6 +367,14 @@
       RemoteSuggestionsProvider::FetchStatusCallback());
 }
 
+void SnippetsInternalsMessageHandler::HandlePushDummySuggestionIn10Seconds(
+    const base::ListValue* args) {
+  suggestion_push_timer_.Start(
+      FROM_HERE, base::TimeDelta::FromSeconds(10),
+      base::Bind(&SnippetsInternalsMessageHandler::PushDummySuggestion,
+                 weak_ptr_factory_.GetWeakPtr()));
+}
+
 void SnippetsInternalsMessageHandler::SendAllContent() {
   SendBoolean(
       "flag-article-suggestions",
@@ -508,6 +535,45 @@
       "chrome.SnippetsInternals.receiveProperty", string_name, string_value);
 }
 
+void SnippetsInternalsMessageHandler::PushDummySuggestion() {
+  std::string json =
+      "{"
+      "  \"ids\" : [\"http://url.com\"],"
+      "  \"title\" : \"Pushed Dummy Title %s\","
+      "  \"snippet\" : \"Pushed Dummy Snippet\","
+      "  \"fullPageUrl\" : \"http://url.com\","
+      "  \"creationTime\" : \"%s\","
+      "  \"expirationTime\" : \"%s\","
+      "  \"attribution\" : \"Pushed Dummy Publisher\","
+      "  \"imageUrl\" : \"https://www.google.com/favicon.ico\" "
+      "}";
+
+  const base::Time now = base::Time::Now();
+  json = base::StringPrintf(
+      json.c_str(), base::UTF16ToUTF8(base::TimeFormatTimeOfDay(now)).c_str(),
+      TimeToJSONTimeString(now).c_str(),
+      TimeToJSONTimeString(now + base::TimeDelta::FromMinutes(60)).c_str());
+
+  std::unique_ptr<base::Value> suggestion_value = base::JSONReader::Read(json);
+  DCHECK(suggestion_value != nullptr);
+
+  const base::DictionaryValue* suggestion_dictionary = nullptr;
+  bool success = suggestion_value->GetAsDictionary(&suggestion_dictionary);
+  DCHECK(success);
+
+  std::unique_ptr<RemoteSuggestion> suggestion =
+      RemoteSuggestion::CreateFromContentSuggestionsDictionary(
+          *suggestion_dictionary, /*remote_category_id=*/1,
+          /*fetch_time=*/now);
+  DCHECK(suggestion != nullptr);
+
+  // TODO(vitaliii): Provide JSON directly to BreakingNewsAppHandler once it is
+  // connected to the provider.
+  static_cast<ntp_snippets::RemoteSuggestionsProviderImpl*>(
+      remote_suggestions_provider_)
+      ->PushArticleSuggestionToTheFrontForDebugging(std::move(suggestion));
+}
+
 void SnippetsInternalsMessageHandler::OnDismissedSuggestionsLoaded(
     Category category,
     std::vector<ContentSuggestion> dismissed_suggestions) {
diff --git a/chrome/browser/ui/webui/snippets_internals_message_handler.h b/chrome/browser/ui/webui/snippets_internals_message_handler.h
index 965e2d4..900ab2d 100644
--- a/chrome/browser/ui/webui/snippets_internals_message_handler.h
+++ b/chrome/browser/ui/webui/snippets_internals_message_handler.h
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observer.h"
+#include "base/timer/timer.h"
 #include "components/ntp_snippets/category.h"
 #include "components/ntp_snippets/category_status.h"
 #include "components/ntp_snippets/content_suggestions_service.h"
@@ -61,6 +62,7 @@
   void HandleToggleDismissedSuggestions(const base::ListValue* args);
   void ClearClassification(const base::ListValue* args);
   void FetchRemoteSuggestionsInTheBackground(const base::ListValue* args);
+  void HandlePushDummySuggestionIn10Seconds(const base::ListValue* args);
 
   void SendAllContent();
   void SendClassification();
@@ -70,6 +72,8 @@
   void SendBoolean(const std::string& name, bool value);
   void SendString(const std::string& name, const std::string& value);
 
+  void PushDummySuggestion();
+
   void OnDismissedSuggestionsLoaded(
       ntp_snippets::Category category,
       std::vector<ntp_snippets::ContentSuggestion> dismissed_suggestions);
@@ -94,6 +98,8 @@
            ntp_snippets::Category::CompareByID>
       dismissed_suggestions_;
 
+  base::OneShotTimer suggestion_push_timer_;
+
   base::WeakPtrFactory<SnippetsInternalsMessageHandler> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(SnippetsInternalsMessageHandler);
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index d9cbe42..a71c7203 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -1048,8 +1048,7 @@
 extern const char kEnableInputImeAPI[] = "enable-input-ime-api";
 #endif
 
-#if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MACOSX) || \
-    defined(OS_WIN)
+#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN)
 extern const char kEnableNewAppMenuIcon[] = "enable-new-app-menu-icon";
 #endif
 
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index f24ee09..4ac9fa1 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -332,8 +332,7 @@
 extern const char kEnableInputImeAPI[];
 #endif
 
-#if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MACOSX) || \
-    defined(OS_WIN)
+#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN)
 extern const char kEnableNewAppMenuIcon[];
 #endif
 
diff --git a/chrome/common/extensions/chrome_extensions_client.cc b/chrome/common/extensions/chrome_extensions_client.cc
index 5b08d48..5a04b7f 100644
--- a/chrome/common/extensions/chrome_extensions_client.cc
+++ b/chrome/common/extensions/chrome_extensions_client.cc
@@ -13,6 +13,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_util.h"
 #include "base/values.h"
+#include "chrome/common/chrome_content_client.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/api/api_features.h"
 #include "chrome/common/extensions/api/behavior_features.h"
@@ -336,6 +337,10 @@
   return GetCurrentChannel() == version_info::Channel::UNKNOWN;
 }
 
+std::string ChromeExtensionsClient::GetUserAgent() const {
+  return ::GetUserAgent();
+}
+
 // static
 ChromeExtensionsClient* ChromeExtensionsClient::GetInstance() {
   return g_client.Pointer();
diff --git a/chrome/common/extensions/chrome_extensions_client.h b/chrome/common/extensions/chrome_extensions_client.h
index ff3195b..26f0c17 100644
--- a/chrome/common/extensions/chrome_extensions_client.h
+++ b/chrome/common/extensions/chrome_extensions_client.h
@@ -53,6 +53,7 @@
   std::set<base::FilePath> GetBrowserImagePaths(
       const Extension* extension) override;
   bool ExtensionAPIEnabledInExtensionServiceWorkers() const override;
+  std::string GetUserAgent() const override;
 
   // Get the LazyInstance for ChromeExtensionsClient.
   static ChromeExtensionsClient* GetInstance();
diff --git a/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.cc b/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.cc
index e85d3ee7..72297d9 100644
--- a/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.cc
+++ b/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.cc
@@ -170,11 +170,23 @@
                         /*fetch_time=*/base::Time::Now())) {
     std::string content_json;
     base::JSONWriter::Write(*content, &content_json);
-    LOG(WARNING) << "Received invalid breaking news: " << content_json;
+    LOG(WARNING)
+        << "Received invalid breaking news: can't interpret value, json is "
+        << content_json;
     return;
   }
-  DCHECK_EQ(1u, fetched_categories.size());
-  DCHECK_EQ(1u, fetched_categories[0].suggestions.size());
+  if (fetched_categories.size() != 1) {
+    LOG(WARNING)
+        << "Received invalid breaking news: expected 1 category, but got "
+        << fetched_categories.size();
+    return;
+  }
+  if (fetched_categories[0].suggestions.size() != 1) {
+    LOG(WARNING)
+        << "Received invalid breaking news: expected 1 suggestion, but got "
+        << fetched_categories[0].suggestions.size();
+    return;
+  }
 
   on_new_remote_suggestion_callback_.Run(
       std::move(fetched_categories[0].suggestions[0]));
diff --git a/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc b/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc
index 7af03b0..ff9fd61 100644
--- a/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc
@@ -546,6 +546,11 @@
   return kMaxSuggestionCount;
 }
 
+void RemoteSuggestionsProviderImpl::PushArticleSuggestionToTheFrontForDebugging(
+    std::unique_ptr<RemoteSuggestion> suggestion) {
+  PrependArticleSuggestion(std::move(suggestion));
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Private methods
 
@@ -882,6 +887,41 @@
   content->suggestions = std::move(new_suggestions);
 }
 
+void RemoteSuggestionsProviderImpl::PrependArticleSuggestion(
+    std::unique_ptr<RemoteSuggestion> remote_suggestion) {
+  if (!ready()) {
+    return;
+  }
+
+  ClearExpiredDismissedSuggestions();
+
+  DCHECK_EQ(articles_category_, Category::FromRemoteCategory(
+                                    remote_suggestion->remote_category_id()));
+
+  auto content_it = category_contents_.find(articles_category_);
+  if (content_it == category_contents_.end()) {
+    return;
+  }
+  CategoryContent* content = &content_it->second;
+
+  std::vector<std::unique_ptr<RemoteSuggestion>> suggestions;
+  suggestions.push_back(std::move(remote_suggestion));
+
+  SanitizeReceivedSuggestions(content->dismissed, &suggestions);
+
+  if (!suggestions.empty()) {
+    content->suggestions.insert(content->suggestions.begin(),
+                                std::move(suggestions[0]));
+
+    for (size_t i = 0; i < content->suggestions.size(); ++i) {
+      content->suggestions[i]->set_rank(i);
+    }
+    database_->SaveSnippets(content->suggestions);
+
+    NotifyNewSuggestions(articles_category_, *content);
+  }
+}
+
 void RemoteSuggestionsProviderImpl::DismissSuggestionFromCategoryContent(
     CategoryContent* content,
     const std::string& id_within_category) {
diff --git a/components/ntp_snippets/remote/remote_suggestions_provider_impl.h b/components/ntp_snippets/remote/remote_suggestions_provider_impl.h
index ef70fc4..09c094e 100644
--- a/components/ntp_snippets/remote/remote_suggestions_provider_impl.h
+++ b/components/ntp_snippets/remote/remote_suggestions_provider_impl.h
@@ -142,6 +142,9 @@
   // the constructor.
   CachedImageFetcher& GetImageFetcherForTesting() { return image_fetcher_; }
 
+  void PushArticleSuggestionToTheFrontForDebugging(
+      std::unique_ptr<RemoteSuggestion> suggestion);
+
  private:
   friend class RemoteSuggestionsProviderImplTest;
 
@@ -286,6 +289,10 @@
                             CategoryContent* content,
                             RemoteSuggestion::PtrVector new_suggestions);
 
+  // Adds newly available suggestion at the top of Articles category.
+  void PrependArticleSuggestion(
+      std::unique_ptr<RemoteSuggestion> remote_suggestion);
+
   // Dismisses a suggestion within a given category content.
   // Note that this modifies the suggestion datastructures of |content|
   // invalidating iterators.
diff --git a/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc b/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc
index a285aa2..25d1f89 100644
--- a/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc
@@ -73,11 +73,13 @@
 using testing::Contains;
 using testing::CreateFunctor;
 using testing::ElementsAre;
+using testing::ElementsAreArray;
 using testing::Eq;
 using testing::Field;
 using testing::InSequence;
 using testing::Invoke;
 using testing::IsEmpty;
+using testing::Matcher;
 using testing::Mock;
 using testing::MockFunction;
 using testing::NiceMock;
@@ -2758,4 +2760,119 @@
           Property(&ContentSuggestion::id, MakeArticleID("http://1.com"))));
 }
 
+TEST_F(RemoteSuggestionsProviderImplTest,
+       PrependingShouldNotAffectOtherSuggestions) {
+  // Set up the provider with some article suggestions.
+  auto provider = MakeSuggestionsProvider();
+  std::vector<FetchedCategory> fetched_categories;
+  FetchedCategoryBuilder category_builder =
+      FetchedCategoryBuilder().SetCategory(articles_category());
+  for (int i = 0; i < 10; ++i) {
+    const std::string url = "http://other.com/" + base::IntToString(i);
+    category_builder.AddSuggestionViaBuilder(
+        RemoteSuggestionBuilder().AddId(url).SetUrl(url));
+  }
+  fetched_categories.push_back(category_builder.Build());
+  FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+                        Status::Success(), std::move(fetched_categories));
+
+  // Prepend an article suggestion.
+  const std::string prepended_url = "http://prepended.com/";
+  std::unique_ptr<RemoteSuggestion> prepended_suggestion =
+      RemoteSuggestionBuilder()
+          .AddId(prepended_url)
+          .SetUrl(prepended_url)
+          .Build();
+
+  // TODO(vitaliii): Once the provider sets a callback in BreakingNewsListener,
+  // capture it instead of using this function here and below.
+  provider->PushArticleSuggestionToTheFrontForDebugging(
+      std::move(prepended_suggestion));
+
+  // Check that the prepended suggestion is in the front, and all the others are
+  // still there in the same order.
+  std::vector<Matcher<const ContentSuggestion&>> expected;
+  expected.push_back(
+      Property(&ContentSuggestion::id, MakeArticleID(prepended_url)));
+  for (int i = 0; i < 10; ++i) {
+    expected.push_back(
+        Property(&ContentSuggestion::id,
+                 MakeArticleID("http://other.com/" + base::IntToString(i))));
+  }
+
+  EXPECT_THAT(observer().SuggestionsForCategory(articles_category()),
+              ElementsAreArray(expected));
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest, ShouldNotPrependDismissedSuggestion) {
+  auto provider = MakeSuggestionsProvider();
+
+  // Prepend an article suggestion.
+  const RemoteSuggestionBuilder suggestion_builder =
+      RemoteSuggestionBuilder()
+          .AddId("http://prepended.com")
+          .SetUrl("http://prepended.com");
+
+  provider->PushArticleSuggestionToTheFrontForDebugging(
+      suggestion_builder.Build());
+  ASSERT_THAT(provider->GetSuggestionsForTesting(articles_category()),
+              SizeIs(1));
+
+  // Dismiss it.
+  provider->DismissSuggestion(MakeArticleID("http://prepended.com"));
+  ASSERT_THAT(provider->GetSuggestionsForTesting(articles_category()),
+              IsEmpty());
+
+  // Prepend it again and verify that it is ignored.
+  provider->PushArticleSuggestionToTheFrontForDebugging(
+      suggestion_builder.Build());
+  EXPECT_THAT(provider->GetSuggestionsForTesting(articles_category()),
+              IsEmpty());
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest,
+       ShouldRestorePrependedSuggestionOnTopAfterRestart) {
+  // Set up the provider with some article suggestions.
+  auto provider = MakeSuggestionsProvider();
+  std::vector<FetchedCategory> fetched_categories;
+  FetchedCategoryBuilder category_builder =
+      FetchedCategoryBuilder().SetCategory(articles_category());
+  for (int i = 0; i < 10; ++i) {
+    const std::string url = "http://other.com/" + base::IntToString(i);
+    category_builder.AddSuggestionViaBuilder(
+        RemoteSuggestionBuilder().AddId(url).SetUrl(url));
+  }
+  fetched_categories.push_back(category_builder.Build());
+  FetchTheseSuggestions(provider.get(), /*interactive_request=*/true,
+                        Status::Success(), std::move(fetched_categories));
+
+  // Prepend an article suggestion.
+  const std::string prepended_url = "http://prepended.com";
+  std::unique_ptr<RemoteSuggestion> prepended_suggestion =
+      RemoteSuggestionBuilder()
+          .AddId(prepended_url)
+          .SetUrl(prepended_url)
+          .Build();
+
+  provider->PushArticleSuggestionToTheFrontForDebugging(
+      std::move(prepended_suggestion));
+
+  // Reset the provider to imitate browser restart.
+  ResetSuggestionsProvider(&provider);
+
+  // Check that prepended suggestion is in the front of the restored list and
+  // all other suggestions are present in the same order.
+  std::vector<Matcher<const ContentSuggestion&>> expected;
+  expected.push_back(
+      Property(&ContentSuggestion::id, MakeArticleID(prepended_url)));
+  for (int i = 0; i < 10; ++i) {
+    expected.push_back(
+        Property(&ContentSuggestion::id,
+                 MakeArticleID("http://other.com/" + base::IntToString(i))));
+  }
+
+  EXPECT_THAT(observer().SuggestionsForCategory(articles_category()),
+              ElementsAreArray(expected));
+}
+
 }  // namespace ntp_snippets
diff --git a/components/ntp_snippets/remote/test_utils.h b/components/ntp_snippets/remote/test_utils.h
index ca77097..d9560115 100644
--- a/components/ntp_snippets/remote/test_utils.h
+++ b/components/ntp_snippets/remote/test_utils.h
@@ -13,7 +13,6 @@
 #include "components/signin/core/browser/fake_signin_manager.h"
 #include "components/sync/driver/fake_sync_service.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
-#include "testing/gtest/include/gtest/gtest.h"
 
 class AccountTrackerService;
 class FakeProfileOAuth2TokenService;
diff --git a/components/test/data/payments/bobpay_and_basic_card_with_modifiers.js b/components/test/data/payments/bobpay_and_basic_card_with_modifiers.js
index c9921af3..119065c2 100644
--- a/components/test/data/payments/bobpay_and_basic_card_with_modifiers.js
+++ b/components/test/data/payments/bobpay_and_basic_card_with_modifiers.js
@@ -32,9 +32,7 @@
         .then(function(resp) {
           resp.complete('success')
               .then(function() {
-                print(
-                    resp.methodName + '<br>' +
-                    JSON.stringify(resp.details, undefined, 2));
+                print(JSON.stringify(resp, undefined, 2));
               })
               .catch(function(error) {
                 print(error.message);
@@ -75,9 +73,7 @@
         .then(function(resp) {
           resp.complete('success')
               .then(function() {
-                print(
-                    resp.methodName + '<br>' +
-                    JSON.stringify(resp.details, undefined, 2));
+                print(JSON.stringify(resp, undefined, 2));
               })
               .catch(function(error) {
                 print(error.message);
@@ -120,9 +116,7 @@
         .then(function(resp) {
           resp.complete('success')
               .then(function() {
-                print(
-                    resp.methodName + '<br>' +
-                    JSON.stringify(resp.details, undefined, 2));
+                print(JSON.stringify(resp, undefined, 2));
               })
               .catch(function(error) {
                 print(error.message);
@@ -165,9 +159,7 @@
         .then(function(resp) {
           resp.complete('success')
               .then(function() {
-                print(
-                    resp.methodName + '<br>' +
-                    JSON.stringify(resp.details, undefined, 2));
+                print(JSON.stringify(resp, undefined, 2));
               })
               .catch(function(error) {
                 print(error.message);
@@ -211,9 +203,7 @@
         .then(function(resp) {
           resp.complete('success')
               .then(function() {
-                print(
-                    resp.methodName + '<br>' +
-                    JSON.stringify(resp.details, undefined, 2));
+                print(JSON.stringify(resp, undefined, 2));
               })
               .catch(function(error) {
                 print(error.message);
@@ -258,9 +248,50 @@
         .then(function(resp) {
           resp.complete('success')
               .then(function() {
-                print(
-                    resp.methodName + '<br>' +
-                    JSON.stringify(resp.details, undefined, 2));
+                print(JSON.stringify(resp, undefined, 2));
+              })
+              .catch(function(error) {
+                print(error.message);
+              });
+        })
+        .catch(function(error) {
+          print(error.message);
+        });
+  } catch (error) {
+    print(error.message);
+  }
+}
+
+/**
+ * Launches the PaymentRequest UI with Bob Pay and basic-card as payment
+ * methods and a modifier for basic-card with "mastercard" network.
+ */
+function mastercardAnySupportedType() { // eslint-disable-line no-unused-vars
+  try {
+    new PaymentRequest(
+        [{supportedMethods: ['https://bobpay.com', 'basic-card']}], {
+          total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}},
+          modifiers: [{
+            supportedMethods: ['basic-card'],
+            total: {
+              label: 'Total',
+              amount: {currency: 'USD', value: '4.00'},
+            },
+            additionalDisplayItems: [{
+              label: 'basic-card discount',
+              amount: {currency: 'USD', value: '-1.00'},
+            }],
+            data: {
+              discountProgramParticipantId: '86328764873265',
+              supportedNetworks: ['mastercard'],
+            },
+          }],
+        })
+        .show()
+        .then(function(resp) {
+          resp.complete('success')
+              .then(function() {
+                print(JSON.stringify(resp, undefined, 2));
               })
               .catch(function(error) {
                 print(error.message);
diff --git a/components/test/data/payments/payment_request_bobpay_and_basic_card_with_modifiers_test.html b/components/test/data/payments/payment_request_bobpay_and_basic_card_with_modifiers_test.html
index 41333cc..bff26690 100644
--- a/components/test/data/payments/payment_request_bobpay_and_basic_card_with_modifiers_test.html
+++ b/components/test/data/payments/payment_request_bobpay_and_basic_card_with_modifiers_test.html
@@ -16,8 +16,9 @@
 <button onclick="buyWithBobPayDiscount()" id="buy_with_bobpay_discount">Bob Pay and Basic-Card with Bob Pay modifiers Test</button>
 <button onclick="creditSupportedType()" id="credit_supported_type">Bob Pay and Basic-Card with Basic-Card modifiers Test with credit supported type</button>
 <button onclick="debitSupportedType()" id="debit_supported_type">Bob Pay and Basic-Card with Basic-Card modifiers Test with debit supported type</button>
-<button onclick="visaSupportedNetwork()" id="visa_supported_network">Bob Pay and Basic-Card with Basic-Card modifiers Test with visa supported network</button>
-<button onclick="mastercardSupportedNetwork()" id="mastercard_supported_network">Bob Pay and Basic-Card with Basic-Card modifiers Test with mastercard supported network</button>
+<button onclick="visaSupportedNetwork()" id="visa_supported_network">Bob Pay and Basic-Card with Basic-Card modifiers Test with visa supported network and credit supported type</button>
+<button onclick="mastercardSupportedNetwork()" id="mastercard_supported_network">Bob Pay and Basic-Card with Basic-Card modifiers Test with mastercard supported network and credit supported type</button>
+<button onclick="mastercardAnySupportedType()" id="mastercard_any_supported_type">Bob Pay and Basic-Card with Basic-Card modifiers Test with mastercard supported network and any supported type</button>
 <pre id="result"></pre>
 <script src="util.js"></script>
 <script src="bobpay_and_basic_card_with_modifiers.js"></script>
diff --git a/components/viz/host/BUILD.gn b/components/viz/host/BUILD.gn
index 998d6b95..6e3abfe 100644
--- a/components/viz/host/BUILD.gn
+++ b/components/viz/host/BUILD.gn
@@ -8,7 +8,7 @@
   defines = [ "VIZ_HOST_IMPLEMENTATION" ]
 
   sources = [
-    "frame_sink_observer.h",
+    "host_frame_sink_client.h",
     "host_frame_sink_manager.cc",
     "host_frame_sink_manager.h",
     "server_gpu_memory_buffer_manager.cc",
diff --git a/components/viz/host/frame_sink_observer.h b/components/viz/host/host_frame_sink_client.h
similarity index 64%
rename from components/viz/host/frame_sink_observer.h
rename to components/viz/host/host_frame_sink_client.h
index f018545..bd9e8bd 100644
--- a/components/viz/host/frame_sink_observer.h
+++ b/components/viz/host/host_frame_sink_client.h
@@ -2,23 +2,23 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_VIZ_HOST_FRAME_SINK_OBSERVER_H_
-#define COMPONENTS_VIZ_HOST_FRAME_SINK_OBSERVER_H_
+#ifndef COMPONENTS_VIZ_HOST_HOST_FRAME_SINK_CLIENT_H_
+#define COMPONENTS_VIZ_HOST_HOST_FRAME_SINK_CLIENT_H_
 
 namespace viz {
 
 class SurfaceInfo;
 
-class FrameSinkObserver {
+class HostFrameSinkClient {
  public:
   // Runs when a CompositorFrame is received for the given SurfaceInfo for the
   // first time.
   virtual void OnSurfaceCreated(const SurfaceInfo& surface_info) = 0;
 
  protected:
-  ~FrameSinkObserver() {}
+  virtual ~HostFrameSinkClient() {}
 };
 
 }  // namespace viz
 
-#endif  // COMPONENTS_VIZ_HOST_FRAME_SINK_OBSERVER_H_
+#endif  // COMPONENTS_VIZ_HOST_HOST_FRAME_SINK_CLIENT_H_
diff --git a/components/viz/host/host_frame_sink_manager.cc b/components/viz/host/host_frame_sink_manager.cc
index aba1a37..189e7be 100644
--- a/components/viz/host/host_frame_sink_manager.cc
+++ b/components/viz/host/host_frame_sink_manager.cc
@@ -40,12 +40,23 @@
   frame_sink_manager_ = frame_sink_manager_ptr_.get();
 }
 
-void HostFrameSinkManager::AddObserver(FrameSinkObserver* observer) {
-  observers_.AddObserver(observer);
+void HostFrameSinkManager::RegisterFrameSinkId(const FrameSinkId& frame_sink_id,
+                                               HostFrameSinkClient* client) {
+  DCHECK(frame_sink_id.is_valid());
+  DCHECK(client);
+  FrameSinkData& data = frame_sink_data_map_[frame_sink_id];
+  DCHECK(!data.HasCompositorFrameSinkData());
+  data.client = client;
+  frame_sink_manager_->RegisterFrameSinkId(frame_sink_id);
 }
 
-void HostFrameSinkManager::RemoveObserver(FrameSinkObserver* observer) {
-  observers_.RemoveObserver(observer);
+void HostFrameSinkManager::InvalidateFrameSinkId(
+    const FrameSinkId& frame_sink_id) {
+  DCHECK(frame_sink_id.is_valid());
+  auto it = frame_sink_data_map_.find(frame_sink_id);
+  DCHECK(it != frame_sink_data_map_.end());
+  frame_sink_data_map_.erase(it);
+  frame_sink_manager_->InvalidateFrameSinkId(frame_sink_id);
 }
 
 void HostFrameSinkManager::CreateCompositorFrameSink(
@@ -60,26 +71,6 @@
 
   frame_sink_manager_->CreateCompositorFrameSink(
       frame_sink_id, std::move(request), std::move(client));
-  frame_sink_manager_->RegisterFrameSinkId(frame_sink_id);
-}
-
-void HostFrameSinkManager::DestroyCompositorFrameSink(
-    const FrameSinkId& frame_sink_id) {
-  auto iter = frame_sink_data_map_.find(frame_sink_id);
-  DCHECK(iter != frame_sink_data_map_.end());
-
-  FrameSinkData& data = iter->second;
-  DCHECK(data.HasCompositorFrameSinkData());
-  if (data.has_created_compositor_frame_sink) {
-    // This will also destroy the CompositorFrameSink pipe to the client.
-    frame_sink_manager_->InvalidateFrameSinkId(frame_sink_id);
-    data.has_created_compositor_frame_sink = false;
-  } else {
-    data.support = nullptr;
-  }
-
-  if (data.IsEmpty())
-    frame_sink_data_map_.erase(iter);
 }
 
 void HostFrameSinkManager::RegisterFrameSinkHierarchy(
@@ -135,6 +126,23 @@
   return support;
 }
 
+void HostFrameSinkManager::DestroyCompositorFrameSink(
+    const FrameSinkId& frame_sink_id) {
+  auto iter = frame_sink_data_map_.find(frame_sink_id);
+  DCHECK(iter != frame_sink_data_map_.end());
+
+  FrameSinkData& data = iter->second;
+  DCHECK(data.HasCompositorFrameSinkData());
+  if (data.has_created_compositor_frame_sink) {
+    data.has_created_compositor_frame_sink = false;
+  } else {
+    data.support = nullptr;
+  }
+
+  if (data.IsEmpty())
+    frame_sink_data_map_.erase(iter);
+}
+
 void HostFrameSinkManager::PerformAssignTemporaryReference(
     const SurfaceId& surface_id) {
   // Find the expected embedder for the new surface and assign the temporary
@@ -160,8 +168,14 @@
 }
 
 void HostFrameSinkManager::OnSurfaceCreated(const SurfaceInfo& surface_info) {
-  for (auto& observer : observers_)
-    observer.OnSurfaceCreated(surface_info);
+  auto it = frame_sink_data_map_.find(surface_info.id().frame_sink_id());
+  // If we've received a bogus or stale SurfaceId from Viz then just ignore it.
+  if (it == frame_sink_data_map_.end())
+    return;
+
+  FrameSinkData& frame_sink_data = it->second;
+  if (frame_sink_data.client)
+    frame_sink_data.client->OnSurfaceCreated(surface_info);
 
   if (frame_sink_manager_impl_ &&
       frame_sink_manager_impl_->surface_manager()->using_surface_references()) {
diff --git a/components/viz/host/host_frame_sink_manager.h b/components/viz/host/host_frame_sink_manager.h
index e9549b9e..4b3dbde0 100644
--- a/components/viz/host/host_frame_sink_manager.h
+++ b/components/viz/host/host_frame_sink_manager.h
@@ -15,7 +15,7 @@
 #include "base/observer_list.h"
 #include "base/optional.h"
 #include "components/viz/common/surfaces/frame_sink_id.h"
-#include "components/viz/host/frame_sink_observer.h"
+#include "components/viz/host/host_frame_sink_client.h"
 #include "components/viz/host/viz_host_export.h"
 #include "components/viz/service/frame_sinks/compositor_frame_sink_support_manager.h"
 #include "mojo/public/cpp/bindings/binding.h"
@@ -57,20 +57,24 @@
       scoped_refptr<base::SingleThreadTaskRunner> task_runner,
       mojom::FrameSinkManagerPtr ptr);
 
-  void AddObserver(FrameSinkObserver* observer);
-  void RemoveObserver(FrameSinkObserver* observer);
+  // Registers |frame_sink_id| will be used. This must be called before
+  // CreateCompositorFrameSink(Support) is called.
+  void RegisterFrameSinkId(const FrameSinkId& frame_sink_id,
+                           HostFrameSinkClient* client);
+
+  // Invalidates |frame_sink_id| which cleans up any unsatisified surface
+  // sequences or dangling temporary references assigned to it. If there is a
+  // CompositorFrameSink for |frame_sink_id| then it will be destroyed and the
+  // message pipe to the client will be closed.
+  void InvalidateFrameSinkId(const FrameSinkId& frame_sink_id);
 
   // Creates a connection between client to viz, using |request| and |client|,
   // that allows the client to submit CompositorFrames. When no longer needed,
-  // call DestroyCompositorFrameSink().
+  // call InvalidateFrameSinkId().
   void CreateCompositorFrameSink(const FrameSinkId& frame_sink_id,
                                  mojom::CompositorFrameSinkRequest request,
                                  mojom::CompositorFrameSinkClientPtr client);
 
-  // Destroys a client connection. Will call UnregisterFrameSinkHierarchy() with
-  // the registered parent if there is one.
-  void DestroyCompositorFrameSink(const FrameSinkId& frame_sink_id);
-
   // Registers FrameSink hierarchy. Clients can call this multiple times to
   // reparent without calling UnregisterFrameSinkHierarchy().
   void RegisterFrameSinkHierarchy(const FrameSinkId& parent_frame_sink_id,
@@ -104,9 +108,12 @@
 
     // Returns true if there is nothing in FrameSinkData and it can be deleted.
     bool IsEmpty() const {
-      return !HasCompositorFrameSinkData() && !parent.has_value();
+      return !HasCompositorFrameSinkData() && !parent.has_value() && !client;
     }
 
+    // The client to be notified of changes to this FrameSink.
+    HostFrameSinkClient* client = nullptr;
+
     // If the frame sink is a root that corresponds to a Display.
     bool is_root = false;
 
@@ -124,6 +131,10 @@
     DISALLOW_COPY_AND_ASSIGN(FrameSinkData);
   };
 
+  // Destroys a client connection. Will call UnregisterFrameSinkHierarchy() with
+  // the registered parent if there is one.
+  void DestroyCompositorFrameSink(const FrameSinkId& frame_sink_id);
+
   // Assigns the temporary reference to the frame sink that is expected to
   // embeded |surface_id|, otherwise drops the temporary reference.
   void PerformAssignTemporaryReference(const SurfaceId& surface_id);
@@ -152,9 +163,6 @@
   // Per CompositorFrameSink data.
   base::flat_map<FrameSinkId, FrameSinkData> frame_sink_data_map_;
 
-  // Local observers to that receive OnSurfaceCreated() messages from IPC.
-  base::ObserverList<FrameSinkObserver> observers_;
-
   base::WeakPtrFactory<HostFrameSinkManager> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(HostFrameSinkManager);
diff --git a/components/viz/host/host_frame_sink_manager_unittests.cc b/components/viz/host/host_frame_sink_manager_unittests.cc
index e9cf2ff6..c266eb9 100644
--- a/components/viz/host/host_frame_sink_manager_unittests.cc
+++ b/components/viz/host/host_frame_sink_manager_unittests.cc
@@ -39,6 +39,19 @@
   return SurfaceInfo(surface_id, 1.f, gfx::Size(1, 1));
 }
 
+// A fake (do-nothing) implementation of HostFrameSinkClient.
+class FakeHostFrameSinkClient : public HostFrameSinkClient {
+ public:
+  FakeHostFrameSinkClient() = default;
+  ~FakeHostFrameSinkClient() override = default;
+
+  // HostFrameSinkClient implementation.
+  void OnSurfaceCreated(const SurfaceInfo& surface_info) override {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FakeHostFrameSinkClient);
+};
+
 // A mock implementation of mojom::FrameSinkManager.
 class MockFrameSinkManagerImpl : public FrameSinkManagerImpl {
  public:
@@ -101,16 +114,22 @@
 
   // testing::Test:
   void SetUp() override {
-    manager_impl_ = base::MakeUnique<MockFrameSinkManagerImpl>();
+    manager_impl_ =
+        base::MakeUnique<testing::NiceMock<MockFrameSinkManagerImpl>>();
     host_manager_ = base::MakeUnique<HostFrameSinkManager>();
 
     manager_impl_->SetLocalClient(host_manager_.get());
     host_manager_->SetLocalManager(manager_impl_.get());
   }
 
+  void TearDown() override {
+    host_manager_.reset();
+    manager_impl_.reset();
+  }
+
  private:
   std::unique_ptr<HostFrameSinkManager> host_manager_;
-  std::unique_ptr<MockFrameSinkManagerImpl> manager_impl_;
+  std::unique_ptr<testing::NiceMock<MockFrameSinkManagerImpl>> manager_impl_;
 
   DISALLOW_COPY_AND_ASSIGN(HostFrameSinkManagerTest);
 };
@@ -121,10 +140,15 @@
   // Calling CreateCompositorFrameSink() should first register the frame sink
   // and then request to create it.
   EXPECT_CALL(manager_impl(), RegisterFrameSinkId(kClientFrameSinkId));
+
+  FakeHostFrameSinkClient client;
+  host_manager().RegisterFrameSinkId(kClientFrameSinkId, &client);
+
   EXPECT_CALL(manager_impl(),
               MockCreateCompositorFrameSink(kClientFrameSinkId));
   host_manager().CreateCompositorFrameSink(
       kClientFrameSinkId, nullptr /* request */, nullptr /* client */);
+
   EXPECT_TRUE(FrameSinkDataExists(kClientFrameSinkId));
 
   // Register should call through to FrameSinkManagerImpl and should work even
@@ -136,7 +160,6 @@
 
   // Destroying the CompositorFrameSink should invalidate it in viz.
   EXPECT_CALL(manager_impl(), InvalidateFrameSinkId(kClientFrameSinkId));
-  host_manager().DestroyCompositorFrameSink(kClientFrameSinkId);
 
   // We should still have the hierarchy data for |kClientFrameSinkId|.
   EXPECT_TRUE(FrameSinkDataExists(kClientFrameSinkId));
@@ -146,6 +169,7 @@
                                                            kClientFrameSinkId));
   host_manager().UnregisterFrameSinkHierarchy(kParentFrameSinkId,
                                               kClientFrameSinkId);
+  host_manager().InvalidateFrameSinkId(kClientFrameSinkId);
 
   // Data for |kClientFrameSinkId| should be deleted now.
   EXPECT_FALSE(FrameSinkDataExists(kClientFrameSinkId));
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame.cc b/content/browser/frame_host/render_widget_host_view_child_frame.cc
index 612a1ba6..d3597a9 100644
--- a/content/browser/frame_host/render_widget_host_view_child_frame.cc
+++ b/content/browser/frame_host/render_widget_host_view_child_frame.cc
@@ -66,8 +66,7 @@
       background_color_(SK_ColorWHITE),
       weak_factory_(this) {
   if (!service_manager::ServiceManagerIsRemote()) {
-    GetFrameSinkManager()->surface_manager()->RegisterFrameSinkId(
-        frame_sink_id_);
+    GetHostFrameSinkManager()->RegisterFrameSinkId(frame_sink_id_, this);
     CreateCompositorFrameSinkSupport();
   }
 }
@@ -75,10 +74,8 @@
 RenderWidgetHostViewChildFrame::~RenderWidgetHostViewChildFrame() {
   if (!service_manager::ServiceManagerIsRemote()) {
     ResetCompositorFrameSinkSupport();
-    if (GetFrameSinkManager()) {
-      GetFrameSinkManager()->surface_manager()->InvalidateFrameSinkId(
-          frame_sink_id_);
-    }
+    if (GetHostFrameSinkManager())
+      GetHostFrameSinkManager()->InvalidateFrameSinkId(frame_sink_id_);
   }
 }
 
@@ -769,6 +766,12 @@
   renderer_compositor_frame_sink_->OnBeginFramePausedChanged(paused);
 }
 
+void RenderWidgetHostViewChildFrame::OnSurfaceCreated(
+    const viz::SurfaceInfo& surface_info) {
+  // TODO(fsamuel): Once surface synchronization is turned on, the fallback
+  // surface should be set here.
+}
+
 void RenderWidgetHostViewChildFrame::SetNeedsBeginFrames(
     bool needs_begin_frames) {
   if (support_)
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame.h b/content/browser/frame_host/render_widget_host_view_child_frame.h
index 66f5479a..29abd318 100644
--- a/content/browser/frame_host/render_widget_host_view_child_frame.h
+++ b/content/browser/frame_host/render_widget_host_view_child_frame.h
@@ -20,6 +20,7 @@
 #include "components/viz/common/resources/returned_resource.h"
 #include "components/viz/common/surfaces/surface_info.h"
 #include "components/viz/common/surfaces/surface_sequence.h"
+#include "components/viz/host/host_frame_sink_client.h"
 #include "components/viz/service/frame_sinks/compositor_frame_sink_support_client.h"
 #include "content/browser/compositor/image_transport_factory.h"
 #include "content/browser/renderer_host/event_with_latency_info.h"
@@ -54,7 +55,8 @@
 class CONTENT_EXPORT RenderWidgetHostViewChildFrame
     : public RenderWidgetHostViewBase,
       public TouchSelectionControllerClientManager::Observer,
-      public NON_EXPORTED_BASE(viz::CompositorFrameSinkSupportClient) {
+      public NON_EXPORTED_BASE(viz::CompositorFrameSinkSupportClient),
+      public NON_EXPORTED_BASE(viz::HostFrameSinkClient) {
  public:
   static RenderWidgetHostViewChildFrame* Create(RenderWidgetHost* widget);
   ~RenderWidgetHostViewChildFrame() override;
@@ -181,6 +183,9 @@
                        const gfx::Rect& damage_rect) override {}
   void OnBeginFramePausedChanged(bool paused) override;
 
+  // viz::HostFrameSinkClient implementation.
+  void OnSurfaceCreated(const viz::SurfaceInfo& surface_info) override;
+
   // Exposed for tests.
   bool IsChildFrameForTesting() const override;
   viz::SurfaceId SurfaceIdForTesting() const override;
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index 7f2c879..172e1ae 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -465,7 +465,7 @@
       num_successive_context_creation_failures_(0),
       layer_tree_frame_sink_request_pending_(false),
       weak_factory_(this) {
-  GetFrameSinkManager()->surface_manager()->RegisterFrameSinkId(frame_sink_id_);
+  GetHostFrameSinkManager()->RegisterFrameSinkId(frame_sink_id_, this);
   DCHECK(client);
   DCHECK(root_window);
   DCHECK(root_window->GetLayer() == nullptr);
@@ -483,8 +483,7 @@
   root_window_->SetLayer(nullptr);
   // Clean-up any surface references.
   SetSurface(NULL);
-  GetFrameSinkManager()->surface_manager()->InvalidateFrameSinkId(
-      frame_sink_id_);
+  GetHostFrameSinkManager()->InvalidateFrameSinkId(frame_sink_id_);
 }
 
 bool CompositorImpl::IsForSubframe() {
@@ -939,6 +938,11 @@
                                                           frame_sink_id);
 }
 
+void CompositorImpl::OnSurfaceCreated(const viz::SurfaceInfo& surface_info) {
+  // TODO(fsamuel): Once surface synchronization is turned on, the fallback
+  // surface should be set here.
+}
+
 bool CompositorImpl::HavePendingReadbacks() {
   return !readback_layer_tree_->children().empty();
 }
diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h
index 2c767ad7..e601d4d 100644
--- a/content/browser/renderer_host/compositor_impl_android.h
+++ b/content/browser/renderer_host/compositor_impl_android.h
@@ -18,6 +18,7 @@
 #include "cc/trees/layer_tree_host_client.h"
 #include "cc/trees/layer_tree_host_single_thread_client.h"
 #include "components/viz/common/surfaces/frame_sink_id.h"
+#include "components/viz/host/host_frame_sink_client.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/android/compositor.h"
 #include "gpu/command_buffer/common/capabilities.h"
@@ -57,7 +58,8 @@
       public cc::LayerTreeHostClient,
       public cc::LayerTreeHostSingleThreadClient,
       public ui::UIResourceProvider,
-      public ui::WindowAndroidCompositor {
+      public ui::WindowAndroidCompositor,
+      public viz::HostFrameSinkClient {
  public:
   CompositorImpl(CompositorClient* client, gfx::NativeWindow root_window);
   ~CompositorImpl() override;
@@ -121,6 +123,9 @@
   void AddChildFrameSink(const viz::FrameSinkId& frame_sink_id) override;
   void RemoveChildFrameSink(const viz::FrameSinkId& frame_sink_id) override;
 
+  // viz::HostFrameSinkClient implementation.
+  void OnSurfaceCreated(const viz::SurfaceInfo& surface_info) override;
+
   void SetVisible(bool visible);
   void CreateLayerTreeHost();
 
diff --git a/content/browser/renderer_host/delegated_frame_host.cc b/content/browser/renderer_host/delegated_frame_host.cc
index e320bb89..032fc45 100644
--- a/content/browser/renderer_host/delegated_frame_host.cc
+++ b/content/browser/renderer_host/delegated_frame_host.cc
@@ -54,10 +54,9 @@
       frame_evictor_(new viz::FrameEvictor(this)) {
   ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
   factory->GetContextFactory()->AddObserver(this);
-  factory->GetContextFactoryPrivate()
-      ->GetFrameSinkManager()
-      ->surface_manager()
-      ->RegisterFrameSinkId(frame_sink_id_);
+  viz::HostFrameSinkManager* host_frame_sink_manager =
+      factory->GetContextFactoryPrivate()->GetHostFrameSinkManager();
+  host_frame_sink_manager->RegisterFrameSinkId(frame_sink_id_, this);
   CreateCompositorFrameSinkSupport();
 }
 
@@ -514,6 +513,12 @@
     renderer_compositor_frame_sink_->OnBeginFramePausedChanged(paused);
 }
 
+void DelegatedFrameHost::OnSurfaceCreated(
+    const viz::SurfaceInfo& surface_info) {
+  // TODO(fsamuel): Once surface synchronization is turned on, the fallback
+  // surface should be set here.
+}
+
 void DelegatedFrameHost::OnBeginFrame(const viz::BeginFrameArgs& args) {
   if (renderer_compositor_frame_sink_)
     renderer_compositor_frame_sink_->OnBeginFrame(args);
@@ -773,10 +778,9 @@
 
   ResetCompositorFrameSinkSupport();
 
-  factory->GetContextFactoryPrivate()
-      ->GetFrameSinkManager()
-      ->surface_manager()
-      ->InvalidateFrameSinkId(frame_sink_id_);
+  viz::HostFrameSinkManager* host_frame_sink_manager =
+      factory->GetContextFactoryPrivate()->GetHostFrameSinkManager();
+  host_frame_sink_manager->InvalidateFrameSinkId(frame_sink_id_);
 
   DCHECK(!vsync_manager_.get());
 }
diff --git a/content/browser/renderer_host/delegated_frame_host.h b/content/browser/renderer_host/delegated_frame_host.h
index 97bfb36..5b50b0b 100644
--- a/content/browser/renderer_host/delegated_frame_host.h
+++ b/content/browser/renderer_host/delegated_frame_host.h
@@ -13,6 +13,7 @@
 #include "components/viz/common/frame_sinks/begin_frame_args.h"
 #include "components/viz/common/frame_sinks/begin_frame_source.h"
 #include "components/viz/common/quads/copy_output_result.h"
+#include "components/viz/host/host_frame_sink_client.h"
 #include "components/viz/service/frame_sinks/compositor_frame_sink_support_client.h"
 #include "components/viz/service/frame_sinks/frame_evictor.h"
 #include "content/browser/compositor/image_transport_factory.h"
@@ -81,6 +82,7 @@
       public ui::ContextFactoryObserver,
       public viz::FrameEvictorClient,
       public NON_EXPORTED_BASE(viz::CompositorFrameSinkSupportClient),
+      public NON_EXPORTED_BASE(viz::HostFrameSinkClient),
       public base::SupportsWeakPtr<DelegatedFrameHost> {
  public:
   DelegatedFrameHost(const viz::FrameSinkId& frame_sink_id,
@@ -115,6 +117,9 @@
                        const gfx::Rect& damage_rect) override;
   void OnBeginFramePausedChanged(bool paused) override;
 
+  // viz::HostFrameSinkClient implementation.
+  void OnSurfaceCreated(const viz::SurfaceInfo& surface_info) override;
+
   // Public interface exposed to RenderWidgetHostView.
 
   void DidCreateNewRendererCompositorFrameSink(
diff --git a/content/browser/renderer_host/offscreen_canvas_surface_impl.cc b/content/browser/renderer_host/offscreen_canvas_surface_impl.cc
index 3698e53..233ba348 100644
--- a/content/browser/renderer_host/offscreen_canvas_surface_impl.cc
+++ b/content/browser/renderer_host/offscreen_canvas_surface_impl.cc
@@ -31,16 +31,15 @@
   binding_.set_connection_error_handler(
       base::Bind(&OffscreenCanvasSurfaceImpl::OnSurfaceConnectionClosed,
                  base::Unretained(this)));
-  host_frame_sink_manager_->AddObserver(this);
+  host_frame_sink_manager_->RegisterFrameSinkId(frame_sink_id_, this);
 }
 
 OffscreenCanvasSurfaceImpl::~OffscreenCanvasSurfaceImpl() {
   if (has_created_compositor_frame_sink_) {
     host_frame_sink_manager_->UnregisterFrameSinkHierarchy(
         parent_frame_sink_id_, frame_sink_id_);
-    host_frame_sink_manager_->DestroyCompositorFrameSink(frame_sink_id_);
+    host_frame_sink_manager_->InvalidateFrameSinkId(frame_sink_id_);
   }
-  host_frame_sink_manager_->RemoveObserver(this);
 }
 
 void OffscreenCanvasSurfaceImpl::CreateCompositorFrameSink(
@@ -61,8 +60,7 @@
 
 void OffscreenCanvasSurfaceImpl::OnSurfaceCreated(
     const viz::SurfaceInfo& surface_info) {
-  if (surface_info.id().frame_sink_id() != frame_sink_id_)
-    return;
+  DCHECK_EQ(surface_info.id().frame_sink_id(), frame_sink_id_);
 
   local_surface_id_ = surface_info.id().local_surface_id();
   if (client_)
diff --git a/content/browser/renderer_host/offscreen_canvas_surface_impl.h b/content/browser/renderer_host/offscreen_canvas_surface_impl.h
index 734c1406..5498b76 100644
--- a/content/browser/renderer_host/offscreen_canvas_surface_impl.h
+++ b/content/browser/renderer_host/offscreen_canvas_surface_impl.h
@@ -9,7 +9,7 @@
 #include "base/compiler_specific.h"
 #include "components/viz/common/surfaces/frame_sink_id.h"
 #include "components/viz/common/surfaces/surface_info.h"
-#include "components/viz/host/frame_sink_observer.h"
+#include "components/viz/host/host_frame_sink_client.h"
 #include "components/viz/host/host_frame_sink_manager.h"
 #include "content/common/content_export.h"
 #include "mojo/public/cpp/bindings/binding.h"
@@ -21,7 +21,7 @@
 // connections to both the renderer and frame sink manager.
 class CONTENT_EXPORT OffscreenCanvasSurfaceImpl
     : public blink::mojom::OffscreenCanvasSurface,
-      public NON_EXPORTED_BASE(viz::FrameSinkObserver) {
+      public NON_EXPORTED_BASE(viz::HostFrameSinkClient) {
  public:
   using DestroyCallback = base::OnceCallback<void()>;
 
@@ -52,7 +52,7 @@
       viz::mojom::CompositorFrameSinkClientPtr client,
       viz::mojom::CompositorFrameSinkRequest request);
 
-  // FrameSinkObserver implementation.
+  // viz::HostFrameSinkClient implementation.
   void OnSurfaceCreated(const viz::SurfaceInfo& surface_info) override;
 
   // blink::mojom::OffscreenCanvasSurface implementation.
diff --git a/content/common/content_switches_internal.cc b/content/common/content_switches_internal.cc
index 105a9d1..0752026 100644
--- a/content/common/content_switches_internal.cc
+++ b/content/common/content_switches_internal.cc
@@ -27,7 +27,7 @@
 #endif
 
 bool IsUseZoomForDSFEnabledByDefault() {
-#if defined(OS_CHROMEOS) || defined(OS_LINUX)
+#if defined(OS_LINUX)
   return true;
 #elif defined(OS_WIN)
   return base::FeatureList::IsEnabled(kUseZoomForDsfEnabledByDefault);
diff --git a/content/public/test/test_browser_thread_bundle.cc b/content/public/test/test_browser_thread_bundle.cc
index bf3737da..98dc5218 100644
--- a/content/public/test/test_browser_thread_bundle.cc
+++ b/content/public/test/test_browser_thread_bundle.cc
@@ -8,8 +8,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
-#include "base/task_scheduler/task_scheduler.h"
-#include "base/test/scoped_async_task_scheduler.h"
+#include "base/test/scoped_task_environment.h"
 #include "content/browser/browser_thread_impl.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/test_browser_thread.h"
@@ -66,30 +65,25 @@
   // Skip the following step when TaskScheduler isn't managed by this
   // TestBrowserThreadBundle, otherwise it can hang (e.g.
   // RunAllBlockingPoolTasksUntilIdle() hangs when the TaskScheduler is managed
-  // by a ScopedTaskEnvironment with ExecutionMode::QUEUED). This is fine as (1)
-  // it's rare and (2) it mimics production where BrowserThreads are shutdown
-  // before TaskScheduler.
-  if (scoped_async_task_scheduler_) {
-    // This is required to ensure we run all remaining tasks in an atomic step
-    // (instead of ~ScopedAsyncTaskScheduler() followed by another
-    // RunLoop().RunUntilIdle()). Otherwise If a pending task in
-    // |scoped_async_task_scheduler_| posts to |message_loop_|, that task can
-    // then post back to |scoped_async_task_scheduler_| after the former was
-    // destroyed. This is a bit different than production where the main thread
-    // is not flushed after it's done running but this approach is preferred in
-    // unit tests as running more tasks can merely uncover more issues (e.g. if
-    // a bad tasks is posted but never blocked upon it could make a test flaky
-    // whereas by flushing we guarantee it will blow up).
+  // by an external ScopedTaskEnvironment with ExecutionMode::QUEUED). This is
+  // fine as (1) it's rare and (2) it mimics production where BrowserThreads are
+  // shutdown before TaskScheduler.
+  if (scoped_task_environment_) {
+    // This is required to ensure we run all remaining MessageLoop and
+    // TaskScheduler tasks in an atomic step. This is a bit different than
+    // production where the main thread is not flushed after it's done running
+    // but this approach is preferred in unit tests as running more tasks can
+    // merely uncover more issues (e.g. if a bad tasks is posted but never
+    // blocked upon it could make a test flaky whereas by flushing we guarantee
+    // it will blow up).
     RunAllBlockingPoolTasksUntilIdle();
-
-    scoped_async_task_scheduler_.reset();
     CHECK(base::MessageLoop::current()->IsIdleForTesting());
   }
 
-  // |message_loop_| needs to explicitly go away before fake threads in order
-  // for DestructionObservers hooked to |message_loop_| to be able to invoke
-  // BrowserThread::CurrentlyOn() -- ref. ~TestBrowserThread().
-  message_loop_.reset();
+  // |scoped_task_environment_| needs to explicitly go away before fake threads
+  // in order for DestructionObservers hooked to the main MessageLoop to be able
+  // to invoke BrowserThread::CurrentlyOn() -- ref. ~TestBrowserThread().
+  scoped_task_environment_.reset();
 
 #if defined(OS_WIN)
   com_initializer_.reset();
@@ -103,8 +97,8 @@
 
   // Check for conflicting options can't have two IO threads.
   CHECK(!(options_ & IO_MAINLOOP) || !(options_ & REAL_IO_THREAD));
-  // There must be a thread to start to use DONT_CREATE_THREADS
-  CHECK((options_ & ~IO_MAINLOOP) != DONT_CREATE_THREADS);
+  // There must be a thread to start to use DONT_CREATE_BROWSER_THREADS
+  CHECK((options_ & ~IO_MAINLOOP) != DONT_CREATE_BROWSER_THREADS);
 
 #if defined(OS_WIN)
   // Similar to Chrome's UI thread, we need to initialize COM separately for
@@ -114,39 +108,32 @@
   CHECK(com_initializer_->succeeded());
 #endif
 
-  // Create the main MessageLoop, if it doesn't already exist, and set the
-  // current thread as the UI thread. In production, this work is done in
-  // BrowserMainLoop::MainMessageLoopStart(). The main MessageLoop may already
-  // exist if this TestBrowserThreadBundle is instantiated in a test whose
-  // parent fixture provides a base::test::ScopedTaskEnvironment.
-  const base::MessageLoop::Type message_loop_type =
-      options_ & IO_MAINLOOP ? base::MessageLoop::TYPE_IO
-                             : base::MessageLoop::TYPE_UI;
-  if (!base::MessageLoop::current())
-    message_loop_ = base::MakeUnique<base::MessageLoop>(message_loop_type);
-  CHECK(base::MessageLoop::current()->IsType(message_loop_type));
+  // Create the ScopedTaskEnvironment if it doesn't already exist. A
+  // ScopedTaskEnvironment may already exist if this TestBrowserThreadBundle is
+  // instantiated in a test whose parent fixture provides a
+  // ScopedTaskEnvironment.
+  if (!base::MessageLoop::current()) {
+    scoped_task_environment_ =
+        base::MakeUnique<base::test::ScopedTaskEnvironment>(
+            options_ & IO_MAINLOOP
+                ? base::test::ScopedTaskEnvironment::MainThreadType::IO
+                : base::test::ScopedTaskEnvironment::MainThreadType::UI);
+  }
+  CHECK(base::MessageLoop::current()->IsType(options_ & IO_MAINLOOP
+                                                 ? base::MessageLoop::TYPE_IO
+                                                 : base::MessageLoop::TYPE_UI));
 
+  // Set the current thread as the UI thread.
   ui_thread_ = base::MakeUnique<TestBrowserThread>(
       BrowserThread::UI, base::MessageLoop::current());
 
-  if (!(options_ & DONT_CREATE_THREADS))
-    CreateThreads();
+  if (!(options_ & DONT_CREATE_BROWSER_THREADS))
+    CreateBrowserThreads();
 }
 
-// This method mimics the work done in BrowserMainLoop::CreateThreads().
-void TestBrowserThreadBundle::CreateThreads() {
+void TestBrowserThreadBundle::CreateBrowserThreads() {
   CHECK(!threads_created_);
 
-  // TaskScheduler can sometimes be externally provided by a
-  // base::test::ScopedTaskEnvironment in a parent fixture. In that case it's
-  // expected to have provided the MessageLoop as well (in which case
-  // |message_loop_| remains null in Init()).
-  CHECK(!base::TaskScheduler::GetInstance() || !message_loop_);
-  if (!base::TaskScheduler::GetInstance()) {
-    scoped_async_task_scheduler_ =
-        base::MakeUnique<base::test::ScopedAsyncTaskScheduler>();
-  }
-
   if (options_ & REAL_DB_THREAD) {
     db_thread_ = base::MakeUnique<TestBrowserThread>(BrowserThread::DB);
     db_thread_->Start();
diff --git a/content/public/test/test_browser_thread_bundle.h b/content/public/test/test_browser_thread_bundle.h
index 991a7f9..079e339 100644
--- a/content/public/test/test_browser_thread_bundle.h
+++ b/content/public/test/test_browser_thread_bundle.h
@@ -47,12 +47,13 @@
 // REAL_IO_THREAD.
 //
 // For some tests it is important to emulate real browser startup. During real
-// browser startup, the main MessageLoop is created before other threads.
-// Passing DONT_CREATE_THREADS to constructor will delay creating other threads
-// until the test explicitly calls CreateThreads().
+// browser startup, the main MessageLoop and the TaskScheduler are created
+// before browser threads. Passing DONT_CREATE_BROWSER_THREADS to constructor
+// will delay creating browser threads until the test explicitly calls
+// CreateBrowserThreads().
 //
-// DONT_CREATE_THREADS should only be used when the options specify at least
-// one real thread other than the main thread.
+// DONT_CREATE_BROWSER_THREADS should only be used when the options specify at
+// least one real thread other than the main thread.
 //
 // TestBrowserThreadBundle may be instantiated in a scope where there is already
 // a base::test::ScopedTaskEnvironment. In that case, it will use the
@@ -90,9 +91,8 @@
 #include "build/build_config.h"
 
 namespace base {
-class MessageLoop;
 namespace test {
-class ScopedAsyncTaskScheduler;
+class ScopedTaskEnvironment;
 }  // namespace test
 #if defined(OS_WIN)
 namespace win {
@@ -116,24 +116,22 @@
     REAL_DB_THREAD = 1 << 1,
     REAL_FILE_THREAD = 1 << 2,
     REAL_IO_THREAD = 1 << 3,
-    DONT_CREATE_THREADS = 1 << 4,
+    DONT_CREATE_BROWSER_THREADS = 1 << 4,
   };
 
   TestBrowserThreadBundle();
   explicit TestBrowserThreadBundle(int options);
 
-  // Creates threads; should only be called from other classes if the
-  // DONT_CREATE_THREADS option was used when the bundle was created.
-  void CreateThreads();
+  // Creates browser threads; should only be called from other classes if the
+  // DONT_CREATE_BROWSER_THREADS option was used when the bundle was created.
+  void CreateBrowserThreads();
 
   ~TestBrowserThreadBundle();
 
  private:
   void Init();
 
-  std::unique_ptr<base::MessageLoop> message_loop_;
-  std::unique_ptr<base::test::ScopedAsyncTaskScheduler>
-      scoped_async_task_scheduler_;
+  std::unique_ptr<base::test::ScopedTaskEnvironment> scoped_task_environment_;
   std::unique_ptr<TestBrowserThread> ui_thread_;
   std::unique_ptr<TestBrowserThread> db_thread_;
   std::unique_ptr<TestBrowserThread> file_thread_;
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index fe2ac15..255f982 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -257,6 +257,7 @@
     "//cc/ipc",
     "//cc/ipc:interfaces",
     "//components/leveldb/public/interfaces",
+    "//components/viz/host",
     "//components/viz/service",
     "//content/app:both_for_content_tests",
     "//content/browser:for_content_tests",
diff --git a/content/test/DEPS b/content/test/DEPS
index 7c2de5f..9be8a4dc 100644
--- a/content/test/DEPS
+++ b/content/test/DEPS
@@ -6,6 +6,7 @@
   "+components/scheduler/renderer",
   "+components/scheduler/test",
   "+components/viz/common",
+  "+components/viz/host",
   "+components/viz/service",
   "+services/viz/public/interfaces/compositing",
 
diff --git a/content/test/test_render_view_host.cc b/content/test/test_render_view_host.cc
index cc86452..e79f5225 100644
--- a/content/test/test_render_view_host.cc
+++ b/content/test/test_render_view_host.cc
@@ -8,6 +8,7 @@
 
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "components/viz/host/host_frame_sink_manager.h"
 #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
 #include "components/viz/service/surfaces/surface_manager.h"
 #include "content/browser/compositor/image_transport_factory.h"
@@ -69,13 +70,12 @@
       background_color_(SK_ColorWHITE) {
 #if defined(OS_ANDROID)
   frame_sink_id_ = AllocateFrameSinkId();
-  GetFrameSinkManager()->surface_manager()->RegisterFrameSinkId(frame_sink_id_);
+  GetHostFrameSinkManager()->RegisterFrameSinkId(frame_sink_id_, this);
 #else
   // Not all tests initialize or need an image transport factory.
   if (ImageTransportFactory::GetInstance()) {
     frame_sink_id_ = AllocateFrameSinkId();
-    GetFrameSinkManager()->surface_manager()->RegisterFrameSinkId(
-        frame_sink_id_);
+    GetHostFrameSinkManager()->RegisterFrameSinkId(frame_sink_id_, this);
   }
 #endif
 
@@ -90,10 +90,9 @@
 }
 
 TestRenderWidgetHostView::~TestRenderWidgetHostView() {
-  viz::FrameSinkManagerImpl* manager = GetFrameSinkManager();
-  if (manager) {
-    manager->surface_manager()->InvalidateFrameSinkId(frame_sink_id_);
-  }
+  viz::HostFrameSinkManager* manager = GetHostFrameSinkManager();
+  if (manager)
+    manager->InvalidateFrameSinkId(frame_sink_id_);
 }
 
 RenderWidgetHost* TestRenderWidgetHostView::GetRenderWidgetHost() const {
@@ -221,6 +220,12 @@
   return frame_sink_id_;
 }
 
+void TestRenderWidgetHostView::OnSurfaceCreated(
+    const viz::SurfaceInfo& surface_info) {
+  // TODO(fsamuel): Once surface synchronization is turned on, the fallback
+  // surface should be set here.
+}
+
 TestRenderViewHost::TestRenderViewHost(
     SiteInstance* instance,
     std::unique_ptr<RenderWidgetHostImpl> widget,
diff --git a/content/test/test_render_view_host.h b/content/test/test_render_view_host.h
index 5a26b8d6..7a4d22c 100644
--- a/content/test/test_render_view_host.h
+++ b/content/test/test_render_view_host.h
@@ -14,6 +14,7 @@
 #include "base/macros.h"
 #include "build/build_config.h"
 #include "components/viz/common/surfaces/frame_sink_id.h"
+#include "components/viz/host/host_frame_sink_client.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_view_base.h"
 #include "content/public/common/web_preferences.h"
@@ -60,7 +61,9 @@
 
 // Subclass the RenderViewHost's view so that we can call Show(), etc.,
 // without having side-effects.
-class TestRenderWidgetHostView : public RenderWidgetHostViewBase {
+class TestRenderWidgetHostView
+    : public RenderWidgetHostViewBase,
+      public NON_EXPORTED_BASE(viz::HostFrameSinkClient) {
  public:
   explicit TestRenderWidgetHostView(RenderWidgetHost* rwh);
   ~TestRenderWidgetHostView() override;
@@ -128,6 +131,9 @@
     did_change_compositor_frame_sink_ = false;
   }
 
+  // viz::HostFrameSinkClient implementation.
+  void OnSurfaceCreated(const viz::SurfaceInfo& surface_info) override;
+
  protected:
   RenderWidgetHostImpl* rwh_;
   viz::FrameSinkId frame_sink_id_;
diff --git a/crypto/nss_util.cc b/crypto/nss_util.cc
index 1adcde8..94ac253 100644
--- a/crypto/nss_util.cc
+++ b/crypto/nss_util.cc
@@ -85,7 +85,7 @@
   DVLOG(2) << "DefaultConfigDirectory: " << dir.value();
   return dir;
 }
-#endif  // !defined(IS_CHROMEOS)
+#endif  // !defined(OS_CHROMEOS)
 
 // On non-Chrome OS platforms, return the default config directory. On Chrome OS
 // test images, return a read-only directory with fake root CA certs (which are
diff --git a/device/bluetooth/bluetooth_adapter.cc b/device/bluetooth/bluetooth_adapter.cc
index 9153dc5..49cab45 100644
--- a/device/bluetooth/bluetooth_adapter.cc
+++ b/device/bluetooth/bluetooth_adapter.cc
@@ -38,7 +38,7 @@
   return weak_ptr_factory_.GetWeakPtr();
 }
 
-#if defined(OS_CHROMEOS) || defined(OS_LINUX)
+#if defined(OS_LINUX)
 void BluetoothAdapter::Shutdown() {
   NOTIMPLEMENTED();
 }
diff --git a/device/bluetooth/bluetooth_adapter.h b/device/bluetooth/bluetooth_adapter.h
index bdefc09b..ac3e19b1 100644
--- a/device/bluetooth/bluetooth_adapter.h
+++ b/device/bluetooth/bluetooth_adapter.h
@@ -117,6 +117,7 @@
                                       BluetoothDevice* device,
                                       const std::string& old_address) {}
 
+// TODO(crbug.com/732991): Update comment and fix redundant #ifs throughout.
 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
     // This function is implemented for ChromeOS only, and the support for
     // Android, MaxOS and Windows should be added on demand in the future.
@@ -262,7 +263,7 @@
   // Returns a weak pointer to an existing adapter for testing purposes only.
   base::WeakPtr<BluetoothAdapter> GetWeakPtrForTesting();
 
-#if defined(OS_CHROMEOS) || defined(OS_LINUX)
+#if defined(OS_LINUX)
   // Shutdown the adapter: tear down and clean up all objects owned by
   // BluetoothAdapter. After this call, the BluetoothAdapter will behave as if
   // no Bluetooth controller exists in the local system. |IsPresent| will return
@@ -444,7 +445,7 @@
       const CreateAdvertisementCallback& callback,
       const AdvertisementErrorCallback& error_callback) = 0;
 
-#if defined(OS_CHROMEOS) || defined(OS_LINUX)
+#if defined(OS_LINUX)
   // Sets the interval between two consecutive advertisements. Valid ranges
   // for the interval are from 20ms to 10.24 seconds, with min <= max.
   // Note: This is a best effort. The actual interval may vary non-trivially
diff --git a/device/bluetooth/bluetooth_adapter_factory.cc b/device/bluetooth/bluetooth_adapter_factory.cc
index cee5e1d..f1e62dc 100644
--- a/device/bluetooth/bluetooth_adapter_factory.cc
+++ b/device/bluetooth/bluetooth_adapter_factory.cc
@@ -38,7 +38,7 @@
 base::LazyInstance<base::WeakPtr<BluetoothAdapter>>::Leaky default_adapter =
     LAZY_INSTANCE_INITIALIZER;
 
-#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if defined(OS_WIN) || defined(OS_LINUX)
 typedef std::vector<BluetoothAdapterFactory::AdapterCallback>
     AdapterCallbackList;
 
@@ -59,7 +59,7 @@
   }
   adapter_callbacks.Get().clear();
 }
-#endif  // defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+#endif  // defined(OS_WIN) || defined(OS_LINUX)
 
 }  // namespace
 
@@ -76,8 +76,8 @@
   // instance even on platforms that would otherwise not support it.
   if (default_adapter.Get())
     return true;
-#if defined(OS_ANDROID) || defined(OS_CHROMEOS) || defined(OS_WIN) || \
-    defined(OS_LINUX) || defined(OS_MACOSX)
+#if defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_LINUX) || \
+    defined(OS_MACOSX)
   return true;
 #else
   return false;
@@ -99,7 +99,7 @@
   return base::win::GetVersion() >= base::win::VERSION_WIN10;
 #elif defined(OS_MACOSX)
   return base::mac::IsAtLeastOS10_10();
-#elif defined(OS_LINUX) || defined(OS_CHROMEOS)
+#elif defined(OS_LINUX)
   return true;
 #else
   return false;
@@ -110,7 +110,7 @@
 void BluetoothAdapterFactory::GetAdapter(const AdapterCallback& callback) {
   DCHECK(IsBluetoothSupported());
 
-#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if defined(OS_WIN) || defined(OS_LINUX)
   if (!default_adapter.Get()) {
     default_adapter.Get() =
         BluetoothAdapter::CreateAdapter(base::Bind(&RunAdapterCallbacks));
@@ -119,20 +119,20 @@
 
   if (!default_adapter.Get()->IsInitialized())
     adapter_callbacks.Get().push_back(callback);
-#else   // !defined(OS_WIN) && !defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#else   // !defined(OS_WIN) && !defined(OS_LINUX)
   if (!default_adapter.Get()) {
     default_adapter.Get() =
         BluetoothAdapter::CreateAdapter(BluetoothAdapter::InitCallback());
   }
 
   DCHECK(default_adapter.Get()->IsInitialized());
-#endif  // defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+#endif  // defined(OS_WIN) || defined(OS_LINUX)
 
   if (default_adapter.Get()->IsInitialized())
     callback.Run(scoped_refptr<BluetoothAdapter>(default_adapter.Get().get()));
 }
 
-#if defined(OS_CHROMEOS) || defined(OS_LINUX)
+#if defined(OS_LINUX)
 // static
 void BluetoothAdapterFactory::Shutdown() {
   if (default_adapter.Get())
diff --git a/device/bluetooth/bluetooth_adapter_factory.h b/device/bluetooth/bluetooth_adapter_factory.h
index 16f8457..7217c2f 100644
--- a/device/bluetooth/bluetooth_adapter_factory.h
+++ b/device/bluetooth/bluetooth_adapter_factory.h
@@ -52,7 +52,7 @@
   // use.
   static void GetAdapter(const AdapterCallback& callback);
 
-#if defined(OS_CHROMEOS) || defined(OS_LINUX)
+#if defined(OS_LINUX)
   // Calls |BluetoothAdapter::Shutdown| on the adapter if
   // present.
   static void Shutdown();
diff --git a/device/bluetooth/bluetooth_advertisement.h b/device/bluetooth/bluetooth_advertisement.h
index 70659f3..d379f72 100644
--- a/device/bluetooth/bluetooth_advertisement.h
+++ b/device/bluetooth/bluetooth_advertisement.h
@@ -17,6 +17,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/observer_list.h"
+#include "build/build_config.h"
 #include "device/bluetooth/bluetooth_export.h"
 
 namespace device {
@@ -37,7 +38,7 @@
                                          // is not registered.
     ERROR_ADVERTISEMENT_INVALID_LENGTH,  // Advertisement is not of a valid
                                          // length.
-#if defined(OS_CHROMEOS) || defined(OS_LINUX)
+#if defined(OS_LINUX)
     ERROR_INVALID_ADVERTISEMENT_INTERVAL,  // Advertisement interval specified
                                            // is out of valid range.
     ERROR_RESET_ADVERTISING,               // Error while resetting advertising.
diff --git a/device/bluetooth/bluetooth_device.h b/device/bluetooth/bluetooth_device.h
index ac9dc0ea..91334697 100644
--- a/device/bluetooth/bluetooth_device.h
+++ b/device/bluetooth/bluetooth_device.h
@@ -22,6 +22,7 @@
 #include "base/optional.h"
 #include "base/strings/string16.h"
 #include "base/time/time.h"
+#include "build/build_config.h"
 #include "device/bluetooth/bluetooth_common.h"
 #include "device/bluetooth/bluetooth_export.h"
 #include "device/bluetooth/bluetooth_remote_gatt_service.h"
@@ -203,7 +204,7 @@
   // and metrics logging,
   virtual uint32_t GetBluetoothClass() const = 0;
 
-#if defined(OS_CHROMEOS) || defined(OS_LINUX)
+#if defined(OS_LINUX)
   // Returns the transport type of the device. Some devices only support one
   // of BR/EDR or LE, and some support both.
   virtual BluetoothTransport GetType() const = 0;
diff --git a/device/bluetooth/bluetooth_local_gatt_characteristic.cc b/device/bluetooth/bluetooth_local_gatt_characteristic.cc
index e4350c0..70ab356 100644
--- a/device/bluetooth/bluetooth_local_gatt_characteristic.cc
+++ b/device/bluetooth/bluetooth_local_gatt_characteristic.cc
@@ -5,11 +5,12 @@
 #include "device/bluetooth/bluetooth_local_gatt_characteristic.h"
 
 #include "base/logging.h"
+#include "build/build_config.h"
 #include "device/bluetooth/bluetooth_local_gatt_service.h"
 
 namespace device {
 
-#if !defined(OS_CHROMEOS) && !defined(OS_LINUX)
+#if !defined(OS_LINUX)
 // static
 base::WeakPtr<BluetoothLocalGattCharacteristic>
 BluetoothLocalGattCharacteristic::Create(const BluetoothUUID& uuid,
diff --git a/device/bluetooth/bluetooth_local_gatt_descriptor.cc b/device/bluetooth/bluetooth_local_gatt_descriptor.cc
index 2ffa979..0ab463bb 100644
--- a/device/bluetooth/bluetooth_local_gatt_descriptor.cc
+++ b/device/bluetooth/bluetooth_local_gatt_descriptor.cc
@@ -5,10 +5,11 @@
 #include "device/bluetooth/bluetooth_local_gatt_descriptor.h"
 
 #include "base/logging.h"
+#include "build/build_config.h"
 
 namespace device {
 
-#if !defined(OS_CHROMEOS) && !defined(OS_LINUX)
+#if !defined(OS_LINUX)
 // static
 base::WeakPtr<BluetoothLocalGattDescriptor>
 BluetoothLocalGattDescriptor::Create(
diff --git a/device/bluetooth/bluetooth_local_gatt_service.cc b/device/bluetooth/bluetooth_local_gatt_service.cc
index 000d6ab..86da8c9b 100644
--- a/device/bluetooth/bluetooth_local_gatt_service.cc
+++ b/device/bluetooth/bluetooth_local_gatt_service.cc
@@ -4,9 +4,11 @@
 
 #include "device/bluetooth/bluetooth_local_gatt_service.h"
 
+#include "build/build_config.h"
+
 namespace device {
 
-#if !defined(OS_CHROMEOS) && !defined(OS_LINUX)
+#if !defined(OS_LINUX)
 // static
 base::WeakPtr<BluetoothLocalGattService> BluetoothLocalGattService::Create(
     BluetoothAdapter* adapter,
diff --git a/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.cc b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.cc
index 69fb27f..9fec1ef 100644
--- a/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.cc
+++ b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.cc
@@ -18,6 +18,7 @@
 #include "base/logging.h"
 #include "base/memory/weak_ptr.h"
 #include "base/values.h"
+#include "build/build_config.h"
 #include "content/public/browser/browser_thread.h"
 #include "device/bluetooth/bluetooth_adapter.h"
 #include "device/bluetooth/bluetooth_gatt_characteristic.h"
@@ -81,7 +82,7 @@
     "An advertisement is already advertising";
 const char kStatusAdvertisementDoesNotExist[] =
     "This advertisement does not exist";
-#if defined(OS_CHROMEOS) || defined(OS_LINUX)
+#if defined(OS_LINUX)
 const char kStatusInvalidAdvertisingInterval[] =
     "Invalid advertising interval specified.";
 #endif
@@ -1269,7 +1270,7 @@
 }
 
 void BluetoothLowEnergySetAdvertisingIntervalFunction::DoWork() {
-#if defined(OS_CHROMEOS) || defined(OS_LINUX)
+#if defined(OS_LINUX)
   BluetoothLowEnergyEventRouter* event_router =
       GetEventRouter(browser_context());
   event_router->adapter()->SetAdvertisingInterval(
@@ -1290,7 +1291,7 @@
 
 void BluetoothLowEnergySetAdvertisingIntervalFunction::ErrorCallback(
     device::BluetoothAdvertisement::ErrorCode status) {
-#if defined(OS_CHROMEOS) || defined(OS_LINUX)
+#if defined(OS_LINUX)
   switch (status) {
     case device::BluetoothAdvertisement::ErrorCode::
         ERROR_INVALID_ADVERTISEMENT_INTERVAL:
diff --git a/extensions/common/extensions_client.cc b/extensions/common/extensions_client.cc
index ec6d686..7dd5df2 100644
--- a/extensions/common/extensions_client.cc
+++ b/extensions/common/extensions_client.cc
@@ -32,6 +32,10 @@
   return false;
 }
 
+std::string ExtensionsClient::GetUserAgent() const {
+  return std::string();
+}
+
 void ExtensionsClient::Set(ExtensionsClient* client) {
   // This can happen in unit tests, where the utility thread runs in-process.
   if (g_client)
diff --git a/extensions/common/extensions_client.h b/extensions/common/extensions_client.h
index f99636a..98e7d47 100644
--- a/extensions/common/extensions_client.h
+++ b/extensions/common/extensions_client.h
@@ -128,6 +128,9 @@
   // Can be overridden in tests.
   virtual bool ExtensionAPIEnabledInExtensionServiceWorkers() const;
 
+  // Returns the user agent used by the content module.
+  virtual std::string GetUserAgent() const;
+
   // Return the extensions client.
   static ExtensionsClient* Get();
 
diff --git a/extensions/shell/browser/shell_browser_main_parts.cc b/extensions/shell/browser/shell_browser_main_parts.cc
index af9ee8d..0763eccc 100644
--- a/extensions/shell/browser/shell_browser_main_parts.cc
+++ b/extensions/shell/browser/shell_browser_main_parts.cc
@@ -52,7 +52,7 @@
 #include "extensions/shell/browser/shell_network_controller_chromeos.h"
 #endif
 
-#if defined(OS_CHROMEOS) || defined(OS_LINUX)
+#if defined(OS_LINUX)
 #include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "device/bluetooth/dbus/bluez_dbus_manager.h"
 #endif
diff --git a/extensions/shell/common/shell_extensions_client.cc b/extensions/shell/common/shell_extensions_client.cc
index cbe52a6..4b8a867 100644
--- a/extensions/shell/common/shell_extensions_client.cc
+++ b/extensions/shell/common/shell_extensions_client.cc
@@ -10,6 +10,8 @@
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "components/version_info/version_info.h"
+#include "content/public/common/user_agent.h"
 #include "extensions/common/api/generated_schemas.h"
 #include "extensions/common/common_manifest_handlers.h"
 #include "extensions/common/extension_urls.h"
@@ -190,4 +192,9 @@
   return true;
 }
 
+std::string ShellExtensionsClient::GetUserAgent() const {
+  return content::BuildUserAgentFromProduct(
+      version_info::GetProductNameAndVersionForUserAgent());
+}
+
 }  // namespace extensions
diff --git a/extensions/shell/common/shell_extensions_client.h b/extensions/shell/common/shell_extensions_client.h
index baea4407..e6b5c76 100644
--- a/extensions/shell/common/shell_extensions_client.h
+++ b/extensions/shell/common/shell_extensions_client.h
@@ -44,6 +44,7 @@
   const GURL& GetWebstoreBaseURL() const override;
   const GURL& GetWebstoreUpdateURL() const override;
   bool IsBlacklistUpdateURL(const GURL& url) const override;
+  std::string GetUserAgent() const override;
 
  private:
   const ExtensionsAPIPermissions extensions_api_permissions_;
diff --git a/gpu/command_buffer/tests/gl_tests_main.cc b/gpu/command_buffer/tests/gl_tests_main.cc
index 9f97550..d2e267e 100644
--- a/gpu/command_buffer/tests/gl_tests_main.cc
+++ b/gpu/command_buffer/tests/gl_tests_main.cc
@@ -18,11 +18,6 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "ui/gl/init/gl_factory.h"
 
-#if defined(OS_ANDROID)
-#include "base/android/jni_android.h"
-#include "ui/gl/android/gl_jni_registrar.h"
-#endif
-
 namespace {
 
 int RunHelper(base::TestSuite* testSuite) {
@@ -44,9 +39,6 @@
 }  // namespace
 
 int main(int argc, char** argv) {
-#if defined(OS_ANDROID)
-  ui::gl::android::RegisterJni(base::android::AttachCurrentThread());
-#endif
   base::TestSuite test_suite(argc, argv);
   base::CommandLine::Init(argc, argv);
 #if defined(OS_MACOSX)
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index 5d3a161..c475537 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -809,6 +809,9 @@
       <message name="IDS_IOS_OPTIONS_ADVANCED_TAB_LABEL" desc="The title of the Advanced section of the Settings page.  [Length: 20em] [iOS only]">
         Advanced
       </message>
+      <message name="IDS_IOS_OPTIONS_CONTENT_SUGGESTIONS" desc="Title for the option to turn on/off content suggestions. [Length: 20em] [iOS only]">
+        Show Content Suggestions
+      </message>
       <message name="IDS_IOS_OPTIONS_CONTINUITY_LABEL" desc="Title for group of items in the Privacy settings table, including Handoff. [Length: 10em] [iOS only]">
         Other Devices
       </message>
diff --git a/ios/chrome/browser/content_suggestions/BUILD.gn b/ios/chrome/browser/content_suggestions/BUILD.gn
index d913df6..c0fe0e0 100644
--- a/ios/chrome/browser/content_suggestions/BUILD.gn
+++ b/ios/chrome/browser/content_suggestions/BUILD.gn
@@ -5,7 +5,6 @@
 source_set("content_suggestions") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
-    "content_suggestions_alert_commands.h",
     "content_suggestions_alert_factory.h",
     "content_suggestions_alert_factory.mm",
     "content_suggestions_category_wrapper.h",
@@ -94,6 +93,7 @@
     "//ios/chrome/browser/ui/alert_coordinator",
     "//ios/chrome/browser/ui/alert_coordinator",
     "//ios/chrome/browser/ui/collection_view/cells",
+    "//ios/chrome/browser/ui/content_suggestions/cells",
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/test/earl_grey:test_support",
     "//ui/strings",
diff --git a/ios/chrome/browser/content_suggestions/content_suggestions_alert_commands.h b/ios/chrome/browser/content_suggestions/content_suggestions_alert_commands.h
deleted file mode 100644
index d734e65..0000000
--- a/ios/chrome/browser/content_suggestions/content_suggestions_alert_commands.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_ALERT_COMMANDS_H_
-#define IOS_CHROME_BROWSER_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_ALERT_COMMANDS_H_
-
-#import <UIKit/UIKit.h>
-
-@class CollectionViewItem;
-
-// Command protocol for the ContentSuggestionsAlertFactory, handling the
-// callbacks from the alerts.
-@protocol ContentSuggestionsAlertCommands
-
-// Opens the URL corresponding to the |item| in a new tab, |incognito| or not.
-// The item has to be a suggestion item.
-- (void)openNewTabWithSuggestionsItem:(nonnull CollectionViewItem*)item
-                            incognito:(BOOL)incognito;
-
-// Adds the |item| to the reading list. The item has to be a suggestion item.
-- (void)addItemToReadingList:(nonnull CollectionViewItem*)item;
-
-// Dismiss the |item| at |indexPath|. The item has to be a suggestion item.
-- (void)dismissSuggestion:(nonnull CollectionViewItem*)item
-              atIndexPath:(nonnull NSIndexPath*)indexPath;
-
-// Open the URL corresponding to the |item| in a new tab, |incognito| or not.
-// The item has to be a Most Visited item.
-- (void)openNewTabWithMostVisitedItem:(nonnull CollectionViewItem*)item
-                            incognito:(BOOL)incognito
-                              atIndex:(NSInteger)mostVisitedIndex;
-
-// Removes the most visited |item|.
-- (void)removeMostVisited:(nonnull CollectionViewItem*)item;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_ALERT_COMMANDS_H_
diff --git a/ios/chrome/browser/content_suggestions/content_suggestions_alert_egtest.mm b/ios/chrome/browser/content_suggestions/content_suggestions_alert_egtest.mm
index 6283b14..a1942a6b7 100644
--- a/ios/chrome/browser/content_suggestions/content_suggestions_alert_egtest.mm
+++ b/ios/chrome/browser/content_suggestions/content_suggestions_alert_egtest.mm
@@ -7,9 +7,9 @@
 #import <EarlGrey/EarlGrey.h>
 #import <XCTest/XCTest.h>
 
-#import "ios/chrome/browser/content_suggestions/content_suggestions_alert_commands.h"
 #import "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h"
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
+#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_gesture_commands.h"
 #include "ios/chrome/browser/ui/ui_util.h"
 #import "ios/chrome/browser/ui/util/top_view_controller.h"
 #include "ios/chrome/grit/ios_strings.h"
@@ -35,6 +35,7 @@
                        onViewController:viewController
                                 atPoint:CGPointMake(50, 50)
                             atIndexPath:nil
+                        readLaterAction:YES
                          commandHandler:nil];
   [coordinator start];
 
@@ -67,11 +68,11 @@
   UIViewController* viewController =
       top_view_controller::TopPresentedViewController();
   AlertCoordinator* coordinator = [ContentSuggestionsAlertFactory
-      alertCoordinatorForSuggestionItem:nil
-                       onViewController:viewController
-                                atPoint:CGPointMake(50, 50)
-                            atIndexPath:nil
-                         commandHandler:nil];
+      alertCoordinatorForMostVisitedItem:nil
+                        onViewController:viewController
+                                 atPoint:CGPointMake(50, 50)
+                             atIndexPath:nil
+                          commandHandler:nil];
   [coordinator start];
 
   [[EarlGrey
diff --git a/ios/chrome/browser/content_suggestions/content_suggestions_alert_factory.h b/ios/chrome/browser/content_suggestions/content_suggestions_alert_factory.h
index accca13..2b51a0d5 100644
--- a/ios/chrome/browser/content_suggestions/content_suggestions_alert_factory.h
+++ b/ios/chrome/browser/content_suggestions/content_suggestions_alert_factory.h
@@ -8,8 +8,9 @@
 #import <UIKit/UIKit.h>
 
 @class AlertCoordinator;
-@class CollectionViewItem;
-@protocol ContentSuggestionsAlertCommands;
+@class ContentSuggestionsItem;
+@class ContentSuggestionsMostVisitedItem;
+@protocol ContentSuggestionsGestureCommands;
 
 // Factory for AlertCoordinators for ContentSuggestions.
 @interface ContentSuggestionsAlertFactory : NSObject
@@ -20,21 +21,22 @@
 // |commandHandler| will receive callbacks when the user chooses one of the
 // options displayed by the alert.
 + (AlertCoordinator*)
-alertCoordinatorForSuggestionItem:(CollectionViewItem*)item
+alertCoordinatorForSuggestionItem:(ContentSuggestionsItem*)item
                  onViewController:(UIViewController*)viewController
                           atPoint:(CGPoint)touchLocation
                       atIndexPath:(NSIndexPath*)indexPath
+                  readLaterAction:(BOOL)readLaterAction
                    commandHandler:
-                       (id<ContentSuggestionsAlertCommands>)commandHandler;
+                       (id<ContentSuggestionsGestureCommands>)commandHandler;
 
 // Same as above but for a MostVisited item.
 + (AlertCoordinator*)
-alertCoordinatorForMostVisitedItem:(CollectionViewItem*)item
+alertCoordinatorForMostVisitedItem:(ContentSuggestionsMostVisitedItem*)item
                   onViewController:(UIViewController*)viewController
                            atPoint:(CGPoint)touchLocation
                        atIndexPath:(NSIndexPath*)indexPath
                     commandHandler:
-                        (id<ContentSuggestionsAlertCommands>)commandHandler;
+                        (id<ContentSuggestionsGestureCommands>)commandHandler;
 
 @end
 
diff --git a/ios/chrome/browser/content_suggestions/content_suggestions_alert_factory.mm b/ios/chrome/browser/content_suggestions/content_suggestions_alert_factory.mm
index 1deedfb5..dcec6e0 100644
--- a/ios/chrome/browser/content_suggestions/content_suggestions_alert_factory.mm
+++ b/ios/chrome/browser/content_suggestions/content_suggestions_alert_factory.mm
@@ -4,9 +4,10 @@
 
 #import "ios/chrome/browser/content_suggestions/content_suggestions_alert_factory.h"
 
-#import "ios/chrome/browser/content_suggestions/content_suggestions_alert_commands.h"
 #import "ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.h"
-#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
+#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_gesture_commands.h"
+#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.h"
+#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/strings/grit/ui_strings.h"
@@ -18,12 +19,13 @@
 @implementation ContentSuggestionsAlertFactory
 
 + (AlertCoordinator*)
-alertCoordinatorForSuggestionItem:(CollectionViewItem*)item
+alertCoordinatorForSuggestionItem:(ContentSuggestionsItem*)item
                  onViewController:(UIViewController*)viewController
                           atPoint:(CGPoint)touchLocation
                       atIndexPath:(NSIndexPath*)indexPath
+                  readLaterAction:(BOOL)readLaterAction
                    commandHandler:
-                       (id<ContentSuggestionsAlertCommands>)commandHandler {
+                       (id<ContentSuggestionsGestureCommands>)commandHandler {
   AlertCoordinator* alertCoordinator = [[ActionSheetCoordinator alloc]
       initWithBaseViewController:viewController
                            title:nil
@@ -32,15 +34,15 @@
                                             0)
                             view:[viewController view]];
 
-  __weak CollectionViewItem* weakItem = item;
-  __weak id<ContentSuggestionsAlertCommands> weakCommandHandler =
+  __weak ContentSuggestionsItem* weakItem = item;
+  __weak id<ContentSuggestionsGestureCommands> weakCommandHandler =
       commandHandler;
 
   NSString* openInNewTabTitle =
       l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB);
   [alertCoordinator addItemWithTitle:openInNewTabTitle
                               action:^{
-                                CollectionViewItem* strongItem = weakItem;
+                                ContentSuggestionsItem* strongItem = weakItem;
                                 if (strongItem) {
                                   // TODO(crbug.com/691979): Add metrics.
                                   [weakCommandHandler
@@ -54,7 +56,7 @@
       l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWINCOGNITOTAB);
   [alertCoordinator addItemWithTitle:openInNewTabIncognitoTitle
                               action:^{
-                                CollectionViewItem* strongItem = weakItem;
+                                ContentSuggestionsItem* strongItem = weakItem;
                                 if (strongItem) {
                                   // TODO(crbug.com/691979): Add metrics.
                                   [weakCommandHandler
@@ -64,24 +66,26 @@
                               }
                                style:UIAlertActionStyleDefault];
 
-  NSString* readLaterTitle =
-      l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_ADDTOREADINGLIST);
-  [alertCoordinator
-      addItemWithTitle:readLaterTitle
-                action:^{
-                  CollectionViewItem* strongItem = weakItem;
-                  if (strongItem) {
-                    // TODO(crbug.com/691979): Add metrics.
-                    [weakCommandHandler addItemToReadingList:strongItem];
+  if (readLaterAction) {
+    NSString* readLaterTitle =
+        l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_ADDTOREADINGLIST);
+    [alertCoordinator
+        addItemWithTitle:readLaterTitle
+                  action:^{
+                    ContentSuggestionsItem* strongItem = weakItem;
+                    if (strongItem) {
+                      // TODO(crbug.com/691979): Add metrics.
+                      [weakCommandHandler addItemToReadingList:strongItem];
+                    }
                   }
-                }
-                 style:UIAlertActionStyleDefault];
+                   style:UIAlertActionStyleDefault];
+  }
 
   NSString* deleteTitle =
       l10n_util::GetNSString(IDS_IOS_CONTENT_SUGGESTIONS_REMOVE);
   [alertCoordinator addItemWithTitle:deleteTitle
                               action:^{
-                                CollectionViewItem* strongItem = weakItem;
+                                ContentSuggestionsItem* strongItem = weakItem;
                                 if (strongItem) {
                                   // TODO(crbug.com/691979): Add metrics.
                                   [weakCommandHandler
@@ -100,12 +104,12 @@
 }
 
 + (AlertCoordinator*)
-alertCoordinatorForMostVisitedItem:(CollectionViewItem*)item
+alertCoordinatorForMostVisitedItem:(ContentSuggestionsMostVisitedItem*)item
                   onViewController:(UIViewController*)viewController
                            atPoint:(CGPoint)touchLocation
                        atIndexPath:(NSIndexPath*)indexPath
                     commandHandler:
-                        (id<ContentSuggestionsAlertCommands>)commandHandler {
+                        (id<ContentSuggestionsGestureCommands>)commandHandler {
   AlertCoordinator* alertCoordinator = [[ActionSheetCoordinator alloc]
       initWithBaseViewController:viewController
                            title:nil
@@ -114,15 +118,15 @@
                                             0)
                             view:[viewController view]];
 
-  __weak CollectionViewItem* weakItem = item;
-  __weak id<ContentSuggestionsAlertCommands> weakCommandHandler =
+  __weak ContentSuggestionsMostVisitedItem* weakItem = item;
+  __weak id<ContentSuggestionsGestureCommands> weakCommandHandler =
       commandHandler;
 
   [alertCoordinator
       addItemWithTitle:l10n_util::GetNSStringWithFixup(
                            IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB)
                 action:^{
-                  CollectionViewItem* strongItem = weakItem;
+                  ContentSuggestionsMostVisitedItem* strongItem = weakItem;
                   if (strongItem) {
                     [weakCommandHandler
                         openNewTabWithMostVisitedItem:strongItem
@@ -136,7 +140,7 @@
       addItemWithTitle:l10n_util::GetNSStringWithFixup(
                            IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWINCOGNITOTAB)
                 action:^{
-                  CollectionViewItem* strongItem = weakItem;
+                  ContentSuggestionsMostVisitedItem* strongItem = weakItem;
                   if (strongItem) {
                     [weakCommandHandler
                         openNewTabWithMostVisitedItem:strongItem
@@ -150,7 +154,7 @@
       addItemWithTitle:l10n_util::GetNSStringWithFixup(
                            IDS_IOS_CONTENT_SUGGESTIONS_REMOVE)
                 action:^{
-                  CollectionViewItem* strongItem = weakItem;
+                  ContentSuggestionsMostVisitedItem* strongItem = weakItem;
                   if (strongItem) {
                     [weakCommandHandler removeMostVisited:strongItem];
                   }
diff --git a/ios/chrome/browser/content_suggestions/content_suggestions_coordinator.mm b/ios/chrome/browser/content_suggestions/content_suggestions_coordinator.mm
index 87c50c9c3..70069b59 100644
--- a/ios/chrome/browser/content_suggestions/content_suggestions_coordinator.mm
+++ b/ios/chrome/browser/content_suggestions/content_suggestions_coordinator.mm
@@ -17,7 +17,6 @@
 #include "components/reading_list/core/reading_list_model.h"
 #include "components/strings/grit/components_strings.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#import "ios/chrome/browser/content_suggestions/content_suggestions_alert_commands.h"
 #import "ios/chrome/browser/content_suggestions/content_suggestions_alert_factory.h"
 #import "ios/chrome/browser/content_suggestions/content_suggestions_header_view_controller.h"
 #import "ios/chrome/browser/content_suggestions/content_suggestions_header_view_controller_delegate.h"
@@ -35,6 +34,7 @@
 #import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
 #import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
+#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_gesture_commands.h"
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.h"
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.h"
@@ -66,8 +66,8 @@
 }  // namespace
 
 @interface ContentSuggestionsCoordinator ()<
-    ContentSuggestionsAlertCommands,
     ContentSuggestionsCommands,
+    ContentSuggestionsGestureCommands,
     ContentSuggestionsHeaderViewControllerCommandHandler,
     ContentSuggestionsHeaderViewControllerDelegate,
     ContentSuggestionsViewControllerAudience,
@@ -217,14 +217,18 @@
         rendererInitiated:NO];
 }
 
-- (void)displayContextMenuForArticle:(CollectionViewItem*)item
-                             atPoint:(CGPoint)touchLocation
-                         atIndexPath:(NSIndexPath*)indexPath {
+- (void)displayContextMenuForSuggestion:(CollectionViewItem*)item
+                                atPoint:(CGPoint)touchLocation
+                            atIndexPath:(NSIndexPath*)indexPath
+                        readLaterAction:(BOOL)readLaterAction {
+  ContentSuggestionsItem* suggestionsItem =
+      base::mac::ObjCCastStrict<ContentSuggestionsItem>(item);
   self.alertCoordinator = [ContentSuggestionsAlertFactory
-      alertCoordinatorForSuggestionItem:item
+      alertCoordinatorForSuggestionItem:suggestionsItem
                        onViewController:self.suggestionsViewController
                                 atPoint:touchLocation
                             atIndexPath:indexPath
+                        readLaterAction:readLaterAction
                          commandHandler:self];
 
   [self.alertCoordinator start];
@@ -233,8 +237,10 @@
 - (void)displayContextMenuForMostVisitedItem:(CollectionViewItem*)item
                                      atPoint:(CGPoint)touchLocation
                                  atIndexPath:(NSIndexPath*)indexPath {
+  ContentSuggestionsMostVisitedItem* mostVisitedItem =
+      base::mac::ObjCCastStrict<ContentSuggestionsMostVisitedItem>(item);
   self.alertCoordinator = [ContentSuggestionsAlertFactory
-      alertCoordinatorForMostVisitedItem:item
+      alertCoordinatorForMostVisitedItem:mostVisitedItem
                         onViewController:self.suggestionsViewController
                                  atPoint:touchLocation
                              atIndexPath:indexPath
@@ -274,52 +280,54 @@
         rendererInitiated:NO];
 }
 
-#pragma mark - ContentSuggestionsAlertCommands
+#pragma mark - ContentSuggestionsGestureCommands
 
-- (void)openNewTabWithSuggestionsItem:(CollectionViewItem*)item
+- (void)openNewTabWithSuggestionsItem:(ContentSuggestionsItem*)item
                             incognito:(BOOL)incognito {
-  ContentSuggestionsItem* suggestionsItem =
-      base::mac::ObjCCastStrict<ContentSuggestionsItem>(item);
-  [self openNewTabWithURL:suggestionsItem.URL incognito:incognito];
+  [self openNewTabWithURL:item.URL incognito:incognito];
 }
 
-- (void)addItemToReadingList:(CollectionViewItem*)item {
-  ContentSuggestionsItem* suggestionsItem =
-      base::mac::ObjCCastStrict<ContentSuggestionsItem>(item);
+- (void)addItemToReadingList:(ContentSuggestionsItem*)item {
   base::RecordAction(base::UserMetricsAction("MobileReadingListAdd"));
   ReadingListModel* readingModel =
       ReadingListModelFactory::GetForBrowserState(self.browserState);
-  readingModel->AddEntry(suggestionsItem.URL,
-                         base::SysNSStringToUTF8(suggestionsItem.title),
+  readingModel->AddEntry(item.URL, base::SysNSStringToUTF8(item.title),
                          reading_list::ADDED_VIA_CURRENT_APP);
 }
 
-- (void)dismissSuggestion:(CollectionViewItem*)item
+- (void)dismissSuggestion:(ContentSuggestionsItem*)item
               atIndexPath:(NSIndexPath*)indexPath {
-  ContentSuggestionsItem* suggestionsItem =
-      base::mac::ObjCCastStrict<ContentSuggestionsItem>(item);
+  NSIndexPath* itemIndexPath = indexPath;
+  if (!itemIndexPath) {
+    // If the caller uses a nil |indexPath|, find it from the model.
+    itemIndexPath = [self.suggestionsViewController.collectionViewModel
+        indexPathForItem:item];
+  }
 
   // TODO(crbug.com/691979): Add metrics.
-  [self.contentSuggestionsMediator
-      dismissSuggestion:suggestionsItem.suggestionIdentifier];
-  [self.suggestionsViewController dismissEntryAtIndexPath:indexPath];
+  [self.contentSuggestionsMediator dismissSuggestion:item.suggestionIdentifier];
+  [self.suggestionsViewController dismissEntryAtIndexPath:itemIndexPath];
 }
 
-- (void)openNewTabWithMostVisitedItem:(CollectionViewItem*)item
+- (void)openNewTabWithMostVisitedItem:(ContentSuggestionsMostVisitedItem*)item
                             incognito:(BOOL)incognito
                               atIndex:(NSInteger)index {
-  ContentSuggestionsMostVisitedItem* mostVisitedItem =
-      base::mac::ObjCCastStrict<ContentSuggestionsMostVisitedItem>(item);
-  [self logMostVisitedOpening:mostVisitedItem atIndex:index];
-  [self openNewTabWithURL:mostVisitedItem.URL incognito:incognito];
+  [self logMostVisitedOpening:item atIndex:index];
+  [self openNewTabWithURL:item.URL incognito:incognito];
 }
 
-- (void)removeMostVisited:(CollectionViewItem*)item {
-  ContentSuggestionsMostVisitedItem* mostVisitedItem =
-      base::mac::ObjCCastStrict<ContentSuggestionsMostVisitedItem>(item);
+- (void)openNewTabWithMostVisitedItem:(ContentSuggestionsMostVisitedItem*)item
+                            incognito:(BOOL)incognito {
+  NSInteger index =
+      [self.suggestionsViewController.collectionViewModel indexPathForItem:item]
+          .item;
+  [self openNewTabWithMostVisitedItem:item incognito:incognito atIndex:index];
+}
+
+- (void)removeMostVisited:(ContentSuggestionsMostVisitedItem*)item {
   base::RecordAction(base::UserMetricsAction("MostVisited_UrlBlacklisted"));
-  [self.contentSuggestionsMediator blacklistMostVisitedURL:mostVisitedItem.URL];
-  [self showMostVisitedUndoForURL:mostVisitedItem.URL];
+  [self.contentSuggestionsMediator blacklistMostVisitedURL:item.URL];
+  [self showMostVisitedUndoForURL:item.URL];
 }
 
 #pragma mark - ContentSuggestionsHeaderViewControllerDelegate
diff --git a/ios/chrome/browser/content_suggestions/content_suggestions_mediator.h b/ios/chrome/browser/content_suggestions/content_suggestions_mediator.h
index 5791abd..172d6af 100644
--- a/ios/chrome/browser/content_suggestions/content_suggestions_mediator.h
+++ b/ios/chrome/browser/content_suggestions/content_suggestions_mediator.h
@@ -25,6 +25,7 @@
 }
 
 @protocol ContentSuggestionsCommands;
+@protocol ContentSuggestionsGestureCommands;
 @protocol ContentSuggestionsHeaderProvider;
 @class ContentSuggestionIdentifier;
 class GURL;
@@ -49,8 +50,9 @@
 - (nullable instancetype)init NS_UNAVAILABLE;
 
 // Command handler for the mediator.
-@property(nonatomic, weak, nullable) id<ContentSuggestionsCommands>
-    commandHandler;
+@property(nonatomic, weak, nullable)
+    id<ContentSuggestionsCommands, ContentSuggestionsGestureCommands>
+        commandHandler;
 
 @property(nonatomic, weak, nullable) id<ContentSuggestionsHeaderProvider>
     headerProvider;
diff --git a/ios/chrome/browser/content_suggestions/content_suggestions_mediator.mm b/ios/chrome/browser/content_suggestions/content_suggestions_mediator.mm
index 25709894..73744eb 100644
--- a/ios/chrome/browser/content_suggestions/content_suggestions_mediator.mm
+++ b/ios/chrome/browser/content_suggestions/content_suggestions_mediator.mm
@@ -452,6 +452,7 @@
     ContentSuggestionsItem* suggestion =
         ConvertSuggestion(contentSuggestion, sectionInfo, category);
     suggestion.delegate = self;
+    suggestion.commandHandler = self.commandHandler;
     [self.faviconMediator fetchFaviconForSuggestions:suggestion
                                           inCategory:category];
 
diff --git a/ios/chrome/browser/content_suggestions/mediator_util.mm b/ios/chrome/browser/content_suggestions/mediator_util.mm
index 4dd5855..4516c0c 100644
--- a/ios/chrome/browser/content_suggestions/mediator_util.mm
+++ b/ios/chrome/browser/content_suggestions/mediator_util.mm
@@ -64,6 +64,7 @@
   }
   if (category.IsKnownCategory(ntp_snippets::KnownCategories::ARTICLES)) {
     suggestion.hasImage = YES;
+    suggestion.readLaterAction = YES;
   }
 
   return suggestion;
diff --git a/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory_util.cc b/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory_util.cc
index ef4fbd6b..615a945 100644
--- a/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory_util.cc
+++ b/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory_util.cc
@@ -43,6 +43,7 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/favicon/ios_chrome_large_icon_service_factory.h"
 #include "ios/chrome/browser/history/history_service_factory.h"
+#include "ios/chrome/browser/pref_names.h"
 #include "ios/chrome/browser/reading_list/reading_list_model_factory.h"
 #include "ios/chrome/browser/signin/oauth2_token_service_factory.h"
 #include "ios/chrome/browser/signin/signin_manager_factory.h"
@@ -185,6 +186,7 @@
       base::Bind(&ParseJson), GetFetchEndpoint(GetChannel()), api_key,
       service->user_classifier());
 
+  std::string pref_name = prefs::kContentSuggestionsRemoteEnabled;
   auto provider = base::MakeUnique<RemoteSuggestionsProviderImpl>(
       service, prefs, GetApplicationContext()->GetApplicationLocale(),
       service->category_ranker(), service->remote_suggestions_scheduler(),
@@ -193,7 +195,7 @@
                                          request_context.get()),
       base::MakeUnique<RemoteSuggestionsDatabase>(database_dir, task_runner),
       base::MakeUnique<RemoteSuggestionsStatusService>(signin_manager, prefs,
-                                                       std::string()),
+                                                       pref_name),
       /*prefetched_pages_tracker=*/nullptr);
 
   service->remote_suggestions_scheduler()->SetProvider(provider.get());
diff --git a/ios/chrome/browser/pref_names.cc b/ios/chrome/browser/pref_names.cc
index 880f1c6..bc5bb06 100644
--- a/ios/chrome/browser/pref_names.cc
+++ b/ios/chrome/browser/pref_names.cc
@@ -100,6 +100,10 @@
 // Boolean that is true when Suggest support is enabled.
 const char kSearchSuggestEnabled[] = "search.suggest_enabled";
 
+// Boolean that is true when Suggest support is enabled.
+const char kContentSuggestionsRemoteEnabled[] =
+    "content_suggestions.remote_enabled";
+
 // A boolean pref set to true if prediction of network actions is allowed.
 // Actions include prerendering of web pages.
 // NOTE: The "dns_prefetching.enabled" value is used so that historical user
diff --git a/ios/chrome/browser/pref_names.h b/ios/chrome/browser/pref_names.h
index 110ffae..5d3a34e 100644
--- a/ios/chrome/browser/pref_names.h
+++ b/ios/chrome/browser/pref_names.h
@@ -30,6 +30,7 @@
 extern const char kNtpShownPage[];
 extern const char kSavingBrowserHistoryDisabled[];
 extern const char kSearchSuggestEnabled[];
+extern const char kContentSuggestionsRemoteEnabled[];
 
 // TODO(crbug.com/538573): Consider migrating from these two bools to an integer
 // since only three cases are supported.
diff --git a/ios/chrome/browser/prefs/browser_prefs.mm b/ios/chrome/browser/prefs/browser_prefs.mm
index 1c46425..10bbdcc 100644
--- a/ios/chrome/browser/prefs/browser_prefs.mm
+++ b/ios/chrome/browser/prefs/browser_prefs.mm
@@ -156,6 +156,9 @@
   registry->RegisterBooleanPref(
       prefs::kSearchSuggestEnabled, true,
       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterBooleanPref(
+      prefs::kContentSuggestionsRemoteEnabled, true,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
   registry->RegisterBooleanPref(prefs::kSavingBrowserHistoryDisabled, false);
   registry->RegisterIntegerPref(prefs::kNtpShownPage, 1 << 10);
 
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn b/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn
index 6cbaabd..afb8f990 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn
+++ b/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn
@@ -4,6 +4,7 @@
 
 source_set("cells") {
   sources = [
+    "content_suggestions_gesture_commands.h",
     "content_suggestions_item.h",
     "content_suggestions_item.mm",
     "content_suggestions_most_visited_item.h",
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_gesture_commands.h b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_gesture_commands.h
new file mode 100644
index 0000000..d1126494
--- /dev/null
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_gesture_commands.h
@@ -0,0 +1,50 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_GESTURE_COMMANDS_H_
+#define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_GESTURE_COMMANDS_H_
+
+#import <UIKit/UIKit.h>
+
+@class ContentSuggestionsItem;
+@class ContentSuggestionsMostVisitedItem;
+
+// Command protocol for the interactions based on a gesture, handling the
+// callbacks from the alerts and the accessibility custom actions.
+@protocol ContentSuggestionsGestureCommands
+
+// Opens the URL corresponding to the |item| in a new tab, |incognito| or not.
+// The item has to be a suggestion item.
+- (void)openNewTabWithSuggestionsItem:(nonnull ContentSuggestionsItem*)item
+                            incognito:(BOOL)incognito;
+
+// Adds the |item| to the reading list. The item has to be a suggestion item.
+- (void)addItemToReadingList:(nonnull ContentSuggestionsItem*)item;
+
+// Dismiss the |item| at |indexPath|. The item has to be a suggestion item.
+// If |indexPath| is nil, the commands handler will find the index path
+// associated with the |item|.
+- (void)dismissSuggestion:(nonnull ContentSuggestionsItem*)item
+              atIndexPath:(nullable NSIndexPath*)indexPath;
+
+// Open the URL corresponding to the |item| in a new tab, |incognito| or not.
+// The item has to be a Most Visited item.
+- (void)openNewTabWithMostVisitedItem:
+            (nonnull ContentSuggestionsMostVisitedItem*)item
+                            incognito:(BOOL)incognito
+                              atIndex:(NSInteger)mostVisitedIndex;
+
+// Open the URL corresponding to the |item| in a new tab, |incognito| or not.
+// The index of the item will be find by the  command handler. The item has to
+// be a Most Visited item.
+- (void)openNewTabWithMostVisitedItem:
+            (nonnull ContentSuggestionsMostVisitedItem*)item
+                            incognito:(BOOL)incognito;
+
+// Removes the most visited |item|.
+- (void)removeMostVisited:(nonnull ContentSuggestionsMostVisitedItem*)item;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_GESTURE_COMMANDS_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.h b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.h
index f7db2f4f..e0168ec 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.h
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.h
@@ -16,6 +16,8 @@
 @class FaviconAttributes;
 class GURL;
 
+@protocol ContentSuggestionsGestureCommands;
+
 // Delegate for SuggestedContent.
 @protocol ContentSuggestionsItemDelegate
 
@@ -48,6 +50,10 @@
 @property(nonatomic, strong) FaviconAttributes* attributes;
 // URL for the favicon, if different of |URL|.
 @property(nonatomic, assign) GURL faviconURL;
+// Whether this item should have an option to be read later.
+@property(nonatomic, assign) BOOL readLaterAction;
+// Command handler for the accessibility custom actions.
+@property(nonatomic, weak) id<ContentSuggestionsGestureCommands> commandHandler;
 
 @end
 
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.mm
index 201092e..fd7cf891d 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.mm
@@ -7,6 +7,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/time/time.h"
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.h"
+#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_gesture_commands.h"
 #import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion_identifier.h"
 #import "ios/chrome/browser/ui/favicon/favicon_attributes.h"
 #import "ios/chrome/browser/ui/favicon/favicon_view.h"
@@ -46,6 +47,8 @@
 @synthesize faviconURL = _faviconURL;
 @synthesize hasImage = _hasImage;
 @synthesize firstTimeWithImage = _firstTimeWithImage;
+@synthesize readLaterAction = _readLaterAction;
+@synthesize commandHandler = _commandHandler;
 
 - (instancetype)initWithType:(NSInteger)type
                        title:(NSString*)title
@@ -75,6 +78,7 @@
                                              date:[self relativeDate]];
   cell.isAccessibilityElement = YES;
   cell.accessibilityLabel = [self accessibilityLabel];
+  cell.accessibilityCustomActions = [self customActions];
 }
 
 - (void)setImage:(UIImage*)image {
@@ -121,4 +125,67 @@
       base::SysNSStringToUTF16([self relativeDate]));
 }
 
+#pragma mark - AccessibilityCustomAction
+
+// Custom action for a cell configured with this item.
+- (NSArray<UIAccessibilityCustomAction*>*)customActions {
+  UIAccessibilityCustomAction* openInNewTab =
+      [[UIAccessibilityCustomAction alloc]
+          initWithName:l10n_util::GetNSString(
+                           IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB)
+                target:self
+              selector:@selector(openInNewTab)];
+  UIAccessibilityCustomAction* openInNewIncognitoTab =
+      [[UIAccessibilityCustomAction alloc]
+          initWithName:l10n_util::GetNSString(
+                           IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWINCOGNITOTAB)
+                target:self
+              selector:@selector(openInNewIncognitoTab)];
+  NSMutableArray* customActions = [NSMutableArray
+      arrayWithObjects:openInNewTab, openInNewIncognitoTab, nil];
+
+  if (self.readLaterAction) {
+    UIAccessibilityCustomAction* readLater =
+        [[UIAccessibilityCustomAction alloc]
+            initWithName:l10n_util::GetNSString(
+                             IDS_IOS_CONTENT_CONTEXT_ADDTOREADINGLIST)
+                  target:self
+                selector:@selector(readLater)];
+    [customActions addObject:readLater];
+  }
+
+  UIAccessibilityCustomAction* removeSuggestion = [
+      [UIAccessibilityCustomAction alloc]
+      initWithName:l10n_util::GetNSString(IDS_IOS_CONTENT_SUGGESTIONS_REMOVE)
+            target:self
+          selector:@selector(removeSuggestion)];
+  [customActions addObject:removeSuggestion];
+
+  return customActions;
+}
+
+// Target for custom action.
+- (BOOL)openInNewTab {
+  [self.commandHandler openNewTabWithSuggestionsItem:self incognito:NO];
+  return YES;
+}
+
+// Target for custom action.
+- (BOOL)openInNewIncognitoTab {
+  [self.commandHandler openNewTabWithSuggestionsItem:self incognito:YES];
+  return YES;
+}
+
+// Target for custom action.
+- (BOOL)readLater {
+  [self.commandHandler addItemToReadingList:self];
+  return YES;
+}
+
+// Target for custom action.
+- (BOOL)removeSuggestion {
+  [self.commandHandler dismissSuggestion:self atIndexPath:nil];
+  return YES;
+}
+
 @end
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item_unittest.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item_unittest.mm
index 56d3175b..dafd30dc 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item_unittest.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item_unittest.mm
@@ -37,6 +37,7 @@
   item.hasImage = YES;
   item.publisher = publisher;
   item.publishDate = publishTime;
+  item.readLaterAction = YES;
   OCMExpect([delegateMock loadImageForSuggestedItem:item]);
   ContentSuggestionsCell* cell = [[[item cellClass] alloc] init];
   ASSERT_EQ([ContentSuggestionsCell class], [cell class]);
@@ -54,6 +55,7 @@
   EXPECT_OCMOCK_VERIFY(cellMock);
   EXPECT_EQ(title, cell.titleLabel.text);
   EXPECT_OCMOCK_VERIFY(delegateMock);
+  EXPECT_EQ(4U, [cell.accessibilityCustomActions count]);
 }
 
 // Tests that configureCell: does not call the delegate if it fetched the image
@@ -139,4 +141,24 @@
   EXPECT_OCMOCK_VERIFY(cell1);
   EXPECT_OCMOCK_VERIFY(cell2);
 }
+
+// Tests the custom actions when there is no read later actions.
+TEST(ContentSuggestionsItemTest, NoReadLaterAction) {
+  // Setup.
+  NSString* title = @"testTitle";
+  GURL url = GURL("http://chromium.org");
+  ContentSuggestionsItem* item =
+      [[ContentSuggestionsItem alloc] initWithType:0 title:title url:url];
+  item.readLaterAction = NO;
+  item.image = [[UIImage alloc] init];
+
+  ContentSuggestionsCell* cell = [[[item cellClass] alloc] init];
+
+  // Action.
+  [item configureCell:cell];
+
+  // Tests.
+  EXPECT_EQ(3U, [cell.accessibilityCustomActions count]);
+}
+
 }  // namespace
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h
index 7b73994..1ebca56 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h
@@ -10,6 +10,7 @@
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
 #import "ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h"
 
+@protocol ContentSuggestionsGestureCommands;
 @class FaviconAttributes;
 class GURL;
 
@@ -26,6 +27,9 @@
 @property(nonatomic, assign) ntp_tiles::TileSource source;
 // Attributes for favicon.
 @property(nonatomic, strong, nullable) FaviconAttributes* attributes;
+// Command handler for the accessibility custom actions.
+@property(nonatomic, weak, nullable) id<ContentSuggestionsGestureCommands>
+    commandHandler;
 
 - (ntp_tiles::TileVisualType)tileType;
 
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.mm
index a314f4cc..9f04f3d7 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.mm
@@ -4,10 +4,13 @@
 
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h"
 
+#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_gesture_commands.h"
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_cell.h"
 #import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion_identifier.h"
 #import "ios/chrome/browser/ui/favicon/favicon_attributes.h"
 #import "ios/chrome/browser/ui/favicon/favicon_view.h"
+#include "ios/chrome/grit/ios_strings.h"
+#include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -21,6 +24,7 @@
 @synthesize title = _title;
 @synthesize URL = _URL;
 @synthesize source = _source;
+@synthesize commandHandler = _commandHandler;
 
 - (instancetype)initWithType:(NSInteger)type {
   self = [super initWithType:type];
@@ -35,6 +39,7 @@
   cell.titleLabel.text = self.title;
   cell.accessibilityLabel = self.title;
   [cell.faviconView configureWithAttributes:self.attributes];
+  cell.accessibilityCustomActions = [self customActions];
 }
 
 - (ntp_tiles::TileVisualType)tileType {
@@ -52,4 +57,51 @@
   return [ContentSuggestionsMostVisitedCell defaultSize].height;
 }
 
+#pragma mark - AccessibilityCustomAction
+
+// Custom action for a cell configured with this item.
+- (NSArray<UIAccessibilityCustomAction*>*)customActions {
+  UIAccessibilityCustomAction* openInNewTab =
+      [[UIAccessibilityCustomAction alloc]
+          initWithName:l10n_util::GetNSString(
+                           IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB)
+                target:self
+              selector:@selector(openInNewTab)];
+  UIAccessibilityCustomAction* openInNewIncognitoTab =
+      [[UIAccessibilityCustomAction alloc]
+          initWithName:l10n_util::GetNSString(
+                           IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWINCOGNITOTAB)
+                target:self
+              selector:@selector(openInNewIncognitoTab)];
+  UIAccessibilityCustomAction* removeMostVisited = [
+      [UIAccessibilityCustomAction alloc]
+      initWithName:l10n_util::GetNSString(IDS_IOS_CONTENT_SUGGESTIONS_REMOVE)
+            target:self
+          selector:@selector(removeMostVisited)];
+
+  NSArray* customActions =
+      [NSArray arrayWithObjects:openInNewTab, openInNewIncognitoTab,
+                                removeMostVisited, nil];
+
+  return customActions;
+}
+
+// Target for custom action.
+- (BOOL)openInNewTab {
+  [self.commandHandler openNewTabWithMostVisitedItem:self incognito:NO];
+  return YES;
+}
+
+// Target for custom action.
+- (BOOL)openInNewIncognitoTab {
+  [self.commandHandler openNewTabWithMostVisitedItem:self incognito:YES];
+  return YES;
+}
+
+// Target for custom action.
+- (BOOL)removeMostVisited {
+  [self.commandHandler removeMostVisited:self];
+  return YES;
+}
+
 @end
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm
index 5cf8c5ec..18ee041 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm
@@ -119,6 +119,12 @@
   }
 }
 
+// Returns whether this |sectionIdentifier| comes from ContentSuggestions.
+BOOL IsFromContentSuggestions(NSInteger sectionIdentifier) {
+  return sectionIdentifier == SectionIdentifierArticles ||
+         sectionIdentifier == SectionIdentifierReadingList;
+}
+
 const CGFloat kNumberOfMostVisitedLines = 2;
 
 }  // namespace
@@ -133,6 +139,9 @@
 @property(nonatomic, assign) CGFloat collectionWidth;
 // Whether an item of type ItemTypePromo has already been added to the model.
 @property(nonatomic, assign) BOOL promoAdded;
+// All SectionIdentifier from ContentSuggestions.
+@property(nonatomic, strong)
+    NSMutableSet<NSNumber*>* sectionIdentifiersFromContentSuggestions;
 
 @end
 
@@ -143,6 +152,8 @@
 @synthesize sectionInfoBySectionIdentifier = _sectionInfoBySectionIdentifier;
 @synthesize collectionWidth = _collectionWidth;
 @synthesize promoAdded = _promoAdded;
+@synthesize sectionIdentifiersFromContentSuggestions =
+    _sectionIdentifiersFromContentSuggestions;
 
 - (instancetype)initWithDataSource:
     (id<ContentSuggestionsDataSource>)dataSource {
@@ -151,6 +162,7 @@
     _promoAdded = NO;
     _dataSource = dataSource;
     _dataSource.dataSink = self;
+    _sectionIdentifiersFromContentSuggestions = [[NSMutableSet alloc] init];
   }
   return self;
 }
@@ -234,8 +246,13 @@
 
 - (void)clearSection:(ContentSuggestionsSectionInformation*)sectionInfo {
   SectionIdentifier sectionIdentifier = SectionIdentifierForInfo(sectionInfo);
-  NSInteger section = [self.collectionViewController.collectionViewModel
-      sectionIdentifierForSection:sectionIdentifier];
+  CSCollectionViewModel* model =
+      self.collectionViewController.collectionViewModel;
+
+  if (![model hasSectionForSectionIdentifier:sectionIdentifier])
+    return;
+
+  NSInteger section = [model sectionForSectionIdentifier:sectionIdentifier];
 
   [self.collectionViewController dismissSection:section];
 }
@@ -500,22 +517,58 @@
 
 // Adds the header corresponding to |sectionInfo| to the section if there is
 // none present and the section info contains a title.
+// In addition to that, if the section is for a content suggestion, only show a
+// title if there are more than 1 occurence of a content suggestion section.
 - (void)addHeaderIfNeeded:(ContentSuggestionsSectionInformation*)sectionInfo {
   NSInteger sectionIdentifier = SectionIdentifierForInfo(sectionInfo);
 
-  if (![self.collectionViewController.collectionViewModel
-          headerForSectionWithIdentifier:sectionIdentifier] &&
+  CSCollectionViewModel* model =
+      self.collectionViewController.collectionViewModel;
+
+  if (![model headerForSectionWithIdentifier:sectionIdentifier] &&
       sectionInfo.title) {
-    CollectionViewTextItem* header =
-        [[CollectionViewTextItem alloc] initWithType:ItemTypeHeader];
-    header.text = sectionInfo.title;
-    header.textColor = [[MDCPalette greyPalette] tint500];
-    [self.collectionViewController.collectionViewModel
-                       setHeader:header
-        forSectionWithIdentifier:sectionIdentifier];
+    BOOL addHeader = YES;
+
+    if (IsFromContentSuggestions(sectionIdentifier)) {
+      addHeader = NO;
+
+      if ([self.sectionIdentifiersFromContentSuggestions
+              containsObject:@(sectionIdentifier)]) {
+        return;
+      }
+      if ([self.sectionIdentifiersFromContentSuggestions count] == 1) {
+        NSNumber* existingSectionIdentifier =
+            [self.sectionIdentifiersFromContentSuggestions anyObject];
+        ContentSuggestionsSectionInformation* existingSectionInfo =
+            self.sectionInfoBySectionIdentifier[existingSectionIdentifier];
+        [model setHeader:[self headerForSectionInfo:existingSectionInfo]
+            forSectionWithIdentifier:[existingSectionIdentifier integerValue]];
+        addHeader = YES;
+      } else if ([self.sectionIdentifiersFromContentSuggestions count] > 1) {
+        addHeader = YES;
+      }
+
+      [self.sectionIdentifiersFromContentSuggestions
+          addObject:@(sectionIdentifier)];
+    }
+
+    if (addHeader) {
+      [model setHeader:[self headerForSectionInfo:sectionInfo]
+          forSectionWithIdentifier:sectionIdentifier];
+    }
   }
 }
 
+// Returns the header for this |sectionInfo|.
+- (CollectionViewItem*)headerForSectionInfo:
+    (ContentSuggestionsSectionInformation*)sectionInfo {
+  CollectionViewTextItem* header =
+      [[CollectionViewTextItem alloc] initWithType:ItemTypeHeader];
+  header.text = sectionInfo.title;
+  header.textColor = [[MDCPalette greyPalette] tint500];
+  return header;
+}
+
 // Adds the header for the first section, containing the logo and the omnibox,
 // if there is no header for the section.
 - (void)addLogoHeaderIfNeeded {
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_commands.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_commands.h
index 91d8934..f7f1210 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_commands.h
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_commands.h
@@ -18,10 +18,12 @@
 // Opens the Most Visited associated with this |item| at the |mostVisitedItem|.
 - (void)openMostVisitedItem:(nonnull CollectionViewItem*)item
                     atIndex:(NSInteger)mostVisitedIndex;
-// Displays a context menu for the |articleItem|.
-- (void)displayContextMenuForArticle:(nonnull CollectionViewItem*)articleItem
-                             atPoint:(CGPoint)touchLocation
-                         atIndexPath:(nonnull NSIndexPath*)indexPath;
+// Displays a context menu for the |suggestionItem|.
+- (void)displayContextMenuForSuggestion:
+            (nonnull CollectionViewItem*)suggestionItem
+                                atPoint:(CGPoint)touchLocation
+                            atIndexPath:(nonnull NSIndexPath*)indexPath
+                        readLaterAction:(BOOL)readLaterAction;
 // Displays a context menu for the |mostVisitedItem|.
 - (void)displayContextMenuForMostVisitedItem:
             (nonnull CollectionViewItem*)mostVisitedItem
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.mm
index 84282a0..d07277ac 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.mm
@@ -151,13 +151,14 @@
 
 #pragma mark - ContentSuggestionsHeaderSynchronizing
 
-- (void)updateFakeOmniboxForScrollView:(UIScrollView*)scrollView {
-  // Unfocus the omnibox when the scroll view is scrolled below the pinned
-  // offset.
+- (void)unfocusOmniboxOnCollectionScroll {
+  // Unfocus the omnibox when the scroll view is scrolled.
   if ([self.headerController isOmniboxFocused] && !self.shouldAnimateHeader) {
     [self.headerController unfocusOmnibox];
   }
+}
 
+- (void)updateFakeOmniboxForScrollView:(UIScrollView*)scrollView {
   if (IsIPadIdiom()) {
     return;
   }
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizing.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizing.h
index e2ab334..14e270d6 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizing.h
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizing.h
@@ -11,6 +11,9 @@
 // synchronize with the header, containing the fake omnibox and the logo.
 @protocol ContentSuggestionsHeaderSynchronizing
 
+// Handles the scroll of the collection and unfocus the omnibox if needed.
+- (void)unfocusOmniboxOnCollectionScroll;
+
 // Updates the fake omnibox to adapt to the current scrolling.
 - (void)updateFakeOmniboxForScrollView:(nonnull UIScrollView*)scrollView;
 
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
index 612f98a..958f281 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
@@ -30,7 +30,7 @@
 
 namespace {
 using CSCollectionViewItem = CollectionViewItem<SuggestedContent>;
-const CGFloat kMaxCardWidth = 432;
+const CGFloat kMaxCardWidth = 416;
 
 // Returns whether the cells should be displayed using the full width.
 BOOL ShouldCellsBeFullWidth(UITraitCollection* collection) {
@@ -213,6 +213,7 @@
       ^(id<UIViewControllerTransitionCoordinatorContext> context) {
         [self.headerCommandHandler
             updateFakeOmniboxForScrollView:self.collectionView];
+        [self.collectionView.collectionViewLayout invalidateLayout];
       };
   [coordinator animateAlongsideTransition:alongsideBlock completion:nil];
 }
@@ -423,6 +424,7 @@
   [super scrollViewDidScroll:scrollView];
   [self.audience contentSuggestionsDidScroll];
   [self.overscrollActionsController scrollViewDidScroll:scrollView];
+  [self.headerCommandHandler unfocusOmniboxOnCollectionScroll];
   [self.headerCommandHandler updateFakeOmniboxForScrollView:scrollView];
   self.scrolledToTop =
       scrollView.contentOffset.y >= [self.suggestionsDelegate pinnedOffsetY];
@@ -476,9 +478,17 @@
   switch (type) {
     case ContentSuggestionTypeArticle:
       [self.suggestionCommandHandler
-          displayContextMenuForArticle:touchedItem
-                               atPoint:touchLocation
-                           atIndexPath:touchedItemIndexPath];
+          displayContextMenuForSuggestion:touchedItem
+                                  atPoint:touchLocation
+                              atIndexPath:touchedItemIndexPath
+                          readLaterAction:YES];
+      break;
+    case ContentSuggestionTypeReadingList:
+      [self.suggestionCommandHandler
+          displayContextMenuForSuggestion:touchedItem
+                                  atPoint:touchLocation
+                              atIndexPath:touchedItemIndexPath
+                          readLaterAction:NO];
       break;
     case ContentSuggestionTypeMostVisited:
       [self.suggestionCommandHandler
diff --git a/ios/chrome/browser/ui/settings/privacy_collection_view_controller.mm b/ios/chrome/browser/ui/settings/privacy_collection_view_controller.mm
index 48bc1ca..c85d9c6f 100644
--- a/ios/chrome/browser/ui/settings/privacy_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/privacy_collection_view_controller.mm
@@ -67,6 +67,7 @@
   ItemTypeWebServicesHeader,
   ItemTypeWebServicesFooter,
   ItemTypeWebServicesShowSuggestions,
+  ItemTypeWebServicesShowContentSuggestions,
   ItemTypeWebServicesSendUsageData,
   ItemTypeWebServicesDoNotTrack,
   ItemTypeWebServicesPhysicalWeb,
@@ -79,8 +80,11 @@
                                               PrefObserverDelegate> {
   ios::ChromeBrowserState* _browserState;  // weak
   PrefBackedBoolean* _suggestionsEnabled;
+  PrefBackedBoolean* _contentSuggestionsEnabled;
   // The item related to the switch for the show suggestions setting.
   CollectionViewSwitchItem* _showSuggestionsItem;
+  // The item related to the switch for the show content suggestions setting.
+  CollectionViewSwitchItem* _showContentSuggestionsItem;
 
   // Pref observer to track changes to prefs.
   std::unique_ptr<PrefObserverBridge> _prefObserverBridge;
@@ -96,6 +100,7 @@
 // Initialization methods for various model items.
 - (CollectionViewItem*)handoffDetailItem;
 - (CollectionViewSwitchItem*)showSuggestionsSwitchItem;
+- (CollectionViewSwitchItem*)showContentSuggestionsSwitchItem;
 - (CollectionViewItem*)showSuggestionsFooterItem;
 - (CollectionViewItem*)clearBrowsingDetailItem;
 - (CollectionViewItem*)sendUsageDetailItem;
@@ -122,6 +127,10 @@
         initWithPrefService:_browserState->GetPrefs()
                    prefName:prefs::kSearchSuggestEnabled];
     [_suggestionsEnabled setObserver:self];
+    _contentSuggestionsEnabled = [[PrefBackedBoolean alloc]
+        initWithPrefService:_browserState->GetPrefs()
+                   prefName:prefs::kContentSuggestionsRemoteEnabled];
+    [_contentSuggestionsEnabled setObserver:self];
 
     PrefService* prefService = _browserState->GetPrefs();
 
@@ -147,6 +156,7 @@
 
 - (void)dealloc {
   [_suggestionsEnabled setObserver:nil];
+  [_contentSuggestionsEnabled setObserver:nil];
 }
 
 #pragma mark - SettingsRootCollectionViewController
@@ -181,6 +191,12 @@
   [model addItem:_showSuggestionsItem
       toSectionWithIdentifier:SectionIdentifierWebServices];
 
+  if (experimental_flags::IsSuggestionsUIEnabled()) {
+    _showContentSuggestionsItem = [self showContentSuggestionsSwitchItem];
+    [model addItem:_showContentSuggestionsItem
+        toSectionWithIdentifier:SectionIdentifierWebServices];
+  }
+
   [model addItem:[self sendUsageDetailItem]
       toSectionWithIdentifier:SectionIdentifierWebServices];
 
@@ -231,6 +247,17 @@
   return showSuggestionsSwitchItem;
 }
 
+- (CollectionViewSwitchItem*)showContentSuggestionsSwitchItem {
+  CollectionViewSwitchItem* showContentSuggestionsSwitchItem =
+      [[CollectionViewSwitchItem alloc]
+          initWithType:ItemTypeWebServicesShowContentSuggestions];
+  showContentSuggestionsSwitchItem.text =
+      l10n_util::GetNSString(IDS_IOS_OPTIONS_CONTENT_SUGGESTIONS);
+  showContentSuggestionsSwitchItem.on = [_contentSuggestionsEnabled value];
+
+  return showContentSuggestionsSwitchItem;
+}
+
 - (CollectionViewItem*)showSuggestionsFooterItem {
   CollectionViewFooterItem* showSuggestionsFooterItem =
       [[CollectionViewFooterItem alloc] initWithType:ItemTypeWebServicesFooter];
@@ -314,6 +341,12 @@
     [switchCell.switchView addTarget:self
                               action:@selector(showSuggestionsToggled:)
                     forControlEvents:UIControlEventValueChanged];
+  } else if (itemType == ItemTypeWebServicesShowContentSuggestions) {
+    CollectionViewSwitchCell* switchCell =
+        base::mac::ObjCCastStrict<CollectionViewSwitchCell>(cell);
+    [switchCell.switchView addTarget:self
+                              action:@selector(showContentSuggestionsToggled:)
+                    forControlEvents:UIControlEventValueChanged];
   }
 
   return cell;
@@ -416,13 +449,21 @@
 #pragma mark - BooleanObserver
 
 - (void)booleanDidChange:(id<ObservableBoolean>)observableBoolean {
-  DCHECK_EQ(observableBoolean, _suggestionsEnabled);
+  if (observableBoolean == _suggestionsEnabled) {
+    // Update the item.
+    _showSuggestionsItem.on = [_suggestionsEnabled value];
 
-  // Update the item.
-  _showSuggestionsItem.on = [_suggestionsEnabled value];
+    // Update the cell.
+    [self reconfigureCellsForItems:@[ _showSuggestionsItem ]];
+  } else if (observableBoolean == _contentSuggestionsEnabled) {
+    // Update the item.
+    _showContentSuggestionsItem.on = [_contentSuggestionsEnabled value];
 
-  // Update the cell.
-  [self reconfigureCellsForItems:@[ _showSuggestionsItem ]];
+    // Update the cell.
+    [self reconfigureCellsForItems:@[ _showContentSuggestionsItem ]];
+  } else {
+    NOTREACHED();
+  }
 }
 
 #pragma mark - Actions
@@ -445,6 +486,24 @@
   [_suggestionsEnabled setValue:isOn];
 }
 
+- (void)showContentSuggestionsToggled:(UISwitch*)sender {
+  NSIndexPath* switchPath = [self.collectionViewModel
+      indexPathForItemType:ItemTypeWebServicesShowContentSuggestions
+         sectionIdentifier:SectionIdentifierWebServices];
+
+  CollectionViewSwitchItem* switchItem =
+      base::mac::ObjCCastStrict<CollectionViewSwitchItem>(
+          [self.collectionViewModel itemAtIndexPath:switchPath]);
+  CollectionViewSwitchCell* switchCell =
+      base::mac::ObjCCastStrict<CollectionViewSwitchCell>(
+          [self.collectionView cellForItemAtIndexPath:switchPath]);
+
+  DCHECK_EQ(switchCell.switchView, sender);
+  BOOL isOn = switchCell.switchView.isOn;
+  switchItem.on = isOn;
+  [_contentSuggestionsEnabled setValue:isOn];
+}
+
 #pragma mark - PrefObserverDelegate
 
 - (void)onPreferenceChanged:(const std::string&)preferenceName {
diff --git a/ios/showcase/content_suggestions/sc_content_suggestions_egtest.mm b/ios/showcase/content_suggestions/sc_content_suggestions_egtest.mm
index 46e2d75..29678d7 100644
--- a/ios/showcase/content_suggestions/sc_content_suggestions_egtest.mm
+++ b/ios/showcase/content_suggestions/sc_content_suggestions_egtest.mm
@@ -133,9 +133,10 @@
       performAction:grey_longPress()];
 
   [[EarlGrey
-      selectElementWithMatcher:grey_allOf(TextBeginsWith(
-                                              @"displayContextMenuForArticle:"),
-                                          grey_sufficientlyVisible(), nil)]
+      selectElementWithMatcher:grey_allOf(
+                                   TextBeginsWith(
+                                       @"displayContextMenuForSuggestion:"),
+                                   grey_sufficientlyVisible(), nil)]
       assertWithMatcher:grey_sufficientlyVisible()];
   [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(
                                           @"protocol_alerter_done")]
diff --git a/media/BUILD.gn b/media/BUILD.gn
index bc34533..fc92bb29 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -498,6 +498,10 @@
     ":media_config",
     ":media_implementation",
   ]
+  if (!is_debug) {
+    configs -= [ "//build/config/compiler:default_optimization" ]
+    configs += [ "//build/config/compiler:optimize_max" ]
+  }
   deps = [
     "//base",
     "//ui/gfx/geometry",
diff --git a/media/test/run_all_unittests.cc b/media/test/run_all_unittests.cc
index 57d384c6..437d26d4 100644
--- a/media/test/run_all_unittests.cc
+++ b/media/test/run_all_unittests.cc
@@ -17,7 +17,6 @@
 #include "base/android/jni_android.h"
 #include "media/base/android/media_codec_util.h"
 #include "media/base/android/media_jni_registrar.h"
-#include "ui/gl/android/gl_jni_registrar.h"
 #endif
 
 class TestSuiteNoAtExit : public base::TestSuite {
@@ -42,8 +41,6 @@
 #if defined(OS_ANDROID)
   // Register JNI bindings for android.
   JNIEnv* env = base::android::AttachCurrentThread();
-  // Needed for surface texture support.
-  ui::gl::android::RegisterJni(env);
 
   media::RegisterJni(env);
 
diff --git a/net/nqe/network_quality_estimator.cc b/net/nqe/network_quality_estimator.cc
index 0b9da149..e0b0f94 100644
--- a/net/nqe/network_quality_estimator.cc
+++ b/net/nqe/network_quality_estimator.cc
@@ -1454,8 +1454,7 @@
       case NetworkChangeNotifier::ConnectionType::CONNECTION_ETHERNET:
         break;
       case NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI:
-#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
-    defined(OS_WIN)
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_WIN)
         network_id.id = GetWifiSSID();
 #endif
         break;
diff --git a/remoting/client/jni/remoting_jni_onload.cc b/remoting/client/jni/remoting_jni_onload.cc
index 05be338..49d2c76a 100644
--- a/remoting/client/jni/remoting_jni_onload.cc
+++ b/remoting/client/jni/remoting_jni_onload.cc
@@ -11,12 +11,10 @@
 #include "net/android/net_jni_registrar.h"
 #include "remoting/client/jni/remoting_jni_registrar.h"
 #include "remoting/client/remoting_jni_registration.h"
-#include "ui/gfx/android/gfx_jni_registrar.h"
 
 namespace {
 
 base::android::RegistrationMethod kRemotingRegisteredMethods[] = {
-  {"gfx", gfx::android::RegisterJni},
   {"net", net::android::RegisterJni},
   {"remoting", remoting::RegisterJni},
 };
diff --git a/skia/BUILD.gn b/skia/BUILD.gn
index 7b75a07..33b4d7e8 100644
--- a/skia/BUILD.gn
+++ b/skia/BUILD.gn
@@ -34,6 +34,7 @@
     "//third_party/skia/include/core",
     "//third_party/skia/include/effects",
     "//third_party/skia/include/encode",
+    "//third_party/skia/include/gpu",
     "//third_party/skia/include/images",
     "//third_party/skia/include/lazy",
     "//third_party/skia/include/pathops",
@@ -63,7 +64,6 @@
 
   if (skia_support_gpu) {
     include_dirs += [
-      "//third_party/skia/include/gpu",
       "//third_party/skia/src/gpu",
       "//third_party/skia/src/sksl",
     ]
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 136216aa..c9ec6dd 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -10638,6 +10638,23 @@
       }
     ]
   },
+  "Fuchsia Compile": {
+    "additional_compile_targets": [
+      "base_unittests",
+      "crypto_unittests",
+      "gl_unittests",
+      "ipc_tests",
+      "media_unittests",
+      "mojo_common_unittests",
+      "mojo_js_unittests",
+      "mojo_public_bindings_unittests",
+      "mojo_public_system_unittests",
+      "mojo_system_unittests",
+      "net_unittests",
+      "skia_unittests",
+      "ui_base_unittests"
+    ]
+  },
   "Headless Linux (dbg)": {
     "additional_compile_targets": [
       "headless_lib",
diff --git a/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter b/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter
index 6e2ebd7..2a81cd7 100644
--- a/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter
@@ -86,9 +86,7 @@
 -NavigationHandleImplBrowserTest.ErrorCodeOnRedirect
 -NavigationHandleImplBrowserTest.RedirectToRendererDebugUrl
 -ParallelDownloadTest.ParallelDownloadComplete
--PaymentAppBrowserTest.PaymentAppInvocation
--PaymentAppBrowserTest.PaymentAppInvocationAndFailed
--PaymentAppBrowserTest.PaymentAppOpenWindowFailed
+-PaymentAppBrowserTest.*
 -PlzNavigateNavigationHandleImplBrowserTest.ErrorPageNetworkError
 -PowerMonitorTest.TestGpuProcess
 -PowerMonitorTest.TestRendererProcess
diff --git a/third_party/WebKit/LayoutTests/css3/calc/number-parsing.html b/third_party/WebKit/LayoutTests/css3/calc/number-parsing.html
index da0e324..fdb73ec 100644
--- a/third_party/WebKit/LayoutTests/css3/calc/number-parsing.html
+++ b/third_party/WebKit/LayoutTests/css3/calc/number-parsing.html
@@ -19,7 +19,7 @@
   assertParsedValue('transition-timing-function', 'steps(calc(1 + 2), start)', 'steps(3, start)');
   assertParsedValue('grid-row-start', 'calc(1 + 2) test', '3 test');
   assertParsedValue('grid-row-start', 'calc(1 / 2) test', '');
-  assertParsedValue('font-weight', 'calc(100 + 200)', '');
+  assertParsedValue('font-weight', 'calc(100 + 200)', '300');
   assertParsedValue('flex', 'calc(1 + 2) calc(3 + 4)', '3 7 0%');
   assertParsedValue('-webkit-filter', 'saturate(calc(4 / 2))', 'saturate(2)');
   assertParsedValue('-webkit-filter', 'invert(calc(4 / 2))', 'invert(1)');
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css-fonts/variations/font-parse-numeric-stretch-style-weight.html b/third_party/WebKit/LayoutTests/external/wpt/css-fonts/variations/font-parse-numeric-stretch-style-weight.html
index 9836e38..e4ca2d39 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css-fonts/variations/font-parse-numeric-stretch-style-weight.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css-fonts/variations/font-parse-numeric-stretch-style-weight.html
@@ -18,6 +18,8 @@
     '900',
     '850',
     '850.3',
+    'calc(100 + 300)',
+    'calc(0.2 + 205.5)',
   ],
   'stretch': ['51%', '199%', 'calc(10% + 20%)']
 };
@@ -55,7 +57,8 @@
 var faceTests = {
   'weight': [
     ['100', '100'], ['700', '700'], ['900', '900'], ['bold', 'bold'],
-    ['normal', 'normal']
+    ['normal', 'normal'], ['100 400', '100 400'], ['100 101.5', '100 101.5'],
+    ['999.8 999.9', '999.8 999.9']
   ],
   'stretch': [
     ['100%', '100%'],
@@ -68,6 +71,10 @@
 
 var faceInvalidTests = {
   'weight': [
+    '-100 200',
+    '100 -200',
+    '500 400',
+    '100 1001',
     '1001',
     '1000.5',
     '100 200 300',
diff --git a/third_party/WebKit/LayoutTests/fast/workers/resources/dedicated-worker-lifecycle.js b/third_party/WebKit/LayoutTests/fast/workers/resources/dedicated-worker-lifecycle.js
index 956dd8d..a04de67 100644
--- a/third_party/WebKit/LayoutTests/fast/workers/resources/dedicated-worker-lifecycle.js
+++ b/third_party/WebKit/LayoutTests/fast/workers/resources/dedicated-worker-lifecycle.js
@@ -25,9 +25,8 @@
 
         // Orphan our worker (no more references to it) and wait for it to exit.
         worker.onmessage = 0;
+        worker.terminate();
         worker = 0;
-        // Allocating a Date object seems to scramble the stack and force the worker object to get GC'd.
-        new Date();
         waitUntilWorkerThreadsExit(orphanedWorkerExited);
     }
 }
@@ -51,10 +50,8 @@
 
         // Orphan our worker (no more references to it) and wait for it to exit.
         worker.onmessage = 0;
+        worker.terminate();
         worker = 0;
-        // For some reason, the worker object does not get GC'd unless we allocate a new object here.
-        // The conjecture is that there's a value on the stack that appears to point to the worker which this clobbers.
-        new Date();
         waitUntilWorkerThreadsExit(orphanedTimeoutWorkerExited);
     }
 }
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-css-resources-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-css-resources-expected.txt
index 46f7b82..523fd49 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-css-resources-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-css-resources-expected.txt
@@ -1,4 +1,3 @@
 CONSOLE WARNING: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-css-resources.html' was loaded over HTTPS, but requested an insecure font 'http://example.test:8080/css/resources/cors-ahem.php'. This content should also be served over HTTPS.
 CONSOLE WARNING: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-css-resources.html' was loaded over HTTPS, but requested an insecure image 'http://example.test:8080/resources/square20.png'. This content should also be served over HTTPS.
-CONSOLE WARNING: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-css-resources.html' was loaded over HTTPS, but requested an insecure font 'http://example.test:8080/css/resources/cors-ahem.php'. This content should also be served over HTTPS.
 This test opens a window that loads a style sheet which fetches an insecure background image and an insecure web font. We should trigger a mixed content callback because the main frame in the window is HTTPS but is running insecure content.
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-font-in-main-frame-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-font-in-main-frame-expected.txt
index 026fe68..649aa95 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-font-in-main-frame-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-font-in-main-frame-expected.txt
@@ -1,3 +1,2 @@
 CONSOLE WARNING: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-font.html' was loaded over HTTPS, but requested an insecure font 'http://example.test:8080/css/resources/cors-ahem.php'. This content should also be served over HTTPS.
-CONSOLE WARNING: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-font.html' was loaded over HTTPS, but requested an insecure font 'http://example.test:8080/css/resources/cors-ahem.php'. This content should also be served over HTTPS.
 This test opens a window that loads an insecure font. We should trigger a mixed content callback because the main frame in the window is HTTPS but is displaying insecure content.
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn
index 3d6ac574..445ccde 100644
--- a/third_party/WebKit/Source/core/BUILD.gn
+++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -486,6 +486,8 @@
     "$blink_core_output_dir/css/properties/CSSPropertyAPIAutoOrString.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIBackgroundAttachment.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIBackgroundBlendMode.h",
+    "$blink_core_output_dir/css/properties/CSSPropertyAPIBackgroundBox.h",
+    "$blink_core_output_dir/css/properties/CSSPropertyAPIBackgroundOrMaskImage.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIBaselineShift.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIBorderColor.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIBorderImageOutset.h",
@@ -511,6 +513,8 @@
     "$blink_core_output_dir/css/properties/CSSPropertyAPICounterReset.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPICursor.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPID.h",
+    "$blink_core_output_dir/css/properties/CSSPropertyAPIDelay.h",
+    "$blink_core_output_dir/css/properties/CSSPropertyAPIDuration.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIFilter.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIFlexBasis.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIFlexGrowOrShrink.h",
@@ -527,6 +531,7 @@
     "$blink_core_output_dir/css/properties/CSSPropertyAPIFragmentation.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIGridAutoFlow.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIGridAutoLine.h",
+    "$blink_core_output_dir/css/properties/CSSPropertyAPIGridGap.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIGridLine.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIGridTemplateAreas.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIGridTemplateLine.h",
@@ -579,6 +584,7 @@
     "$blink_core_output_dir/css/properties/CSSPropertyAPITextShadow.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPITextSizeAdjust.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPITextUnderlinePosition.h",
+    "$blink_core_output_dir/css/properties/CSSPropertyAPITimingFunction.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPITouchAction.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPITransform.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPITransformOrigin.h",
@@ -1589,6 +1595,7 @@
     "scheduler/ActiveConnectionThrottlingTest.cpp",
     "scheduler/FrameThrottlingTest.cpp",
     "scheduler/ThrottlingTest.cpp",
+    "scheduler/VirtualTimeTest.cpp",
     "streams/ReadableStreamOperationsTest.cpp",
     "style/BorderValueTest.cpp",
     "style/ComputedStyleTest.cpp",
diff --git a/third_party/WebKit/Source/core/css/BUILD.gn b/third_party/WebKit/Source/core/css/BUILD.gn
index 1b9a0e4..850f2460 100644
--- a/third_party/WebKit/Source/core/css/BUILD.gn
+++ b/third_party/WebKit/Source/core/css/BUILD.gn
@@ -383,6 +383,8 @@
     "properties/CSSPropertyAPIAutoOrString.cpp",
     "properties/CSSPropertyAPIBackgroundAttachment.cpp",
     "properties/CSSPropertyAPIBackgroundBlendMode.cpp",
+    "properties/CSSPropertyAPIBackgroundBox.cpp",
+    "properties/CSSPropertyAPIBackgroundOrMaskImage.cpp",
     "properties/CSSPropertyAPIBaselineShift.cpp",
     "properties/CSSPropertyAPIBorderColor.cpp",
     "properties/CSSPropertyAPIBorderImageOutset.cpp",
@@ -408,6 +410,8 @@
     "properties/CSSPropertyAPICounterReset.cpp",
     "properties/CSSPropertyAPICursor.cpp",
     "properties/CSSPropertyAPID.cpp",
+    "properties/CSSPropertyAPIDelay.cpp",
+    "properties/CSSPropertyAPIDuration.cpp",
     "properties/CSSPropertyAPIFilter.cpp",
     "properties/CSSPropertyAPIFlexBasis.cpp",
     "properties/CSSPropertyAPIFlexGrowOrShrink.cpp",
@@ -425,6 +429,7 @@
     "properties/CSSPropertyAPIFragmentation.cpp",
     "properties/CSSPropertyAPIGridAutoFlow.cpp",
     "properties/CSSPropertyAPIGridAutoLine.cpp",
+    "properties/CSSPropertyAPIGridGap.cpp",
     "properties/CSSPropertyAPIGridLine.cpp",
     "properties/CSSPropertyAPIGridTemplateAreas.cpp",
     "properties/CSSPropertyAPIGridTemplateLine.cpp",
@@ -477,6 +482,7 @@
     "properties/CSSPropertyAPITextShadow.cpp",
     "properties/CSSPropertyAPITextSizeAdjust.cpp",
     "properties/CSSPropertyAPITextUnderlinePosition.cpp",
+    "properties/CSSPropertyAPITimingFunction.cpp",
     "properties/CSSPropertyAPITouchAction.cpp",
     "properties/CSSPropertyAPITransform.cpp",
     "properties/CSSPropertyAPITransformOrigin.cpp",
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.json5 b/third_party/WebKit/Source/core/css/CSSProperties.json5
index e4caa11f..02aa490 100644
--- a/third_party/WebKit/Source/core/css/CSSProperties.json5
+++ b/third_party/WebKit/Source/core/css/CSSProperties.json5
@@ -319,6 +319,8 @@
     // Animation Priority properties
     {
       name: "animation-delay",
+      api_class: "CSSPropertyAPIDelay",
+      api_methods: ["parseSingleValue"],
       custom_all: true,
       priority: "Animation",
     },
@@ -333,6 +335,8 @@
     },
     {
       name: "animation-duration",
+      api_class: "CSSPropertyAPIDuration",
+      api_methods: ["parseSingleValue"],
       custom_all: true,
       priority: "Animation",
     },
@@ -368,16 +372,22 @@
     },
     {
       name: "animation-timing-function",
+      api_class: "CSSPropertyAPITimingFunction",
+      api_methods: ["parseSingleValue"],
       custom_all: true,
       priority: "Animation",
     },
     {
       name: "transition-delay",
+      api_class: "CSSPropertyAPIDelay",
+      api_methods: ["parseSingleValue"],
       custom_all: true,
       priority: "Animation",
     },
     {
       name: "transition-duration",
+      api_class: "CSSPropertyAPIDuration",
+      api_methods: ["parseSingleValue"],
       custom_all: true,
       priority: "Animation",
     },
@@ -390,6 +400,8 @@
     },
     {
       name: "transition-timing-function",
+      api_class: "CSSPropertyAPITimingFunction",
+      api_methods: ["parseSingleValue"],
       custom_all: true,
       priority: "Animation",
     },
@@ -698,6 +710,8 @@
     },
     {
       name: "background-clip",
+      api_class: "CSSPropertyAPIBackgroundBox",
+      api_methods: ["parseSingleValue"],
       custom_all: true,
     },
     {
@@ -715,6 +729,8 @@
     },
     {
       name: "background-image",
+      api_class: "CSSPropertyAPIBackgroundOrMaskImage",
+      api_methods: ["parseSingleValue"],
       custom_all: true,
       interpolable: true,
       keywords: ["auto", "none"],
@@ -722,6 +738,8 @@
     },
     {
       name: "background-origin",
+      api_class: "CSSPropertyAPIBackgroundBox",
+      api_methods: ["parseSingleValue"],
       custom_all: true,
     },
     {
@@ -826,17 +844,20 @@
     {
       name: "border-image-outset",
       api_class: "CSSPropertyAPIBorderImageOutset",
+      api_methods: ["parseSingleValue"],
       custom_all: true,
       interpolable: true,
     },
     {
       name: "border-image-repeat",
       api_class: "CSSPropertyAPIBorderImageRepeat",
+      api_methods: ["parseSingleValue"],
       custom_all: true,
     },
     {
       name: "border-image-slice",
       api_class: "CSSPropertyAPIBorderImageSlice",
+      api_methods: ["parseSingleValue"],
       custom_all: true,
       interpolable: true,
     },
@@ -852,6 +873,7 @@
     {
       name: "border-image-width",
       api_class: "CSSPropertyAPIBorderImageWidth",
+      api_methods: ["parseSingleValue"],
       custom_all: true,
       interpolable: true,
     },
@@ -1390,6 +1412,8 @@
     },
     {
       name: "grid-column-gap",
+      api_class: "CSSPropertyAPIGridGap",
+      api_methods: ["parseSingleValue"],
       converter: "ConvertLength",
       runtime_flag: "CSSGridLayout",
       field_template: "<length>",
@@ -1420,6 +1444,8 @@
     },
     {
       name: "grid-row-gap",
+      api_class: "CSSPropertyAPIGridGap",
+      api_methods: ["parseSingleValue"],
       converter: "ConvertLength",
       runtime_flag: "CSSGridLayout",
       field_template: "<length>",
@@ -3136,17 +3162,20 @@
     {
       name: "-webkit-mask-box-image-outset",
       api_class: "CSSPropertyAPIBorderImageOutset",
+      api_methods: ["parseSingleValue"],
       custom_all: true,
       interpolable: true,
     },
     {
       name: "-webkit-mask-box-image-repeat",
       api_class: "CSSPropertyAPIBorderImageRepeat",
+      api_methods: ["parseSingleValue"],
       custom_all: true,
     },
     {
       name: "-webkit-mask-box-image-slice",
       api_class: "CSSPropertyAPIBorderImageSlice",
+      api_methods: ["parseSingleValue"],
       custom_all: true,
       interpolable: true,
     },
@@ -3160,6 +3189,7 @@
     {
       name: "-webkit-mask-box-image-width",
       api_class: "CSSPropertyAPIBorderImageWidth",
+      api_methods: ["parseSingleValue"],
       custom_all: true,
       interpolable: true,
     },
@@ -3175,6 +3205,8 @@
     },
     {
       name: "-webkit-mask-image",
+      api_class: "CSSPropertyAPIBackgroundOrMaskImage",
+      api_methods: ["parseSingleValue"],
       custom_all: true,
       interpolable: true,
     },
@@ -3210,12 +3242,14 @@
     {
       name: "-webkit-perspective-origin-x",
       api_class: "CSSPropertyAPIWebkitOriginX",
+      api_methods: ["parseSingleValue"],
       converter: "ConvertLength",
       interpolable: true,
     },
     {
       name: "-webkit-perspective-origin-y",
       api_class: "CSSPropertyAPIWebkitOriginY",
+      api_methods: ["parseSingleValue"],
       converter: "ConvertLength",
       interpolable: true,
     },
@@ -3339,12 +3373,14 @@
     {
       name: "-webkit-transform-origin-x",
       api_class: "CSSPropertyAPIWebkitOriginX",
+      api_methods: ["parseSingleValue"],
       converter: "ConvertLength",
       interpolable: true,
     },
     {
       name: "-webkit-transform-origin-y",
       api_class: "CSSPropertyAPIWebkitOriginY",
+      api_methods: ["parseSingleValue"],
       converter: "ConvertLength",
       interpolable: true,
     },
diff --git a/third_party/WebKit/Source/core/css/StyleSheetList.cpp b/third_party/WebKit/Source/core/css/StyleSheetList.cpp
index b1ed63c3..1f8f409fb 100644
--- a/third_party/WebKit/Source/core/css/StyleSheetList.cpp
+++ b/third_party/WebKit/Source/core/css/StyleSheetList.cpp
@@ -68,7 +68,12 @@
   HTMLStyleElement* item = GetNamedItem(name);
   if (!item)
     return nullptr;
-  return item->sheet();
+  CSSStyleSheet* sheet = item->sheet();
+  if (sheet) {
+    UseCounter::Count(*GetDocument(),
+                      WebFeature::kStyleSheetListNonNullAnonymousNamedGetter);
+  }
+  return sheet;
 }
 
 DEFINE_TRACE(StyleSheetList) {
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
index 7d55803b..1bdd8c9 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -304,11 +304,6 @@
   return nullptr;
 }
 
-static CSSValue* ConsumeBackgroundBox(CSSParserTokenRange& range) {
-  return ConsumeIdent<CSSValueBorderBox, CSSValuePaddingBox,
-                      CSSValueContentBox>(range);
-}
-
 static CSSValue* ConsumePrefixedBackgroundBox(CSSParserTokenRange& range,
                                               const CSSParserContext* context,
                                               bool allow_text_value) {
@@ -356,13 +351,13 @@
                                             const CSSParserContext* context) {
   switch (unresolved_property) {
     case CSSPropertyBackgroundClip:
-      return ConsumeBackgroundBox(range);
+      return CSSPropertyBackgroundUtils::ConsumeBackgroundBox(range);
     case CSSPropertyBackgroundBlendMode:
       return CSSPropertyBackgroundUtils::ConsumeBackgroundBlendMode(range);
     case CSSPropertyBackgroundAttachment:
       return CSSPropertyBackgroundUtils::ConsumeBackgroundAttachment(range);
     case CSSPropertyBackgroundOrigin:
-      return ConsumeBackgroundBox(range);
+      return CSSPropertyBackgroundUtils::ConsumeBackgroundBox(range);
     case CSSPropertyWebkitMaskComposite:
       return CSSPropertyBackgroundUtils::ConsumeBackgroundComposite(range);
     case CSSPropertyMaskSourceType:
@@ -672,55 +667,10 @@
     case CSSPropertyWebkitLogicalWidth:
     case CSSPropertyWebkitLogicalHeight:
       return CSSPropertyLengthUtils::ConsumeWidthOrHeight(range_, *context_);
-    case CSSPropertyAnimationDelay:
-    case CSSPropertyTransitionDelay:
-      return ConsumeCommaSeparatedList(ConsumeTime, range_, kValueRangeAll);
-    case CSSPropertyAnimationDuration:
-    case CSSPropertyTransitionDuration:
-      return ConsumeCommaSeparatedList(ConsumeTime, range_,
-                                       kValueRangeNonNegative);
-    case CSSPropertyAnimationTimingFunction:
-    case CSSPropertyTransitionTimingFunction:
-      return ConsumeCommaSeparatedList(CSSPropertyAnimationTimingFunctionUtils::
-                                           ConsumeAnimationTimingFunction,
-                                       range_);
-    case CSSPropertyGridColumnGap:
-    case CSSPropertyGridRowGap:
-      return ConsumeLengthOrPercent(range_, context_->Mode(),
-                                    kValueRangeNonNegative);
     case CSSPropertyTextDecoration:
       DCHECK(!RuntimeEnabledFeatures::CSS3TextDecorationsEnabled());
       return CSSPropertyTextDecorationLineUtils::ConsumeTextDecorationLine(
           range_);
-    case CSSPropertyWebkitTransformOriginX:
-    case CSSPropertyWebkitPerspectiveOriginX:
-      return CSSPropertyPositionUtils::ConsumePositionLonghand<CSSValueLeft,
-                                                               CSSValueRight>(
-          range_, context_->Mode());
-    case CSSPropertyWebkitTransformOriginY:
-    case CSSPropertyWebkitPerspectiveOriginY:
-      return CSSPropertyPositionUtils::ConsumePositionLonghand<CSSValueTop,
-                                                               CSSValueBottom>(
-          range_, context_->Mode());
-    case CSSPropertyBorderImageRepeat:
-    case CSSPropertyWebkitMaskBoxImageRepeat:
-      return CSSPropertyBorderImageUtils::ConsumeBorderImageRepeat(range_);
-    case CSSPropertyBorderImageSlice:
-    case CSSPropertyWebkitMaskBoxImageSlice:
-      return CSSPropertyBorderImageUtils::ConsumeBorderImageSlice(
-          range_, false /* default_fill */);
-    case CSSPropertyBorderImageOutset:
-    case CSSPropertyWebkitMaskBoxImageOutset:
-      return CSSPropertyBorderImageUtils::ConsumeBorderImageOutset(range_);
-    case CSSPropertyBorderImageWidth:
-    case CSSPropertyWebkitMaskBoxImageWidth:
-      return CSSPropertyBorderImageUtils::ConsumeBorderImageWidth(range_);
-    case CSSPropertyBackgroundClip:
-    case CSSPropertyBackgroundOrigin:
-      return ConsumeCommaSeparatedList(ConsumeBackgroundBox, range_);
-    case CSSPropertyBackgroundImage:
-    case CSSPropertyWebkitMaskImage:
-      return ConsumeCommaSeparatedList(ConsumeImageOrNone, range_, context_);
     case CSSPropertyBackgroundPositionX:
     case CSSPropertyWebkitMaskPositionX:
       return ConsumeCommaSeparatedList(
@@ -881,7 +831,8 @@
       parsed_value = ConsumeFontVariantList(range_);
       break;
     case CSSPropertyFontWeight:
-      parsed_value = CSSPropertyFontUtils::ConsumeFontWeight(range_);
+      parsed_value =
+          CSSPropertyFontUtils::ConsumeFontWeight(range_, kCSSFontFaceRuleMode);
       break;
     case CSSPropertyFontFeatureSettings:
       parsed_value = CSSPropertyFontUtils::ConsumeFontFeatureSettings(range_);
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBackgroundBox.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBackgroundBox.cpp
new file mode 100644
index 0000000..6f768fc
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBackgroundBox.cpp
@@ -0,0 +1,20 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/css/properties/CSSPropertyAPIBackgroundBox.h"
+
+#include "core/css/parser/CSSPropertyParserHelpers.h"
+#include "core/css/properties/CSSPropertyBackgroundUtils.h"
+
+namespace blink {
+
+const CSSValue* CSSPropertyAPIBackgroundBox::parseSingleValue(
+    CSSParserTokenRange& range,
+    const CSSParserContext&,
+    const CSSParserLocalContext&) {
+  return CSSPropertyParserHelpers::ConsumeCommaSeparatedList(
+      CSSPropertyBackgroundUtils::ConsumeBackgroundBox, range);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBackgroundOrMaskImage.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBackgroundOrMaskImage.cpp
new file mode 100644
index 0000000..fc421a0
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBackgroundOrMaskImage.cpp
@@ -0,0 +1,19 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/css/properties/CSSPropertyAPIBackgroundOrMaskImage.h"
+
+#include "core/css/parser/CSSPropertyParserHelpers.h"
+
+namespace blink {
+
+const CSSValue* CSSPropertyAPIBackgroundOrMaskImage::parseSingleValue(
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    const CSSParserLocalContext&) {
+  return CSSPropertyParserHelpers::ConsumeCommaSeparatedList(
+      CSSPropertyParserHelpers::ConsumeImageOrNone, range, &context);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageOutset.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageOutset.cpp
index 8836bd0..ec4e37fc 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageOutset.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageOutset.cpp
@@ -4,4 +4,15 @@
 
 #include "core/css/properties/CSSPropertyAPIBorderImageOutset.h"
 
-namespace blink {}  // namespace blink
+#include "core/css/properties/CSSPropertyBorderImageUtils.h"
+
+namespace blink {
+
+const CSSValue* CSSPropertyAPIBorderImageOutset::parseSingleValue(
+    CSSParserTokenRange& range,
+    const CSSParserContext&,
+    const CSSParserLocalContext&) {
+  return CSSPropertyBorderImageUtils::ConsumeBorderImageOutset(range);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageRepeat.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageRepeat.cpp
index e7b74980..ba6846e 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageRepeat.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageRepeat.cpp
@@ -4,4 +4,15 @@
 
 #include "core/css/properties/CSSPropertyAPIBorderImageRepeat.h"
 
-namespace blink {}  // namespace blink
+#include "core/css/properties/CSSPropertyBorderImageUtils.h"
+
+namespace blink {
+
+const CSSValue* CSSPropertyAPIBorderImageRepeat::parseSingleValue(
+    CSSParserTokenRange& range,
+    const CSSParserContext&,
+    const CSSParserLocalContext&) {
+  return CSSPropertyBorderImageUtils::ConsumeBorderImageRepeat(range);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageSlice.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageSlice.cpp
index 6d6a7eb1..13fc7e6b 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageSlice.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageSlice.cpp
@@ -4,4 +4,16 @@
 
 #include "core/css/properties/CSSPropertyAPIBorderImageSlice.h"
 
-namespace blink {}  // namespace blink
+#include "core/css/properties/CSSPropertyBorderImageUtils.h"
+
+namespace blink {
+
+const CSSValue* CSSPropertyAPIBorderImageSlice::parseSingleValue(
+    CSSParserTokenRange& range,
+    const CSSParserContext&,
+    const CSSParserLocalContext&) {
+  return CSSPropertyBorderImageUtils::ConsumeBorderImageSlice(
+      range, DefaultFill::kNoFill);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageWidth.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageWidth.cpp
index bcc64fa..ec6b4782 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageWidth.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderImageWidth.cpp
@@ -4,4 +4,15 @@
 
 #include "core/css/properties/CSSPropertyAPIBorderImageWidth.h"
 
-namespace blink {}  // namespace blink
+#include "core/css/properties/CSSPropertyBorderImageUtils.h"
+
+namespace blink {
+
+const CSSValue* CSSPropertyAPIBorderImageWidth::parseSingleValue(
+    CSSParserTokenRange& range,
+    const CSSParserContext&,
+    const CSSParserLocalContext&) {
+  return CSSPropertyBorderImageUtils::ConsumeBorderImageWidth(range);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIDelay.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIDelay.cpp
new file mode 100644
index 0000000..e0c153a
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIDelay.cpp
@@ -0,0 +1,20 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/css/properties/CSSPropertyAPIDelay.h"
+
+#include "core/css/parser/CSSPropertyParserHelpers.h"
+#include "platform/Length.h"
+
+namespace blink {
+
+const CSSValue* CSSPropertyAPIDelay::parseSingleValue(
+    CSSParserTokenRange& range,
+    const CSSParserContext&,
+    const CSSParserLocalContext&) {
+  return CSSPropertyParserHelpers::ConsumeCommaSeparatedList(
+      CSSPropertyParserHelpers::ConsumeTime, range, kValueRangeAll);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIDuration.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIDuration.cpp
new file mode 100644
index 0000000..c8121ac
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIDuration.cpp
@@ -0,0 +1,20 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/css/properties/CSSPropertyAPIDuration.h"
+
+#include "core/css/parser/CSSPropertyParserHelpers.h"
+#include "platform/Length.h"
+
+namespace blink {
+
+const CSSValue* CSSPropertyAPIDuration::parseSingleValue(
+    CSSParserTokenRange& range,
+    const CSSParserContext&,
+    const CSSParserLocalContext&) {
+  return CSSPropertyParserHelpers::ConsumeCommaSeparatedList(
+      CSSPropertyParserHelpers::ConsumeTime, range, kValueRangeNonNegative);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontWeight.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontWeight.cpp
index 16de6c58..e93ddab 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontWeight.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontWeight.cpp
@@ -4,15 +4,16 @@
 
 #include "core/css/properties/CSSPropertyAPIFontWeight.h"
 
+#include "core/css/parser/CSSParserContext.h"
 #include "core/css/properties/CSSPropertyFontUtils.h"
 
 namespace blink {
 
 const CSSValue* CSSPropertyAPIFontWeight::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext&,
+    const CSSParserContext& context,
     const CSSParserLocalContext&) {
-  return CSSPropertyFontUtils::ConsumeFontWeight(range);
+  return CSSPropertyFontUtils::ConsumeFontWeight(range, context.Mode());
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIGridGap.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIGridGap.cpp
new file mode 100644
index 0000000..81ac4c9
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIGridGap.cpp
@@ -0,0 +1,21 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/css/properties/CSSPropertyAPIGridGap.h"
+
+#include "core/css/parser/CSSParserContext.h"
+#include "core/css/parser/CSSPropertyParserHelpers.h"
+#include "platform/Length.h"
+
+namespace blink {
+
+const CSSValue* CSSPropertyAPIGridGap::parseSingleValue(
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    const CSSParserLocalContext&) {
+  return CSSPropertyParserHelpers::ConsumeLengthOrPercent(
+      range, context.Mode(), kValueRangeNonNegative);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITimingFunction.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITimingFunction.cpp
new file mode 100644
index 0000000..c8e71935
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITimingFunction.cpp
@@ -0,0 +1,21 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/css/properties/CSSPropertyAPITimingFunction.h"
+
+#include "core/css/parser/CSSPropertyParserHelpers.h"
+#include "core/css/properties/CSSPropertyAnimationTimingFunctionUtils.h"
+
+namespace blink {
+
+const CSSValue* CSSPropertyAPITimingFunction::parseSingleValue(
+    CSSParserTokenRange& range,
+    const CSSParserContext&,
+    const CSSParserLocalContext&) {
+  return CSSPropertyParserHelpers::ConsumeCommaSeparatedList(
+      CSSPropertyAnimationTimingFunctionUtils::ConsumeAnimationTimingFunction,
+      range);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitOriginX.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitOriginX.cpp
index 24ecc2c2..be6ce92 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitOriginX.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitOriginX.cpp
@@ -4,4 +4,19 @@
 
 #include "core/css/properties/CSSPropertyAPIWebkitOriginX.h"
 
-namespace blink {}  // namespace blink
+#include "core/CSSValueKeywords.h"
+#include "core/css/parser/CSSParserContext.h"
+#include "core/css/properties/CSSPropertyPositionUtils.h"
+
+namespace blink {
+
+const CSSValue* CSSPropertyAPIWebkitOriginX::parseSingleValue(
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    const CSSParserLocalContext&) {
+  return CSSPropertyPositionUtils::ConsumePositionLonghand<CSSValueLeft,
+                                                           CSSValueRight>(
+      range, context.Mode());
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitOriginY.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitOriginY.cpp
index 08483ce..d080353 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitOriginY.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitOriginY.cpp
@@ -4,4 +4,19 @@
 
 #include "core/css/properties/CSSPropertyAPIWebkitOriginY.h"
 
-namespace blink {}  // namespace blink
+#include "core/CSSValueKeywords.h"
+#include "core/css/parser/CSSParserContext.h"
+#include "core/css/properties/CSSPropertyPositionUtils.h"
+
+namespace blink {
+
+const CSSValue* CSSPropertyAPIWebkitOriginY::parseSingleValue(
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    const CSSParserLocalContext&) {
+  return CSSPropertyPositionUtils::ConsumePositionLonghand<CSSValueTop,
+                                                           CSSValueBottom>(
+      range, context.Mode());
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyBackgroundUtils.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyBackgroundUtils.cpp
index 16bfeeb..b993d52 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyBackgroundUtils.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyBackgroundUtils.cpp
@@ -43,6 +43,12 @@
   return nullptr;
 }
 
+CSSValue* CSSPropertyBackgroundUtils::ConsumeBackgroundBox(
+    CSSParserTokenRange& range) {
+  return CSSPropertyParserHelpers::ConsumeIdent<
+      CSSValueBorderBox, CSSValuePaddingBox, CSSValueContentBox>(range);
+}
+
 CSSValue* CSSPropertyBackgroundUtils::ConsumeBackgroundComposite(
     CSSParserTokenRange& range) {
   return CSSPropertyParserHelpers::ConsumeIdentRange(range, CSSValueClear,
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyBackgroundUtils.h b/third_party/WebKit/Source/core/css/properties/CSSPropertyBackgroundUtils.h
index 6511178..7885bf73c 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyBackgroundUtils.h
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyBackgroundUtils.h
@@ -24,6 +24,7 @@
 
   static CSSValue* ConsumeBackgroundAttachment(CSSParserTokenRange&);
   static CSSValue* ConsumeBackgroundBlendMode(CSSParserTokenRange&);
+  static CSSValue* ConsumeBackgroundBox(CSSParserTokenRange&);
   static CSSValue* ConsumeBackgroundComposite(CSSParserTokenRange&);
   static CSSValue* ConsumeMaskSourceType(CSSParserTokenRange&);
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyBorderImageUtils.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyBorderImageUtils.cpp
index 4905104..98ec279 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyBorderImageUtils.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyBorderImageUtils.cpp
@@ -34,7 +34,7 @@
   CSSValue* outset = nullptr;
   CSSValue* repeat = nullptr;
   if (ConsumeBorderImageComponents(range, context, source, slice, width, outset,
-                                   repeat, true /* default_fill */))
+                                   repeat, DefaultFill::kFill))
     return CreateBorderImageValue(source, slice, width, outset, repeat);
   return nullptr;
 }
@@ -47,7 +47,7 @@
     CSSValue*& width,
     CSSValue*& outset,
     CSSValue*& repeat,
-    bool default_fill) {
+    DefaultFill default_fill) {
   do {
     if (!source) {
       source = CSSPropertyParserHelpers::ConsumeImageOrNone(range, &context);
@@ -99,7 +99,7 @@
 
 CSSValue* CSSPropertyBorderImageUtils::ConsumeBorderImageSlice(
     CSSParserTokenRange& range,
-    bool default_fill) {
+    DefaultFill default_fill) {
   bool fill = CSSPropertyParserHelpers::ConsumeIdent<CSSValueFill>(range);
   CSSValue* slices[4] = {0};
 
@@ -122,7 +122,7 @@
     fill = true;
   }
   CSSPropertyParserHelpers::Complete4Sides(slices);
-  if (default_fill)
+  if (default_fill == DefaultFill::kFill)
     fill = true;
   return CSSBorderImageSliceValue::Create(
       CSSQuadValue::Create(slices[0], slices[1], slices[2], slices[3],
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyBorderImageUtils.h b/third_party/WebKit/Source/core/css/properties/CSSPropertyBorderImageUtils.h
index 20a6182..b00b5ba9 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyBorderImageUtils.h
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyBorderImageUtils.h
@@ -13,6 +13,8 @@
 class CSSParserTokenRange;
 class CSSValue;
 
+enum class DefaultFill { kFill, kNoFill };
+
 class CSSPropertyBorderImageUtils {
   STATIC_ONLY(CSSPropertyBorderImageUtils);
 
@@ -26,10 +28,9 @@
                                            CSSValue*& width,
                                            CSSValue*& outset,
                                            CSSValue*& repeat,
-                                           bool default_fill);
+                                           DefaultFill);
   static CSSValue* ConsumeBorderImageRepeat(CSSParserTokenRange&);
-  static CSSValue* ConsumeBorderImageSlice(CSSParserTokenRange&,
-                                           bool default_fill);
+  static CSSValue* ConsumeBorderImageSlice(CSSParserTokenRange&, DefaultFill);
   static CSSValue* ConsumeBorderImageWidth(CSSParserTokenRange&);
   static CSSValue* ConsumeBorderImageOutset(CSSParserTokenRange&);
 };
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyFontUtils.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyFontUtils.cpp
index 363e598e..1f5d23c 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyFontUtils.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyFontUtils.cpp
@@ -114,6 +114,18 @@
   return nullptr;
 }
 
+static CSSValue* CombineToRangeListOrNull(const CSSPrimitiveValue* range_start,
+                                          const CSSPrimitiveValue* range_end) {
+  DCHECK(range_start);
+  DCHECK(range_end);
+  if (range_end->GetFloatValue() < range_start->GetFloatValue())
+    return nullptr;
+  CSSValueList* value_list = CSSValueList::CreateSpaceSeparated();
+  value_list->Append(*range_start);
+  value_list->Append(*range_end);
+  return value_list;
+}
+
 CSSValue* CSSPropertyFontUtils::ConsumeFontStretch(CSSParserTokenRange& range) {
   CSSIdentifierValue* parsed_keyword = ConsumeFontStretchKeywordOnly(range);
   if (parsed_keyword)
@@ -125,18 +137,44 @@
   return percent;
 }
 
-CSSValue* CSSPropertyFontUtils::ConsumeFontWeight(CSSParserTokenRange& range) {
+CSSValue* CSSPropertyFontUtils::ConsumeFontWeight(
+    CSSParserTokenRange& range,
+    const CSSParserMode& parser_mode) {
   const CSSParserToken& token = range.Peek();
   if (token.Id() >= CSSValueNormal && token.Id() <= CSSValueLighter)
     return CSSPropertyParserHelpers::ConsumeIdent(range);
-  if (token.GetType() != kNumberToken)
+
+  // Avoid consuming the first zero of font: 0/0; e.g. in the Acid3 test.
+  if (token.GetType() == kNumberToken &&
+      (token.NumericValue() < 1 || token.NumericValue() > 1000))
     return nullptr;
-  float weight = token.NumericValue();
-  if (weight < 1 || weight > 1000)
+
+  CSSPrimitiveValue* start_weight = nullptr;
+  start_weight =
+      CSSPropertyParserHelpers::ConsumeNumber(range, kValueRangeNonNegative);
+  if (!start_weight || start_weight->GetFloatValue() < 1 ||
+      start_weight->GetFloatValue() > 1000)
     return nullptr;
-  range.ConsumeIncludingWhitespace();
-  return CSSPrimitiveValue::Create(weight,
-                                   CSSPrimitiveValue::UnitType::kNumber);
+
+  // In a non-font-face context, more than one number is not allowed. Return
+  // what we have. If there is trailing garbage, the AtEnd() check in
+  // CSSPropertyParser::ParseValueStart will catch that.
+  if (parser_mode != kCSSFontFaceRuleMode)
+    return start_weight;
+
+  CSSPrimitiveValue* end_weight = nullptr;
+  if (!range.AtEnd()) {
+    end_weight =
+        CSSPropertyParserHelpers::ConsumeNumber(range, kValueRangeNonNegative);
+    if (!end_weight || end_weight->GetFloatValue() < 1 ||
+        end_weight->GetFloatValue() > 1000)
+      return nullptr;
+  }
+
+  if (end_weight)
+    return CombineToRangeListOrNull(start_weight, end_weight);
+
+  return start_weight;
 }
 
 // TODO(bugsnash): move this to the FontFeatureSettings API when it is no longer
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyFontUtils.h b/third_party/WebKit/Source/core/css/properties/CSSPropertyFontUtils.h
index 1a6985ca..44f98e5 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyFontUtils.h
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyFontUtils.h
@@ -37,7 +37,8 @@
       CSSParserTokenRange&);
   static CSSValue* ConsumeFontStretch(CSSParserTokenRange&);
   static CSSValue* ConsumeFontStyle(CSSParserTokenRange&);
-  static CSSValue* ConsumeFontWeight(CSSParserTokenRange&);
+  static CSSValue* ConsumeFontWeight(CSSParserTokenRange&,
+                                     const CSSParserMode&);
 
   static CSSValue* ConsumeFontFeatureSettings(CSSParserTokenRange&);
   static CSSFontFeatureValue* ConsumeFontFeatureTag(CSSParserTokenRange&);
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyPositionUtils.h b/third_party/WebKit/Source/core/css/properties/CSSPropertyPositionUtils.h
index d3e3cb6..4cf4137 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyPositionUtils.h
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyPositionUtils.h
@@ -6,6 +6,8 @@
 
 #include "core/CSSValueKeywords.h"
 #include "core/css/parser/CSSParserMode.h"
+#include "core/css/parser/CSSParserTokenRange.h"
+#include "core/css/parser/CSSPropertyParserHelpers.h"
 
 #include "platform/wtf/Allocator.h"
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderImage.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderImage.cpp
index b17bf4f..32c44f6 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderImage.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderImage.cpp
@@ -24,7 +24,8 @@
   CSSValue* repeat = nullptr;
 
   if (!CSSPropertyBorderImageUtils::ConsumeBorderImageComponents(
-          range, context, source, slice, width, outset, repeat, false)) {
+          range, context, source, slice, width, outset, repeat,
+          DefaultFill::kNoFill)) {
     return false;
   }
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIFont.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIFont.cpp
index 4a4d872..efb14a9 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIFont.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIFont.cpp
@@ -115,7 +115,8 @@
         continue;
     }
     if (!font_weight) {
-      font_weight = CSSPropertyFontUtils::ConsumeFontWeight(range);
+      font_weight =
+          CSSPropertyFontUtils::ConsumeFontWeight(range, context.Mode());
       if (font_weight)
         continue;
     }
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitMaskBoxImage.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitMaskBoxImage.cpp
index b4f49c9..031deba 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitMaskBoxImage.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitMaskBoxImage.cpp
@@ -24,7 +24,8 @@
   CSSValue* repeat = nullptr;
 
   if (!CSSPropertyBorderImageUtils::ConsumeBorderImageComponents(
-          range, context, source, slice, width, outset, repeat, true)) {
+          range, context, source, slice, width, outset, repeat,
+          DefaultFill::kFill)) {
     return false;
   }
 
diff --git a/third_party/WebKit/Source/core/frame/DOMTimerCoordinator.cpp b/third_party/WebKit/Source/core/frame/DOMTimerCoordinator.cpp
index 59b3511..6f9acdd 100644
--- a/third_party/WebKit/Source/core/frame/DOMTimerCoordinator.cpp
+++ b/third_party/WebKit/Source/core/frame/DOMTimerCoordinator.cpp
@@ -40,10 +40,6 @@
   return removed_timer;
 }
 
-bool DOMTimerCoordinator::HasInstalledTimeout() const {
-  return !timers_.IsEmpty();
-}
-
 DEFINE_TRACE(DOMTimerCoordinator) {
   visitor->Trace(timers_);
 }
diff --git a/third_party/WebKit/Source/core/frame/DOMTimerCoordinator.h b/third_party/WebKit/Source/core/frame/DOMTimerCoordinator.h
index b9d45f3..b9e99f9 100644
--- a/third_party/WebKit/Source/core/frame/DOMTimerCoordinator.h
+++ b/third_party/WebKit/Source/core/frame/DOMTimerCoordinator.h
@@ -38,8 +38,6 @@
   // destroy the timer.
   DOMTimer* RemoveTimeoutByID(int id);
 
-  bool HasInstalledTimeout() const;
-
   // Timers created during the execution of other timers, and
   // repeating timers, are throttled. Timer nesting level tracks the
   // number of linked timers or repetitions of a timer. See
diff --git a/third_party/WebKit/Source/core/loader/WorkerFetchContext.h b/third_party/WebKit/Source/core/loader/WorkerFetchContext.h
index 3eb9b34..a240e3e 100644
--- a/third_party/WebKit/Source/core/loader/WorkerFetchContext.h
+++ b/third_party/WebKit/Source/core/loader/WorkerFetchContext.h
@@ -26,9 +26,7 @@
 
 // The WorkerFetchContext is a FetchContext for workers (dedicated, shared and
 // service workers) and threaded worklets (animation and audio worklets). This
-// class is used only when off-main-thread-fetch is enabled, and is still under
-// development.
-// TODO(horo): Implement all methods of FetchContext. crbug.com/443374
+// class is used only when off-main-thread-fetch is enabled.
 class WorkerFetchContext final : public BaseFetchContext {
  public:
   static WorkerFetchContext* Create(WorkerOrWorkletGlobalScope&);
diff --git a/third_party/WebKit/Source/core/paint/BoxBorderPainter.cpp b/third_party/WebKit/Source/core/paint/BoxBorderPainter.cpp
index dd8d5658..3965f9a2 100644
--- a/third_party/WebKit/Source/core/paint/BoxBorderPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/BoxBorderPainter.cpp
@@ -943,11 +943,11 @@
       ClipBorderSidePolygon(graphics_context, side, miter1, miter2);
     else
       ClipBorderSideForComplexInnerPath(graphics_context, side);
-    float thickness =
+    float stroke_thickness =
         std::max(std::max(edge_to_render.Width(), adjacent_edge1.Width()),
                  adjacent_edge2.Width());
     DrawBoxSideFromPath(graphics_context, LayoutRect(outer_.Rect()), *path,
-                        edge_to_render.Width(), thickness, side, color,
+                        edge_to_render.Width(), stroke_thickness, side, color,
                         edge_to_render.BorderStyle());
   } else {
     MiterType miter1 =
@@ -977,15 +977,15 @@
 void BoxBorderPainter::DrawBoxSideFromPath(GraphicsContext& graphics_context,
                                            const LayoutRect& border_rect,
                                            const Path& border_path,
-                                           float thickness,
-                                           float draw_thickness,
+                                           float border_thickness,
+                                           float stroke_thickness,
                                            BoxSide side,
                                            Color color,
                                            EBorderStyle border_style) const {
-  if (thickness <= 0)
+  if (border_thickness <= 0)
     return;
 
-  if (border_style == EBorderStyle::kDouble && thickness < 3)
+  if (border_style == EBorderStyle::kDouble && border_thickness < 3)
     border_style = EBorderStyle::kSolid;
 
   switch (border_style) {
@@ -994,20 +994,22 @@
       return;
     case EBorderStyle::kDotted:
     case EBorderStyle::kDashed: {
-      DrawDashedDottedBoxSideFromPath(graphics_context, border_rect, thickness,
-                                      draw_thickness, color, border_style);
+      DrawDashedDottedBoxSideFromPath(graphics_context, border_rect,
+                                      border_thickness, stroke_thickness, color,
+                                      border_style);
       return;
     }
     case EBorderStyle::kDouble: {
       DrawDoubleBoxSideFromPath(graphics_context, border_rect, border_path,
-                                thickness, draw_thickness, side, color);
+                                border_thickness, stroke_thickness, side,
+                                color);
       return;
     }
     case EBorderStyle::kRidge:
     case EBorderStyle::kGroove: {
       DrawRidgeGrooveBoxSideFromPath(graphics_context, border_rect, border_path,
-                                     thickness, draw_thickness, side, color,
-                                     border_style);
+                                     border_thickness, stroke_thickness, side,
+                                     color, border_style);
       return;
     }
     case EBorderStyle::kInset:
@@ -1030,8 +1032,8 @@
 void BoxBorderPainter::DrawDashedDottedBoxSideFromPath(
     GraphicsContext& graphics_context,
     const LayoutRect& border_rect,
-    float thickness,
-    float draw_thickness,
+    float border_thickness,
+    float stroke_thickness,
     Color color,
     EBorderStyle border_style) const {
   // Convert the path to be down the middle of the dots or dashes.
@@ -1045,16 +1047,18 @@
 
   graphics_context.SetStrokeColor(color);
 
-  if (!StrokeData::StrokeIsDashed(
-          thickness, border_style == EBorderStyle::kDashed ? kDashedStroke
-                                                           : kDottedStroke)) {
-    DrawWideDottedBoxSideFromPath(graphics_context, centerline_path, thickness);
+  if (!StrokeData::StrokeIsDashed(border_thickness,
+                                  border_style == EBorderStyle::kDashed
+                                      ? kDashedStroke
+                                      : kDottedStroke)) {
+    DrawWideDottedBoxSideFromPath(graphics_context, centerline_path,
+                                  border_thickness);
     return;
   }
 
   // The extra multiplier is so that the clipping mask can antialias
   // the edges to prevent jaggies.
-  graphics_context.SetStrokeThickness(draw_thickness * 1.1f);
+  graphics_context.SetStrokeThickness(stroke_thickness * 1.1f);
   graphics_context.SetStrokeStyle(
       border_style == EBorderStyle::kDashed ? kDashedStroke : kDottedStroke);
 
@@ -1062,11 +1066,11 @@
   // do the same thing as StrokeData::setupPaintDashPathEffect and should be
   // refactored to re-use that code. It would require
   // GraphicsContext::strokePath to take a length parameter.
-  float dash_length = thickness;
+  float dash_length = border_thickness;
   float gap_length = dash_length;
   if (border_style == EBorderStyle::kDashed) {
-    dash_length *= StrokeData::DashLengthRatio(thickness);
-    gap_length *= StrokeData::DashGapRatio(thickness);
+    dash_length *= StrokeData::DashLengthRatio(border_thickness);
+    gap_length *= StrokeData::DashGapRatio(border_thickness);
   }
   float path_length = centerline_path.length();
   // Don't try to show dashes if we have less than 2 dashes + 2 gaps.
@@ -1096,8 +1100,8 @@
 void BoxBorderPainter::DrawWideDottedBoxSideFromPath(
     GraphicsContext& graphics_context,
     const Path& border_path,
-    float thickness) const {
-  graphics_context.SetStrokeThickness(thickness);
+    float border_thickness) const {
+  graphics_context.SetStrokeThickness(border_thickness);
   graphics_context.SetStrokeStyle(kDottedStroke);
 
   // TODO(schenney): This code for setting up the dash effect is largely
@@ -1107,7 +1111,7 @@
   graphics_context.SetLineCap(kRoundCap);
 
   // Adjust the width to get equal dot spacing as much as possible.
-  float per_dot_length = thickness * 2;
+  float per_dot_length = border_thickness * 2;
   float path_length = border_path.length();
 
   if (path_length < per_dot_length) {
@@ -1118,12 +1122,12 @@
     line_dash.push_back(per_dot_length);
     graphics_context.SetLineDash(line_dash, 0);
   } else {
-    float gap =
-        StrokeData::SelectBestDashGap(path_length, thickness, thickness);
+    float gap = StrokeData::SelectBestDashGap(path_length, border_thickness,
+                                              border_thickness);
     static const float kEpsilon = 1.0e-2f;
     DashArray line_dash;
     line_dash.push_back(0);
-    line_dash.push_back(gap + thickness - kEpsilon);
+    line_dash.push_back(gap + border_thickness - kEpsilon);
     graphics_context.SetLineDash(line_dash, 0);
   }
 
@@ -1136,8 +1140,8 @@
     GraphicsContext& graphics_context,
     const LayoutRect& border_rect,
     const Path& border_path,
-    float thickness,
-    float draw_thickness,
+    float border_thickness,
+    float stroke_thickness,
     BoxSide side,
     Color color) const {
   // Draw inner border line
@@ -1150,8 +1154,9 @@
         include_logical_right_edge_);
 
     graphics_context.ClipRoundedRect(inner_clip);
-    DrawBoxSideFromPath(graphics_context, border_rect, border_path, thickness,
-                        draw_thickness, side, color, EBorderStyle::kSolid);
+    DrawBoxSideFromPath(graphics_context, border_rect, border_path,
+                        border_thickness, stroke_thickness, side, color,
+                        EBorderStyle::kSolid);
   }
 
   // Draw outer border line
@@ -1173,8 +1178,9 @@
         outer_rect, outer_insets, include_logical_left_edge_,
         include_logical_right_edge_);
     graphics_context.ClipOutRoundedRect(outer_clip);
-    DrawBoxSideFromPath(graphics_context, border_rect, border_path, thickness,
-                        draw_thickness, side, color, EBorderStyle::kSolid);
+    DrawBoxSideFromPath(graphics_context, border_rect, border_path,
+                        border_thickness, stroke_thickness, side, color,
+                        EBorderStyle::kSolid);
   }
 }
 
@@ -1182,8 +1188,8 @@
     GraphicsContext& graphics_context,
     const LayoutRect& border_rect,
     const Path& border_path,
-    float thickness,
-    float draw_thickness,
+    float border_thickness,
+    float stroke_thickness,
     BoxSide side,
     Color color,
     EBorderStyle border_style) const {
@@ -1198,8 +1204,8 @@
   }
 
   // Paint full border
-  DrawBoxSideFromPath(graphics_context, border_rect, border_path, thickness,
-                      draw_thickness, side, color, s1);
+  DrawBoxSideFromPath(graphics_context, border_rect, border_path,
+                      border_thickness, stroke_thickness, side, color, s1);
 
   // Paint inner only
   GraphicsContextStateSaver state_saver(graphics_context);
@@ -1214,8 +1220,8 @@
       include_logical_left_edge_, include_logical_right_edge_);
 
   graphics_context.ClipRoundedRect(clip_rect);
-  DrawBoxSideFromPath(graphics_context, border_rect, border_path, thickness,
-                      draw_thickness, side, color, s2);
+  DrawBoxSideFromPath(graphics_context, border_rect, border_path,
+                      border_thickness, stroke_thickness, side, color, s2);
 }
 
 void BoxBorderPainter::ClipBorderSideForComplexInnerPath(
diff --git a/third_party/WebKit/Source/web/tests/VirtualTimeTest.cpp b/third_party/WebKit/Source/core/scheduler/VirtualTimeTest.cpp
similarity index 97%
rename from third_party/WebKit/Source/web/tests/VirtualTimeTest.cpp
rename to third_party/WebKit/Source/core/scheduler/VirtualTimeTest.cpp
index 029b3c12..f6c58a7f 100644
--- a/third_party/WebKit/Source/web/tests/VirtualTimeTest.cpp
+++ b/third_party/WebKit/Source/core/scheduler/VirtualTimeTest.cpp
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/run_loop.h"
 #include "build/build_config.h"
 #include "core/dom/TaskRunnerHelper.h"
 #include "core/testing/sim/SimRequest.h"
@@ -54,19 +53,16 @@
 };
 
 namespace {
-void QuitRunLoop() {
-  base::RunLoop::QuitCurrentDeprecated();
-}
 
 // Some task queues may have repeating v8 tasks that run forever so we impose a
 // hard time limit.
 void RunTasksForPeriod(double delay_ms) {
   Platform::Current()->CurrentThread()->GetWebTaskRunner()->PostDelayedTask(
-      BLINK_FROM_HERE, WTF::Bind(&QuitRunLoop),
+      BLINK_FROM_HERE, WTF::Bind(&testing::ExitRunLoop),
       TimeDelta::FromMillisecondsD(delay_ms));
   testing::EnterRunLoop();
 }
-}
+}  // namespace
 
 // http://crbug.com/633321
 #if defined(OS_ANDROID)
diff --git a/third_party/WebKit/Source/core/workers/DedicatedWorkerTest.cpp b/third_party/WebKit/Source/core/workers/DedicatedWorkerTest.cpp
index 9bb22d8..23f06a7 100644
--- a/third_party/WebKit/Source/core/workers/DedicatedWorkerTest.cpp
+++ b/third_party/WebKit/Source/core/workers/DedicatedWorkerTest.cpp
@@ -24,19 +24,6 @@
 
 namespace blink {
 
-namespace {
-
-// These are chosen by trial-and-error. Making these intervals smaller causes
-// test flakiness. The main thread needs to wait until message confirmation and
-// activity report separately. If the intervals are very short, they are
-// notified to the main thread almost at the same time and the thread may miss
-// the second notification.
-constexpr double kDefaultIntervalInSec = 0.01;
-constexpr double kNextIntervalInSec = 0.01;
-constexpr double kMaxIntervalInSec = 0.02;
-
-}  // namespace
-
 class DedicatedWorkerThreadForTest final : public DedicatedWorkerThread {
  public:
   DedicatedWorkerThreadForTest(InProcessWorkerObjectProxy& worker_object_proxy)
@@ -96,9 +83,6 @@
       ParentFrameTaskRunners* parent_frame_task_runners)
       : InProcessWorkerObjectProxy(messaging_proxy, parent_frame_task_runners),
         reported_features_(static_cast<int>(WebFeature::kNumberOfFeatures)) {
-    default_interval_in_sec_ = kDefaultIntervalInSec;
-    next_interval_in_sec_ = kNextIntervalInSec;
-    max_interval_in_sec_ = kMaxIntervalInSec;
   }
 
   void CountFeature(WebFeature feature) override {
@@ -131,7 +115,6 @@
   }
 
   ~InProcessWorkerMessagingProxyForTest() override {
-    EXPECT_FALSE(blocking_);
   }
 
   void StartWithSourceCode(const String& source) {
@@ -153,49 +136,10 @@
         CreateBackingThreadStartupData(nullptr /* isolate */), script_url);
   }
 
-  enum class Notification {
-    kMessageConfirmed,
-    kPendingActivityReported,
-  };
-
-  // Blocks the main thread until some event is notified.
-  Notification WaitForNotification() {
-    EXPECT_TRUE(IsMainThread());
-    DCHECK(!blocking_);
-    if (events_.IsEmpty()) {
-      blocking_ = true;
-      testing::EnterRunLoop();
-      DCHECK(!blocking_);
-    }
-    return events_.TakeFirst();
-  }
-
-  void ConfirmMessageFromWorkerObject() override {
-    EXPECT_TRUE(IsMainThread());
-    InProcessWorkerMessagingProxy::ConfirmMessageFromWorkerObject();
-    events_.push_back(Notification::kMessageConfirmed);
-    if (blocking_)
-      testing::ExitRunLoop();
-    blocking_ = false;
-  }
-
-  void PendingActivityFinished() override {
-    EXPECT_TRUE(IsMainThread());
-    InProcessWorkerMessagingProxy::PendingActivityFinished();
-    events_.push_back(Notification::kPendingActivityReported);
-    if (blocking_)
-      testing::ExitRunLoop();
-    blocking_ = false;
-  }
-
   DedicatedWorkerThreadForTest* GetDedicatedWorkerThread() {
     return static_cast<DedicatedWorkerThreadForTest*>(GetWorkerThread());
   }
 
-  unsigned UnconfirmedMessageCount() const {
-    return unconfirmed_message_count_;
-  }
-
   DEFINE_INLINE_VIRTUAL_TRACE() {
     visitor->Trace(mock_worker_thread_lifecycle_observer_);
     InProcessWorkerMessagingProxy::Trace(visitor);
@@ -224,13 +168,8 @@
   Member<MockWorkerThreadLifecycleObserver>
       mock_worker_thread_lifecycle_observer_;
   RefPtr<SecurityOrigin> security_origin_;
-
-  WTF::Deque<Notification> events_;
-  bool blocking_ = false;
 };
 
-using Notification = InProcessWorkerMessagingProxyForTest::Notification;
-
 class DedicatedWorkerTest : public ::testing::Test {
  public:
   DedicatedWorkerTest() {}
@@ -266,142 +205,14 @@
   Persistent<InProcessWorkerMessagingProxyForTest> worker_messaging_proxy_;
 };
 
-TEST_F(DedicatedWorkerTest, PendingActivity_NoActivity) {
+TEST_F(DedicatedWorkerTest, PendingActivity_NoActivityAfterContextDestroyed) {
   const String source_code = "// Do nothing";
   WorkerMessagingProxy()->StartWithSourceCode(source_code);
 
-  // Worker initialization should be counted as a pending activity.
   EXPECT_TRUE(WorkerMessagingProxy()->HasPendingActivity());
 
-  // There should be no pending activities after the initialization.
-  EXPECT_EQ(Notification::kPendingActivityReported,
-            WorkerMessagingProxy()->WaitForNotification());
-  EXPECT_FALSE(WorkerMessagingProxy()->HasPendingActivity());
-}
-
-TEST_F(DedicatedWorkerTest, PendingActivity_SetTimeout) {
-  // Start an oneshot timer on initial script evaluation.
-  const String source_code = "setTimeout(function() {}, 0);";
-  WorkerMessagingProxy()->StartWithSourceCode(source_code);
-
-  // Worker initialization should be counted as a pending activity.
-  EXPECT_TRUE(WorkerMessagingProxy()->HasPendingActivity());
-
-  // The timer is fired soon and there should be no pending activities after
-  // that.
-  EXPECT_EQ(Notification::kPendingActivityReported,
-            WorkerMessagingProxy()->WaitForNotification());
-  EXPECT_FALSE(WorkerMessagingProxy()->HasPendingActivity());
-}
-
-TEST_F(DedicatedWorkerTest, PendingActivity_SetInterval) {
-  // Start a repeated timer on initial script evaluation, and stop it when a
-  // message is received. The timer needs a non-zero delay or else worker
-  // activities would not run.
-  const String source_code =
-      "var id = setInterval(function() {}, 50);"
-      "addEventListener('message', function(event) { clearInterval(id); });";
-  WorkerMessagingProxy()->StartWithSourceCode(source_code);
-
-  // Worker initialization should be counted as a pending activity.
-  EXPECT_TRUE(WorkerMessagingProxy()->HasPendingActivity());
-
-  // Stop the timer.
-  DispatchMessageEvent();
-  EXPECT_EQ(1u, WorkerMessagingProxy()->UnconfirmedMessageCount());
-  EXPECT_TRUE(WorkerMessagingProxy()->HasPendingActivity());
-  EXPECT_EQ(Notification::kMessageConfirmed,
-            WorkerMessagingProxy()->WaitForNotification());
-  EXPECT_EQ(0u, WorkerMessagingProxy()->UnconfirmedMessageCount());
-  EXPECT_TRUE(WorkerMessagingProxy()->HasPendingActivity());
-
-  // There should be no pending activities after the timer is stopped.
-  EXPECT_EQ(Notification::kPendingActivityReported,
-            WorkerMessagingProxy()->WaitForNotification());
-  EXPECT_FALSE(WorkerMessagingProxy()->HasPendingActivity());
-}
-
-TEST_F(DedicatedWorkerTest, PendingActivity_SetTimeoutOnMessageEvent) {
-  // Start an oneshot timer on a message event.
-  const String source_code =
-      "addEventListener('message', function(event) {"
-      "  setTimeout(function() {}, 0);"
-      "});";
-  WorkerMessagingProxy()->StartWithSourceCode(source_code);
-
-  // Worker initialization should be counted as a pending activity.
-  EXPECT_TRUE(WorkerMessagingProxy()->HasPendingActivity());
-  EXPECT_EQ(Notification::kPendingActivityReported,
-            WorkerMessagingProxy()->WaitForNotification());
-  EXPECT_FALSE(WorkerMessagingProxy()->HasPendingActivity());
-
-  // A message starts the oneshot timer that is counted as a pending activity.
-  DispatchMessageEvent();
-  EXPECT_EQ(1u, WorkerMessagingProxy()->UnconfirmedMessageCount());
-  EXPECT_TRUE(WorkerMessagingProxy()->HasPendingActivity());
-  EXPECT_EQ(Notification::kMessageConfirmed,
-            WorkerMessagingProxy()->WaitForNotification());
-  EXPECT_EQ(0u, WorkerMessagingProxy()->UnconfirmedMessageCount());
-  EXPECT_TRUE(WorkerMessagingProxy()->HasPendingActivity());
-
-  // The timer is fired soon and there should be no pending activities after
-  // that.
-  EXPECT_EQ(Notification::kPendingActivityReported,
-            WorkerMessagingProxy()->WaitForNotification());
-  EXPECT_FALSE(WorkerMessagingProxy()->HasPendingActivity());
-}
-
-TEST_F(DedicatedWorkerTest, PendingActivity_SetIntervalOnMessageEvent) {
-  // Start a repeated timer on a message event, and stop it when another
-  // message is received. The timer needs a non-zero delay or else worker
-  // activities would not run.
-  const String source_code =
-      "var count = 0;"
-      "var id;"
-      "addEventListener('message', function(event) {"
-      "  if (count++ == 0) {"
-      "    id = setInterval(function() {}, 50);"
-      "  } else {"
-      "    clearInterval(id);"
-      "  }"
-      "});";
-  WorkerMessagingProxy()->StartWithSourceCode(source_code);
-
-  // Worker initialization should be counted as a pending activity.
-  EXPECT_TRUE(WorkerMessagingProxy()->HasPendingActivity());
-  EXPECT_EQ(Notification::kPendingActivityReported,
-            WorkerMessagingProxy()->WaitForNotification());
-  EXPECT_FALSE(WorkerMessagingProxy()->HasPendingActivity());
-
-  // The first message event sets the active timer that is counted as a
-  // pending activity.
-  DispatchMessageEvent();
-  EXPECT_EQ(1u, WorkerMessagingProxy()->UnconfirmedMessageCount());
-  EXPECT_TRUE(WorkerMessagingProxy()->HasPendingActivity());
-  EXPECT_EQ(Notification::kMessageConfirmed,
-            WorkerMessagingProxy()->WaitForNotification());
-  EXPECT_EQ(0u, WorkerMessagingProxy()->UnconfirmedMessageCount());
-  EXPECT_TRUE(WorkerMessagingProxy()->HasPendingActivity());
-
-  // Run the message loop for a while to make sure the timer is counted as a
-  // pending activity until it's stopped. The delay is equal to the max
-  // interval so that the pending activity timer may be able to have a chance
-  // to run before the next expectation check.
-  constexpr TimeDelta kDelay = TimeDelta::FromSecondsD(kMaxIntervalInSec);
-  testing::RunDelayedTasks(kDelay);
-  EXPECT_TRUE(WorkerMessagingProxy()->HasPendingActivity());
-
-  // Stop the timer.
-  DispatchMessageEvent();
-  EXPECT_EQ(1u, WorkerMessagingProxy()->UnconfirmedMessageCount());
-  EXPECT_TRUE(WorkerMessagingProxy()->HasPendingActivity());
-  EXPECT_EQ(Notification::kMessageConfirmed,
-            WorkerMessagingProxy()->WaitForNotification());
-  EXPECT_EQ(0u, WorkerMessagingProxy()->UnconfirmedMessageCount());
-
-  // There should be no pending activities after the timer is stopped.
-  EXPECT_EQ(Notification::kPendingActivityReported,
-            WorkerMessagingProxy()->WaitForNotification());
+  // Destroying the context should result in no pending activities.
+  WorkerMessagingProxy()->TerminateGlobalScope();
   EXPECT_FALSE(WorkerMessagingProxy()->HasPendingActivity());
 }
 
diff --git a/third_party/WebKit/Source/core/workers/InProcessWorkerMessagingProxy.cpp b/third_party/WebKit/Source/core/workers/InProcessWorkerMessagingProxy.cpp
index e33356d..72a34ad 100644
--- a/third_party/WebKit/Source/core/workers/InProcessWorkerMessagingProxy.cpp
+++ b/third_party/WebKit/Source/core/workers/InProcessWorkerMessagingProxy.cpp
@@ -134,9 +134,6 @@
     return;
 
   if (GetWorkerThread()) {
-    // A message event is an activity and may initiate another activity.
-    worker_global_scope_has_pending_activity_ = true;
-    ++unconfirmed_message_count_;
     WTF::CrossThreadClosure task = CrossThreadBind(
         &InProcessWorkerObjectProxy::ProcessMessageFromWorkerObject,
         CrossThreadUnretained(&WorkerObjectProxy()), std::move(message),
@@ -184,11 +181,6 @@
   DCHECK(IsParentContextThread());
   ThreadedMessagingProxyBase::WorkerThreadCreated();
 
-  // Worker initialization means a pending activity.
-  worker_global_scope_has_pending_activity_ = true;
-
-  DCHECK_EQ(0u, unconfirmed_message_count_);
-  unconfirmed_message_count_ = queued_early_tasks_.size();
   for (auto& queued_task : queued_early_tasks_) {
     WTF::CrossThreadClosure task = CrossThreadBind(
         &InProcessWorkerObjectProxy::ProcessMessageFromWorkerObject,
@@ -202,26 +194,6 @@
   queued_early_tasks_.clear();
 }
 
-void InProcessWorkerMessagingProxy::ConfirmMessageFromWorkerObject() {
-  DCHECK(IsParentContextThread());
-  if (AskedToTerminate())
-    return;
-  DCHECK(worker_global_scope_has_pending_activity_);
-  DCHECK_GT(unconfirmed_message_count_, 0u);
-  --unconfirmed_message_count_;
-}
-
-void InProcessWorkerMessagingProxy::PendingActivityFinished() {
-  DCHECK(IsParentContextThread());
-  DCHECK(worker_global_scope_has_pending_activity_);
-  if (unconfirmed_message_count_ > 0) {
-    // Ignore the report because an inflight message event may initiate a
-    // new activity.
-    return;
-  }
-  worker_global_scope_has_pending_activity_ = false;
-}
-
 DEFINE_TRACE(InProcessWorkerMessagingProxy) {
   visitor->Trace(worker_object_);
   ThreadedMessagingProxyBase::Trace(visitor);
@@ -229,9 +201,7 @@
 
 bool InProcessWorkerMessagingProxy::HasPendingActivity() const {
   DCHECK(IsParentContextThread());
-  if (AskedToTerminate())
-    return false;
-  return worker_global_scope_has_pending_activity_;
+  return !AskedToTerminate();
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/workers/InProcessWorkerMessagingProxy.h b/third_party/WebKit/Source/core/workers/InProcessWorkerMessagingProxy.h
index fc46f0fe..bd643be 100644
--- a/third_party/WebKit/Source/core/workers/InProcessWorkerMessagingProxy.h
+++ b/third_party/WebKit/Source/core/workers/InProcessWorkerMessagingProxy.h
@@ -72,13 +72,6 @@
                           std::unique_ptr<SourceLocation>,
                           int exception_id);
 
-  // 'virtual' for testing.
-  virtual void ConfirmMessageFromWorkerObject();
-
-  // Called from InProcessWorkerObjectProxy when all pending activities on the
-  // worker context are finished. See InProcessWorkerObjectProxy.h for details.
-  virtual void PendingActivityFinished();
-
   DECLARE_VIRTUAL_TRACE();
 
  protected:
@@ -116,15 +109,6 @@
   // Tasks are queued here until there's a thread object created.
   struct QueuedTask;
   Vector<QueuedTask> queued_early_tasks_;
-
-  // Unconfirmed messages from the parent context thread to the worker thread.
-  // When this is greater than 0, |m_workerGlobalScopeHasPendingActivity| should
-  // be true.
-  unsigned unconfirmed_message_count_ = 0;
-
-  // Indicates whether there are pending activities (e.g, MessageEvent,
-  // setTimeout) on the worker context.
-  bool worker_global_scope_has_pending_activity_ = false;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/workers/InProcessWorkerObjectProxy.cpp b/third_party/WebKit/Source/core/workers/InProcessWorkerObjectProxy.cpp
index fe8388b..b366fac6 100644
--- a/third_party/WebKit/Source/core/workers/InProcessWorkerObjectProxy.cpp
+++ b/third_party/WebKit/Source/core/workers/InProcessWorkerObjectProxy.cpp
@@ -32,7 +32,6 @@
 
 #include <memory>
 #include "bindings/core/v8/SourceLocation.h"
-#include "bindings/core/v8/V8GCController.h"
 #include "bindings/core/v8/serialization/SerializedScriptValue.h"
 #include "core/dom/Document.h"
 #include "core/dom/ExecutionContext.h"
@@ -51,9 +50,6 @@
 
 namespace blink {
 
-const double kDefaultIntervalInSec = 1;
-const double kMaxIntervalInSec = 30;
-
 std::unique_ptr<InProcessWorkerObjectProxy> InProcessWorkerObjectProxy::Create(
     InProcessWorkerMessagingProxy* messaging_proxy_weak_ptr,
     ParentFrameTaskRunners* parent_frame_task_runners) {
@@ -85,16 +81,6 @@
   MessagePortArray* ports =
       MessagePort::EntanglePorts(*global_scope, std::move(channels));
   global_scope->DispatchEvent(MessageEvent::Create(ports, std::move(message)));
-
-  GetParentFrameTaskRunners()
-      ->Get(TaskType::kUnspecedTimer)
-      ->PostTask(
-          BLINK_FROM_HERE,
-          CrossThreadBind(
-              &InProcessWorkerMessagingProxy::ConfirmMessageFromWorkerObject,
-              messaging_proxy_weak_ptr_));
-
-  StartPendingActivityTimer();
 }
 
 void InProcessWorkerObjectProxy::ProcessUnhandledException(
@@ -122,21 +108,9 @@
     WorkerOrWorkletGlobalScope* global_scope) {
   DCHECK(!worker_global_scope_);
   worker_global_scope_ = ToWorkerGlobalScope(global_scope);
-  // This timer task should be unthrottled in order to prevent GC timing from
-  // being delayed.
-  // TODO(nhiroki): Consider making a special task type for GC.
-  // (https://crbug.com/712504)
-  timer_ = WTF::MakeUnique<TaskRunnerTimer<InProcessWorkerObjectProxy>>(
-      TaskRunnerHelper::Get(TaskType::kUnthrottled, global_scope), this,
-      &InProcessWorkerObjectProxy::CheckPendingActivity);
-}
-
-void InProcessWorkerObjectProxy::DidEvaluateWorkerScript(bool) {
-  StartPendingActivityTimer();
 }
 
 void InProcessWorkerObjectProxy::WillDestroyWorkerGlobalScope() {
-  timer_.reset();
   worker_global_scope_ = nullptr;
 }
 
@@ -144,45 +118,7 @@
     InProcessWorkerMessagingProxy* messaging_proxy_weak_ptr,
     ParentFrameTaskRunners* parent_frame_task_runners)
     : ThreadedObjectProxyBase(parent_frame_task_runners),
-      messaging_proxy_weak_ptr_(messaging_proxy_weak_ptr),
-      default_interval_in_sec_(kDefaultIntervalInSec),
-      next_interval_in_sec_(kDefaultIntervalInSec),
-      max_interval_in_sec_(kMaxIntervalInSec) {}
-
-void InProcessWorkerObjectProxy::StartPendingActivityTimer() {
-  if (timer_->IsActive()) {
-    // Reset the next interval duration to check new activity state timely.
-    // For example, a long-running activity can be cancelled by a message
-    // event.
-    next_interval_in_sec_ = kDefaultIntervalInSec;
-    return;
-  }
-  timer_->StartOneShot(next_interval_in_sec_, BLINK_FROM_HERE);
-  next_interval_in_sec_ =
-      std::min(next_interval_in_sec_ * 1.5, max_interval_in_sec_);
-}
-
-void InProcessWorkerObjectProxy::CheckPendingActivity(TimerBase*) {
-  bool has_pending_activity = V8GCController::HasPendingActivity(
-      worker_global_scope_->GetThread()->GetIsolate(), worker_global_scope_);
-  if (!has_pending_activity) {
-    // Report all activities are done.
-    GetParentFrameTaskRunners()
-        ->Get(TaskType::kUnspecedTimer)
-        ->PostTask(BLINK_FROM_HERE,
-                   CrossThreadBind(
-                       &InProcessWorkerMessagingProxy::PendingActivityFinished,
-                       messaging_proxy_weak_ptr_));
-
-    // Don't schedule a timer. It will be started again when a message event
-    // is dispatched.
-    next_interval_in_sec_ = default_interval_in_sec_;
-    return;
-  }
-
-  // There is still a pending activity. Check it later.
-  StartPendingActivityTimer();
-}
+      messaging_proxy_weak_ptr_(messaging_proxy_weak_ptr) {}
 
 CrossThreadWeakPersistent<ThreadedMessagingProxyBase>
 InProcessWorkerObjectProxy::MessagingProxyWeakPtr() {
diff --git a/third_party/WebKit/Source/core/workers/InProcessWorkerObjectProxy.h b/third_party/WebKit/Source/core/workers/InProcessWorkerObjectProxy.h
index 1bbde8d6..e5b10bf 100644
--- a/third_party/WebKit/Source/core/workers/InProcessWorkerObjectProxy.h
+++ b/third_party/WebKit/Source/core/workers/InProcessWorkerObjectProxy.h
@@ -36,7 +36,6 @@
 #include "core/dom/MessagePort.h"
 #include "core/workers/ThreadedObjectProxyBase.h"
 #include "core/workers/WorkerReportingProxy.h"
-#include "platform/Timer.h"
 #include "platform/heap/Handle.h"
 #include "platform/wtf/RefPtr.h"
 #include "platform/wtf/WeakPtr.h"
@@ -77,7 +76,6 @@
                        std::unique_ptr<SourceLocation>,
                        int exception_id) override;
   void DidCreateWorkerGlobalScope(WorkerOrWorkletGlobalScope*) override;
-  void DidEvaluateWorkerScript(bool success) override;
   void WillDestroyWorkerGlobalScope() override;
 
  protected:
@@ -90,32 +88,12 @@
  private:
   friend class InProcessWorkerObjectProxyForTest;
 
-  void StartPendingActivityTimer();
-  void CheckPendingActivity(TimerBase*);
-
   // No guarantees about the lifetimes of tasks posted by this proxy wrt the
   // InProcessWorkerMessagingProxy so a weak pointer must be used when posting
   // the tasks.
   CrossThreadWeakPersistent<InProcessWorkerMessagingProxy>
       messaging_proxy_weak_ptr_;
 
-  // Used for checking pending activities on the worker global scope. This is
-  // cancelled when the worker global scope is destroyed.
-  std::unique_ptr<TaskRunnerTimer<InProcessWorkerObjectProxy>> timer_;
-
-  // The default interval duration of the timer. This is usually
-  // kDefaultIntervalInSec but made as a member variable for testing.
-  double default_interval_in_sec_;
-
-  // The next interval duration of the timer. This is initially set to
-  // |m_defaultIntervalInSec| and exponentially increased up to
-  // |m_maxIntervalInSec|.
-  double next_interval_in_sec_;
-
-  // The max interval duration of the timer. This is usually kMaxIntervalInSec
-  // but made as a member variable for testing.
-  double max_interval_in_sec_;
-
   CrossThreadPersistent<WorkerGlobalScope> worker_global_scope_;
 };
 
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
index 562986b6..90350bb 100644
--- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
@@ -249,7 +249,9 @@
 }
 
 bool WorkerGlobalScope::HasPendingActivity() const {
-  return timers_.HasInstalledTimeout();
+  // The worker global scope wrapper is kept alive as long as its execution
+  // context is alive.
+  return !ExecutionContext::IsContextDestroyed();
 }
 
 bool WorkerGlobalScope::IsContextThread() const {
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.cpp b/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.cpp
index c7e6979..259d153 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.cpp
@@ -528,32 +528,14 @@
   } else if (options.cors_handling_by_resource_fetcher ==
                  kEnableCORSHandlingByResourceFetcher &&
              fetch_request_mode == WebURLRequest::kFetchRequestModeCORS) {
-    bool unused_preload = resource_->IsUnusedPreload();
-
-    // Redirects can change the response URL different from one of request.
-    const KURL& response_url = response.Url();
-
-    ResourceRequestBlockedReason blocked_reason = Context().CanRequest(
-        resource_type, initial_request, response_url, options,
-        /* Don't send security violation reports for unused preloads */
-        (unused_preload ? SecurityViolationReportingPolicy::kSuppressReporting
-                        : SecurityViolationReportingPolicy::kReport),
-        FetchParameters::kUseDefaultOriginRestrictionForType,
-        initial_request.GetRedirectStatus());
-    if (blocked_reason != ResourceRequestBlockedReason::kNone) {
-      HandleError(ResourceError::CancelledDueToAccessCheckError(
-          response_url, blocked_reason));
-      return;
-    }
-
     if (!resource_->IsSameOriginOrCORSSuccessful()) {
-      if (!unused_preload) {
+      if (!resource_->IsUnusedPreload())
         Context().AddErrorConsoleMessage(cors_error_msg.ToString(),
                                          FetchContext::kJSSource);
-      }
 
+      // Redirects can change the response URL different from one of request.
       HandleError(ResourceError::CancelledDueToAccessCheckError(
-          response_url, ResourceRequestBlockedReason::kOther));
+          response.Url(), ResourceRequestBlockedReason::kOther));
       return;
     }
   }
diff --git a/third_party/WebKit/Source/web/BUILD.gn b/third_party/WebKit/Source/web/BUILD.gn
index b337d83..176c6c9d 100644
--- a/third_party/WebKit/Source/web/BUILD.gn
+++ b/third_party/WebKit/Source/web/BUILD.gn
@@ -70,7 +70,6 @@
     # crbug.com/353585
 
     "tests/RunAllTests.cpp",
-    "tests/VirtualTimeTest.cpp",
   ]
   sources += bindings_unittest_files
 
diff --git a/third_party/WebKit/public/platform/web_feature.mojom b/third_party/WebKit/public/platform/web_feature.mojom
index caf1edf..df54c75a3 100644
--- a/third_party/WebKit/public/platform/web_feature.mojom
+++ b/third_party/WebKit/public/platform/web_feature.mojom
@@ -1601,6 +1601,7 @@
   kPresentationRequestStartSecureOrigin = 2063,
   kPresentationRequestStartInsecureOrigin = 2064,
   kPersistentClientHintHeader = 2065,
+  kStyleSheetListNonNullAnonymousNamedGetter = 2066,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/googletest/README.chromium b/third_party/googletest/README.chromium
index 3fd6f3e..1482ba65 100644
--- a/third_party/googletest/README.chromium
+++ b/third_party/googletest/README.chromium
@@ -3,6 +3,7 @@
 URL: https://github.com/google/googletest.git
 Version: 1.8.0.git-8c7f93fedaca1b0158e67af0f5dd63a044066eab
 License: BSD
+License File: NOT_SHIPPED
 Security critical: no
 
 Google Test is imported as-is, to facilitate version bumping. However, the
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 258f698..b1de6ee 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -178,6 +178,7 @@
       'EarlGreyiOS': 'ios',
       'Fuchsia': 'release_bot_fuchsia',
       'Fuchsia (dbg)': 'debug_bot_fuchsia',
+      'Fuchsia Compile': 'release_bot_fuchsia',
       'GomaCanaryiOS': 'ios',
       'ios-simulator': 'ios',
       'Headless Linux (dbg)': 'headless_linux_debug_bot',
@@ -521,6 +522,7 @@
       'chromeos_daisy_chromium_compile_only_ng': 'cros_chrome_sdk',
       'closure_compilation': 'closure_compilation',
       'fuchsia': 'release_trybot_fuchsia',
+      'fuchsia_compile': 'release_trybot_fuchsia',
       # TODO(kjellander): Remove linux_arm after tryserver restart.
       'linux_arm': 'release_trybot_arm',
       'linux_arm_dbg': 'debug_trybot_arm',
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 4b84fc45..559171073 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -15990,6 +15990,7 @@
   <int value="2063" label="PresentationRequestStartSecureOrigin"/>
   <int value="2064" label="PresentationRequestStartInsecureOrigin"/>
   <int value="2065" label="PersistentClientHintHeader"/>
+  <int value="2066" label="StyleSheetListNonNullAnonymousNamedGetter"/>
 </enum>
 
 <enum name="FeedbackSource">
diff --git a/ui/android/BUILD.gn b/ui/android/BUILD.gn
index 320df23e..ef0f1d70 100644
--- a/ui/android/BUILD.gn
+++ b/ui/android/BUILD.gn
@@ -34,15 +34,12 @@
     "resources/resource.cc",
     "resources/resource.h",
     "resources/resource_factory.cc",
-    "resources/resource_factory.h",
     "resources/resource_manager.h",
     "resources/resource_manager_impl.cc",
     "resources/resource_manager_impl.h",
     "resources/ui_resource_provider.h",
     "screen_android.h",
     "ui_android_export.h",
-    "ui_android_jni_registrar.cc",
-    "ui_android_jni_registrar.h",
     "view_android.cc",
     "view_android.h",
     "view_client.cc",
diff --git a/ui/android/delegated_frame_host_android.cc b/ui/android/delegated_frame_host_android.cc
index 0ed5c46c..cb8333f 100644
--- a/ui/android/delegated_frame_host_android.cc
+++ b/ui/android/delegated_frame_host_android.cc
@@ -65,7 +65,7 @@
   DCHECK(view_);
   DCHECK(client_);
 
-  frame_sink_manager_->surface_manager()->RegisterFrameSinkId(frame_sink_id_);
+  host_frame_sink_manager_->RegisterFrameSinkId(frame_sink_id_, this);
   CreateNewCompositorFrameSinkSupport();
 }
 
@@ -73,7 +73,7 @@
   DestroyDelegatedContent();
   DetachFromCompositor();
   support_.reset();
-  frame_sink_manager_->surface_manager()->InvalidateFrameSinkId(frame_sink_id_);
+  host_frame_sink_manager_->InvalidateFrameSinkId(frame_sink_id_);
 }
 
 void DelegatedFrameHostAndroid::SubmitCompositorFrame(
@@ -202,6 +202,12 @@
   support_->SetNeedsBeginFrame(needs_begin_frames);
 }
 
+void DelegatedFrameHostAndroid::OnSurfaceCreated(
+    const viz::SurfaceInfo& surface_info) {
+  // TODO(fsamuel): Once surface synchronization is turned on, the fallback
+  // surface should be set here.
+}
+
 void DelegatedFrameHostAndroid::CreateNewCompositorFrameSinkSupport() {
   constexpr bool is_root = false;
   constexpr bool handles_frame_sink_id_invalidation = false;
diff --git a/ui/android/delegated_frame_host_android.h b/ui/android/delegated_frame_host_android.h
index 6fd563a..75a18fd 100644
--- a/ui/android/delegated_frame_host_android.h
+++ b/ui/android/delegated_frame_host_android.h
@@ -10,6 +10,7 @@
 #include "components/viz/common/quads/copy_output_request.h"
 #include "components/viz/common/resources/returned_resource.h"
 #include "components/viz/common/surfaces/surface_info.h"
+#include "components/viz/host/host_frame_sink_client.h"
 #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
 #include "components/viz/service/frame_sinks/compositor_frame_sink_support_client.h"
 #include "ui/android/ui_android_export.h"
@@ -33,7 +34,8 @@
 
 class UI_ANDROID_EXPORT DelegatedFrameHostAndroid
     : public viz::CompositorFrameSinkSupportClient,
-      public viz::ExternalBeginFrameSourceClient {
+      public viz::ExternalBeginFrameSourceClient,
+      public viz::HostFrameSinkClient {
  public:
   class Client {
    public:
@@ -92,6 +94,9 @@
   // viz::ExternalBeginFrameSourceClient implementation.
   void OnNeedsBeginFrames(bool needs_begin_frames) override;
 
+  // viz::HostFrameSinkClient implementation.
+  void OnSurfaceCreated(const viz::SurfaceInfo& surface_info) override;
+
   void CreateNewCompositorFrameSinkSupport();
 
   const viz::FrameSinkId frame_sink_id_;
diff --git a/ui/android/display_android_manager.cc b/ui/android/display_android_manager.cc
index 4904bc8..8ea90a90 100644
--- a/ui/android/display_android_manager.cc
+++ b/ui/android/display_android_manager.cc
@@ -32,10 +32,6 @@
   Java_DisplayAndroidManager_onNativeSideCreated(env, (jlong)manager);
 }
 
-bool RegisterScreenAndroid(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 DisplayAndroidManager::DisplayAndroidManager() {}
 
 DisplayAndroidManager::~DisplayAndroidManager() {}
diff --git a/ui/android/event_forwarder.cc b/ui/android/event_forwarder.cc
index 0a19b41..4fdd3c894 100644
--- a/ui/android/event_forwarder.cc
+++ b/ui/android/event_forwarder.cc
@@ -161,8 +161,4 @@
   view_->OnDragEvent(event);
 }
 
-bool RegisterEventForwarder(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 }  // namespace ui
diff --git a/ui/android/event_forwarder.h b/ui/android/event_forwarder.h
index ddc02b9f..86cf413 100644
--- a/ui/android/event_forwarder.h
+++ b/ui/android/event_forwarder.h
@@ -93,8 +93,6 @@
   DISALLOW_COPY_AND_ASSIGN(EventForwarder);
 };
 
-bool RegisterEventForwarder(JNIEnv* env);
-
 }  // namespace ui
 
 #endif  // UI_ANDROID_EVENT_FORWARDER_H_
diff --git a/ui/android/resources/resource_factory.cc b/ui/android/resources/resource_factory.cc
index f6ffba329..1cbdde2 100644
--- a/ui/android/resources/resource_factory.cc
+++ b/ui/android/resources/resource_factory.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/android/resources/resource_factory.h"
-
 #include "jni/ResourceFactory_jni.h"
 #include "ui/android/resources/nine_patch_resource.h"
 #include "ui/gfx/geometry/rect.h"
@@ -12,10 +10,6 @@
 
 namespace ui {
 
-bool RegisterResourceFactory(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 jlong CreateBitmapResource(JNIEnv* env, const JavaParamRef<jclass>& clazz) {
   return reinterpret_cast<intptr_t>(new Resource());
 }
diff --git a/ui/android/resources/resource_factory.h b/ui/android/resources/resource_factory.h
deleted file mode 100644
index 670c290..0000000
--- a/ui/android/resources/resource_factory.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_ANDROID_RESOURCES_RESOURCE_FACTORY_H_
-#define UI_ANDROID_RESOURCES_RESOURCE_FACTORY_H_
-
-#include "base/android/jni_android.h"
-
-namespace ui {
-
-bool RegisterResourceFactory(JNIEnv* env);
-
-}  // namespace ui
-
-#endif  // UI_ANDROID_RESOURCES_RESOURCE_FACTORY_H_
diff --git a/ui/android/resources/resource_manager_impl.cc b/ui/android/resources/resource_manager_impl.cc
index c2d5cf9..c7c02d9 100644
--- a/ui/android/resources/resource_manager_impl.cc
+++ b/ui/android/resources/resource_manager_impl.cc
@@ -233,11 +233,6 @@
   return true;
 }
 
-// static
-bool ResourceManagerImpl::RegisterResourceManager(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 void ResourceManagerImpl::PreloadResourceFromJava(AndroidResourceType res_type,
                                                   int res_id) {
   TRACE_EVENT2("ui", "ResourceManagerImpl::PreloadResourceFromJava",
diff --git a/ui/android/resources/resource_manager_impl.h b/ui/android/resources/resource_manager_impl.h
index 4300787..9eb3998 100644
--- a/ui/android/resources/resource_manager_impl.h
+++ b/ui/android/resources/resource_manager_impl.h
@@ -58,8 +58,6 @@
   void ClearTintedResourceCache(JNIEnv* env,
       const base::android::JavaRef<jobject>& jobj);
 
-  static bool RegisterResourceManager(JNIEnv* env);
-
   // base::trace_event::MemoryDumpProvider implementation.
   bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
                     base::trace_event::ProcessMemoryDump* pmd) override;
diff --git a/ui/android/run_all_unittests.cc b/ui/android/run_all_unittests.cc
index f15eb51..f4419350 100644
--- a/ui/android/run_all_unittests.cc
+++ b/ui/android/run_all_unittests.cc
@@ -10,10 +10,8 @@
 #include "base/test/launcher/unit_test_launcher.h"
 #include "base/test/test_suite.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/android/ui_android_jni_registrar.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/ui_base_paths.h"
-#include "ui/gfx/android/gfx_jni_registrar.h"
 
 namespace {
 
@@ -25,9 +23,6 @@
   void Initialize() override {
     base::TestSuite::Initialize();
 
-    gfx::android::RegisterJni(base::android::AttachCurrentThread());
-    ui::RegisterUIAndroidJni(base::android::AttachCurrentThread());
-
     ui::RegisterPathProvider();
 
     base::FilePath ui_test_pak_path;
diff --git a/ui/android/screen_android.h b/ui/android/screen_android.h
index 4352c0e3..1482223 100644
--- a/ui/android/screen_android.h
+++ b/ui/android/screen_android.h
@@ -10,8 +10,6 @@
 
 namespace ui {
 
-bool RegisterScreenAndroid(JNIEnv* env);
-
 UI_ANDROID_EXPORT void SetScreenAndroid();
 
 }  // namespace display
diff --git a/ui/android/ui_android_jni_registrar.cc b/ui/android/ui_android_jni_registrar.cc
deleted file mode 100644
index 4bb189e..0000000
--- a/ui/android/ui_android_jni_registrar.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/android/ui_android_jni_registrar.h"
-
-#include "base/android/jni_android.h"
-#include "base/android/jni_registrar.h"
-#include "base/macros.h"
-#include "ui/android/event_forwarder.h"
-#include "ui/android/resources/resource_factory.h"
-#include "ui/android/resources/resource_manager_impl.h"
-#include "ui/android/screen_android.h"
-#include "ui/android/view_android.h"
-#include "ui/android/window_android.h"
-
-namespace ui {
-
-static base::android::RegistrationMethod kAndroidRegisteredMethods[] = {
-    {"DisplayAndroidManager", ui::RegisterScreenAndroid},
-    {"EventForwarder", ui::RegisterEventForwarder},
-    {"ResourceFactory", ui::RegisterResourceFactory},
-    {"ResourceManager", ui::ResourceManagerImpl::RegisterResourceManager},
-    {"WindowAndroid", WindowAndroid::RegisterWindowAndroid},
-};
-
-bool RegisterUIAndroidJni(JNIEnv* env) {
-  return RegisterNativeMethods(env, kAndroidRegisteredMethods,
-                               arraysize(kAndroidRegisteredMethods));
-}
-
-}  // namespace ui
diff --git a/ui/android/ui_android_jni_registrar.h b/ui/android/ui_android_jni_registrar.h
deleted file mode 100644
index b1a5fd61..0000000
--- a/ui/android/ui_android_jni_registrar.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_ANDROID_UI_ANDROID_JNI_REGISTRAR_H_
-#define UI_ANDROID_UI_ANDROID_JNI_REGISTRAR_H_
-
-#include <jni.h>
-
-#include "ui/android/ui_android_export.h"
-
-namespace ui {
-
-// Register all JNI bindings necessary for chrome.
-UI_ANDROID_EXPORT bool RegisterUIAndroidJni(JNIEnv* env);
-
-}  // namespace ui
-
-#endif  // UI_ANDROID_UI_ANDROID_JNI_REGISTRAR_H_
diff --git a/ui/android/window_android.cc b/ui/android/window_android.cc
index 843c4bd8..015d6dd 100644
--- a/ui/android/window_android.cc
+++ b/ui/android/window_android.cc
@@ -131,10 +131,6 @@
   return base::android::ScopedJavaLocalRef<jobject>(java_window_);
 }
 
-bool WindowAndroid::RegisterWindowAndroid(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 WindowAndroid::~WindowAndroid() {
   DCHECK(parent_ == nullptr) << "WindowAndroid must be a root view.";
   DCHECK(!compositor_);
diff --git a/ui/android/window_android.h b/ui/android/window_android.h
index 628b1b4..fa6e20a 100644
--- a/ui/android/window_android.h
+++ b/ui/android/window_android.h
@@ -44,8 +44,6 @@
 
   base::android::ScopedJavaLocalRef<jobject> GetJavaObject();
 
-  static bool RegisterWindowAndroid(JNIEnv* env);
-
   // Compositor callback relay.
   void OnCompositingDidCommit();
 
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
index 05c1e76..5fdd15f9 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -67,8 +67,6 @@
     "accelerators/platform_accelerator.h",
     "accelerators/platform_accelerator_cocoa.h",
     "accelerators/platform_accelerator_cocoa.mm",
-    "android/ui_base_jni_registrar.cc",
-    "android/ui_base_jni_registrar.h",
     "class_property.cc",
     "class_property.h",
     "clipboard/clipboard_android.cc",
diff --git a/ui/base/android/ui_base_jni_registrar.cc b/ui/base/android/ui_base_jni_registrar.cc
deleted file mode 100644
index 26343df..0000000
--- a/ui/base/android/ui_base_jni_registrar.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/android/ui_base_jni_registrar.h"
-
-#include "base/android/jni_android.h"
-#include "base/android/jni_registrar.h"
-#include "base/macros.h"
-#include "ui/base/clipboard/clipboard_android.h"
-#include "ui/base/l10n/l10n_util_android.h"
-
-namespace ui {
-namespace android {
-
-static base::android::RegistrationMethod kUiRegisteredMethods[] = {
-    {"LocalizationUtils", l10n_util::RegisterLocalizationUtil},
-    {"ClipboardAndroid", ui::RegisterClipboardAndroid},
-};
-
-bool RegisterJni(JNIEnv* env) {
-  return RegisterNativeMethods(env, kUiRegisteredMethods,
-                               arraysize(kUiRegisteredMethods));
-}
-
-}  // namespace android
-}  // namespace ui
diff --git a/ui/base/android/ui_base_jni_registrar.h b/ui/base/android/ui_base_jni_registrar.h
deleted file mode 100644
index 7540d918..0000000
--- a/ui/base/android/ui_base_jni_registrar.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_ANDROID_UI_BASE_JNI_REGISTRAR_H_
-#define UI_BASE_ANDROID_UI_BASE_JNI_REGISTRAR_H_
-
-#include <jni.h>
-
-#include "ui/base/ui_base_export.h"
-
-namespace ui {
-namespace android {
-
-// Register all JNI bindings necessary for chrome.
-UI_BASE_EXPORT bool RegisterJni(JNIEnv* env);
-
-}  // namespace android
-}  // namespace ui
-
-#endif  // UI_BASE_ANDROID_UI_BASE_JNI_REGISTRAR_H_
diff --git a/ui/base/clipboard/clipboard_android.cc b/ui/base/clipboard/clipboard_android.cc
index 849493e10..a151b99 100644
--- a/ui/base/clipboard/clipboard_android.cc
+++ b/ui/base/clipboard/clipboard_android.cc
@@ -550,10 +550,6 @@
   g_map.Get().Set(format.ToString(), std::string(data_data, data_len));
 }
 
-bool RegisterClipboardAndroid(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 // Returns a pointer to the current ClipboardAndroid object.
 static jlong Init(JNIEnv* env,
                   const base::android::JavaParamRef<jobject>& obj) {
diff --git a/ui/base/clipboard/clipboard_android.h b/ui/base/clipboard/clipboard_android.h
index 716cc387..1ef1bee9 100644
--- a/ui/base/clipboard/clipboard_android.h
+++ b/ui/base/clipboard/clipboard_android.h
@@ -87,9 +87,6 @@
   DISALLOW_COPY_AND_ASSIGN(ClipboardAndroid);
 };
 
-// Registers the ClipboardAndroid native method.
-bool RegisterClipboardAndroid(JNIEnv* env);
-
 }  // namespace ui
 
 #endif  // UI_BASE_CLIPBOARD_CLIPBOARD_ANDROID_H_
diff --git a/ui/base/l10n/l10n_util_android.cc b/ui/base/l10n/l10n_util_android.cc
index 5c7c12d57..6fa1f46 100644
--- a/ui/base/l10n/l10n_util_android.cc
+++ b/ui/base/l10n/l10n_util_android.cc
@@ -108,8 +108,4 @@
   return jtime_remaining;
 }
 
-bool RegisterLocalizationUtil(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 }  // namespace l10n_util
diff --git a/ui/base/l10n/l10n_util_android.h b/ui/base/l10n/l10n_util_android.h
index 3745ed6..38592e9 100644
--- a/ui/base/l10n/l10n_util_android.h
+++ b/ui/base/l10n/l10n_util_android.h
@@ -20,8 +20,6 @@
 
 UI_BASE_EXPORT bool IsLayoutRtl();
 
-UI_BASE_EXPORT bool RegisterLocalizationUtil(JNIEnv* env);
-
 }  // namespace l10n_util
 
 #endif  // UI_BASE_L10N_L10N_UTIL_ANDROID_H_
diff --git a/ui/base/resource/resource_bundle.cc b/ui/base/resource/resource_bundle.cc
index 372d330..4f82347 100644
--- a/ui/base/resource/resource_bundle.cc
+++ b/ui/base/resource/resource_bundle.cc
@@ -707,7 +707,7 @@
 }
 
 ScaleFactor ResourceBundle::GetMaxScaleFactor() const {
-#if defined(OS_CHROMEOS) || defined(OS_WIN) || defined(OS_LINUX)
+#if defined(OS_WIN) || defined(OS_LINUX)
   return max_scale_factor_;
 #else
   return GetSupportedScaleFactors().back();
@@ -762,8 +762,7 @@
   } else {
     supported_scale_factors.push_back(SCALE_FACTOR_100P);
   }
-#elif defined(OS_MACOSX) || defined(OS_CHROMEOS) || defined(OS_LINUX) || \
-    defined(OS_WIN)
+#elif defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_WIN)
   supported_scale_factors.push_back(SCALE_FACTOR_200P);
 #endif
   ui::SetSupportedScaleFactors(supported_scale_factors);
diff --git a/ui/base/test/run_all_unittests.cc b/ui/base/test/run_all_unittests.cc
index af412a3..2ee6100e 100644
--- a/ui/base/test/run_all_unittests.cc
+++ b/ui/base/test/run_all_unittests.cc
@@ -13,12 +13,6 @@
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/ui_base_paths.h"
 
-#if defined(OS_ANDROID)
-#include "base/android/jni_android.h"
-#include "ui/base/android/ui_base_jni_registrar.h"
-#include "ui/gfx/android/gfx_jni_registrar.h"
-#endif
-
 #if defined(OS_MACOSX) && !defined(OS_IOS)
 #include "base/mac/bundle_locations.h"
 #include "base/test/mock_chrome_application_mac.h"
@@ -53,12 +47,6 @@
   display::win::SetDefaultDeviceScaleFactor(1.0);
 #endif
 
-#if defined(OS_ANDROID)
-  // Register JNI bindings for android.
-  gfx::android::RegisterJni(base::android::AttachCurrentThread());
-  ui::android::RegisterJni(base::android::AttachCurrentThread());
-#endif
-
   ui::RegisterPathProvider();
 
   base::FilePath exe_path;
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc
index 534aff3..f0c8888 100644
--- a/ui/compositor/compositor.cc
+++ b/ui/compositor/compositor.cc
@@ -73,9 +73,9 @@
       weak_ptr_factory_(this),
       lock_timeout_weak_ptr_factory_(this) {
   if (context_factory_private) {
-    context_factory_private->GetFrameSinkManager()
-        ->surface_manager()
-        ->RegisterFrameSinkId(frame_sink_id_);
+    auto* host_frame_sink_manager =
+        context_factory_private_->GetHostFrameSinkManager();
+    host_frame_sink_manager->RegisterFrameSinkId(frame_sink_id_, this);
   }
   root_web_layer_ = cc::Layer::Create();
 
@@ -227,9 +227,7 @@
       host_frame_sink_manager->UnregisterFrameSinkHierarchy(frame_sink_id_,
                                                             client);
     }
-    context_factory_private_->GetFrameSinkManager()
-        ->surface_manager()
-        ->InvalidateFrameSinkId(frame_sink_id_);
+    host_frame_sink_manager->InvalidateFrameSinkId(frame_sink_id_);
   }
 }
 
@@ -552,6 +550,11 @@
     observer.OnCompositingStarted(this, start_time);
 }
 
+void Compositor::OnSurfaceCreated(const viz::SurfaceInfo& surface_info) {
+  // TODO(fsamuel): Once surface synchronization is turned on, the fallback
+  // surface should be set here.
+}
+
 void Compositor::SetOutputIsSecure(bool output_is_secure) {
   if (context_factory_private_)
     context_factory_private_->SetOutputIsSecure(this, output_is_secure);
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h
index 045351b..92ed6841 100644
--- a/ui/compositor/compositor.h
+++ b/ui/compositor/compositor.h
@@ -21,6 +21,7 @@
 #include "cc/trees/layer_tree_host_single_thread_client.h"
 #include "components/viz/common/frame_sinks/begin_frame_args.h"
 #include "components/viz/common/surfaces/surface_sequence.h"
+#include "components/viz/host/host_frame_sink_client.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/compositor/compositor_animation_observer.h"
 #include "ui/compositor/compositor_export.h"
@@ -185,7 +186,8 @@
 class COMPOSITOR_EXPORT Compositor
     : NON_EXPORTED_BASE(public cc::LayerTreeHostClient),
       NON_EXPORTED_BASE(public cc::LayerTreeHostSingleThreadClient),
-      NON_EXPORTED_BASE(public CompositorLockDelegate) {
+      NON_EXPORTED_BASE(public CompositorLockDelegate),
+      NON_EXPORTED_BASE(public viz::HostFrameSinkClient) {
  public:
   Compositor(const viz::FrameSinkId& frame_sink_id,
              ui::ContextFactory* context_factory,
@@ -381,6 +383,9 @@
   void DidSubmitCompositorFrame() override;
   void DidLoseLayerTreeFrameSink() override {}
 
+  // viz::HostFrameSinkClient implementation.
+  void OnSurfaceCreated(const viz::SurfaceInfo& surface_info) override;
+
   bool IsLocked() { return !active_locks_.empty(); }
 
   void SetOutputIsSecure(bool output_is_secure);
diff --git a/ui/events/devices/input_device_observer_android.cc b/ui/events/devices/input_device_observer_android.cc
index 3313b7fe..509234eb 100644
--- a/ui/events/devices/input_device_observer_android.cc
+++ b/ui/events/devices/input_device_observer_android.cc
@@ -19,10 +19,6 @@
 
 namespace ui {
 
-bool InputDeviceObserverAndroid::RegisterInputDeviceObserver(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 InputDeviceObserverAndroid::InputDeviceObserverAndroid() {}
 
 InputDeviceObserverAndroid::~InputDeviceObserverAndroid() {}
@@ -64,4 +60,4 @@
 NOTIFY_OBSERVERS(NotifyObserversKeyboardDeviceConfigurationChanged(),
                  OnKeyboardDeviceConfigurationChanged());
 
-}  // namespace ui
\ No newline at end of file
+}  // namespace ui
diff --git a/ui/events/devices/input_device_observer_android.h b/ui/events/devices/input_device_observer_android.h
index 311dfa82..b4d1be6 100644
--- a/ui/events/devices/input_device_observer_android.h
+++ b/ui/events/devices/input_device_observer_android.h
@@ -25,8 +25,6 @@
   static InputDeviceObserverAndroid* GetInstance();
   ~InputDeviceObserverAndroid();
 
-  static bool RegisterInputDeviceObserver(JNIEnv* env);
-
   void AddObserver(ui::InputDeviceEventObserver* observer);
   void RemoveObserver(ui::InputDeviceEventObserver* observer);
 
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn
index e579efd7..e6cb51a 100644
--- a/ui/gfx/BUILD.gn
+++ b/ui/gfx/BUILD.gn
@@ -44,8 +44,6 @@
 
 component("gfx") {
   sources = [
-    "android/gfx_jni_registrar.cc",
-    "android/gfx_jni_registrar.h",
     "android/java_bitmap.cc",
     "android/java_bitmap.h",
     "android/view_configuration.cc",
diff --git a/ui/gfx/android/gfx_jni_registrar.cc b/ui/gfx/android/gfx_jni_registrar.cc
deleted file mode 100644
index 97f06cf..0000000
--- a/ui/gfx/android/gfx_jni_registrar.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/android/gfx_jni_registrar.h"
-
-#include "base/android/jni_android.h"
-#include "base/android/jni_registrar.h"
-#include "base/macros.h"
-#include "ui/gfx/android/view_configuration.h"
-
-namespace gfx {
-namespace android {
-
-static base::android::RegistrationMethod kGfxRegisteredMethods[] = {
-  { "ViewConfiguration", ViewConfiguration::RegisterViewConfiguration }
-};
-
-bool RegisterJni(JNIEnv* env) {
-  return RegisterNativeMethods(env, kGfxRegisteredMethods,
-                               arraysize(kGfxRegisteredMethods));
-}
-
-}  // namespace android
-}  // namespace gfx
diff --git a/ui/gfx/android/gfx_jni_registrar.h b/ui/gfx/android/gfx_jni_registrar.h
deleted file mode 100644
index 3d4947c..0000000
--- a/ui/gfx/android/gfx_jni_registrar.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_ANDROID_GFX_JNI_REGISTRAR_H_
-#define UI_GFX_ANDROID_GFX_JNI_REGISTRAR_H_
-
-#include <jni.h>
-
-#include "ui/gfx/gfx_export.h"
-
-namespace gfx {
-namespace android {
-
-// Register all JNI bindings necessary for chrome.
-GFX_EXPORT bool RegisterJni(JNIEnv* env);
-
-}  // namespace android
-}  // namespace gfx
-
-#endif  // UI_GFX_ANDROID_GFX_JNI_REGISTRAR_H_
diff --git a/ui/gfx/android/view_configuration.cc b/ui/gfx/android/view_configuration.cc
index a79f0f92..11fe458 100644
--- a/ui/gfx/android/view_configuration.cc
+++ b/ui/gfx/android/view_configuration.cc
@@ -175,8 +175,4 @@
   return g_view_configuration.Get().min_scaling_span_in_dips();
 }
 
-bool ViewConfiguration::RegisterViewConfiguration(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 }  // namespace gfx
diff --git a/ui/gfx/android/view_configuration.h b/ui/gfx/android/view_configuration.h
index 4495a5e..e7353de3 100644
--- a/ui/gfx/android/view_configuration.h
+++ b/ui/gfx/android/view_configuration.h
@@ -26,9 +26,6 @@
   static int GetDoubleTapSlopInDips();
 
   static int GetMinScalingSpanInDips();
-
-  // Registers methods with JNI and returns true if succeeded.
-  static bool RegisterViewConfiguration(JNIEnv* env);
 };
 
 }  // namespace gfx
diff --git a/ui/gfx/font_render_params.h b/ui/gfx/font_render_params.h
index ade3672..39d72e3 100644
--- a/ui/gfx/font_render_params.h
+++ b/ui/gfx/font_render_params.h
@@ -113,8 +113,7 @@
 GFX_EXPORT void ClearFontRenderParamsCacheForTest();
 #endif
 
-#if defined(OS_CHROMEOS) || defined(OS_LINUX) || \
-    (defined(OS_ANDROID) && BUILDFLAG(ENABLE_VR))
+#if defined(OS_LINUX) || (defined(OS_ANDROID) && BUILDFLAG(ENABLE_VR))
 // Gets the device scale factor to query the FontRenderParams.
 GFX_EXPORT float GetFontRenderParamsDeviceScaleFactor();
 
diff --git a/ui/gfx/test/run_all_unittests.cc b/ui/gfx/test/run_all_unittests.cc
index 65e1f9a..d814238 100644
--- a/ui/gfx/test/run_all_unittests.cc
+++ b/ui/gfx/test/run_all_unittests.cc
@@ -13,11 +13,6 @@
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/ui_base_paths.h"
 
-#if defined(OS_ANDROID)
-#include "base/android/jni_android.h"
-#include "ui/gfx/android/gfx_jni_registrar.h"
-#endif
-
 #if defined(OS_MACOSX) && !defined(OS_IOS)
 #include "base/test/mock_chrome_application_mac.h"
 #endif
@@ -46,10 +41,6 @@
   void Initialize() override {
     base::TestSuite::Initialize();
 
-#if defined(OS_ANDROID)
-    gfx::android::RegisterJni(base::android::AttachCurrentThread());
-#endif
-
 #if defined(OS_MACOSX) && !defined(OS_IOS)
     mock_cr_app::RegisterMockCrApp();
 #endif
diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn
index e2dac179..141f1f6 100644
--- a/ui/gl/BUILD.gn
+++ b/ui/gl/BUILD.gn
@@ -45,8 +45,6 @@
   output_name = "gl_wrapper"  # Avoid colliding with OS X"s libGL.dylib.
 
   sources = [
-    "android/gl_jni_registrar.cc",
-    "android/gl_jni_registrar.h",
     "android/scoped_java_surface.cc",
     "android/scoped_java_surface.h",
     "android/surface_texture.cc",
diff --git a/ui/gl/android/gl_jni_registrar.cc b/ui/gl/android/gl_jni_registrar.cc
deleted file mode 100644
index a21a619..0000000
--- a/ui/gl/android/gl_jni_registrar.cc
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gl/android/gl_jni_registrar.h"
-
-#include "base/android/jni_android.h"
-#include "base/android/jni_registrar.h"
-#include "base/macros.h"
-#include "ui/gl/android/surface_texture_listener.h"
-
-namespace ui {
-namespace gl {
-namespace android {
-
-static base::android::RegistrationMethod kGLRegisteredMethods[] = {
-    {"SurfaceTextureListener",
-     ::gl::SurfaceTextureListener::RegisterSurfaceTextureListener},
-};
-
-bool RegisterJni(JNIEnv* env) {
-  return RegisterNativeMethods(env, kGLRegisteredMethods,
-                               arraysize(kGLRegisteredMethods));
-}
-
-}  // namespace android
-}  // namespace gl
-}  // namespace ui
diff --git a/ui/gl/android/gl_jni_registrar.h b/ui/gl/android/gl_jni_registrar.h
deleted file mode 100644
index 3f028b7..0000000
--- a/ui/gl/android/gl_jni_registrar.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GL_ANDROID_GL_JNI_REGISTRAR_H_
-#define UI_GL_ANDROID_GL_JNI_REGISTRAR_H_
-
-#include <jni.h>
-
-#include "ui/gl/gl_export.h"
-
-namespace ui {
-namespace gl {
-namespace android {
-
-// Register all JNI bindings necessary for chrome.
-GL_EXPORT bool RegisterJni(JNIEnv* env);
-
-}  // namespace android
-}  // namespace gl
-}  // namespace ui
-
-#endif  // UI_GL_ANDROID_GL_JNI_REGISTRAR_H_
diff --git a/ui/gl/android/surface_texture_listener.cc b/ui/gl/android/surface_texture_listener.cc
index 5b2c713..091facc 100644
--- a/ui/gl/android/surface_texture_listener.cc
+++ b/ui/gl/android/surface_texture_listener.cc
@@ -38,9 +38,4 @@
   }
 }
 
-// static
-bool SurfaceTextureListener::RegisterSurfaceTextureListener(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 }  // namespace gl
diff --git a/ui/gl/android/surface_texture_listener.h b/ui/gl/android/surface_texture_listener.h
index 6e2080d..d022185 100644
--- a/ui/gl/android/surface_texture_listener.h
+++ b/ui/gl/android/surface_texture_listener.h
@@ -30,8 +30,6 @@
   void FrameAvailable(JNIEnv* env,
                       const base::android::JavaParamRef<jobject>& obj);
 
-  static bool RegisterSurfaceTextureListener(JNIEnv* env);
-
  private:
   friend class base::DeleteHelper<SurfaceTextureListener>;
 
diff --git a/ui/platform_window/android/platform_ime_controller_android.cc b/ui/platform_window/android/platform_ime_controller_android.cc
index d9e0edfb..99cf38f 100644
--- a/ui/platform_window/android/platform_ime_controller_android.cc
+++ b/ui/platform_window/android/platform_ime_controller_android.cc
@@ -13,11 +13,6 @@
 
 namespace ui {
 
-// static
-bool PlatformImeControllerAndroid::Register(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 PlatformImeControllerAndroid::PlatformImeControllerAndroid() {
 }
 
diff --git a/ui/platform_window/android/platform_ime_controller_android.h b/ui/platform_window/android/platform_ime_controller_android.h
index 69d9682..ed47c62 100644
--- a/ui/platform_window/android/platform_ime_controller_android.h
+++ b/ui/platform_window/android/platform_ime_controller_android.h
@@ -15,8 +15,6 @@
 class ANDROID_WINDOW_EXPORT PlatformImeControllerAndroid :
     public PlatformImeController {
  public:
-  static bool Register(JNIEnv* env);
-
   PlatformImeControllerAndroid();
   ~PlatformImeControllerAndroid() override;
 
diff --git a/ui/platform_window/android/platform_window_android.cc b/ui/platform_window/android/platform_window_android.cc
index 97bb914..c32b24a3 100644
--- a/ui/platform_window/android/platform_window_android.cc
+++ b/ui/platform_window/android/platform_window_android.cc
@@ -49,11 +49,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 // PlatformWindowAndroid, public:
 
-// static
-bool PlatformWindowAndroid::Register(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 PlatformWindowAndroid::PlatformWindowAndroid(PlatformWindowDelegate* delegate)
     : delegate_(delegate),
       window_(NULL),
diff --git a/ui/platform_window/android/platform_window_android.h b/ui/platform_window/android/platform_window_android.h
index 6ae0681..599ff718 100644
--- a/ui/platform_window/android/platform_window_android.h
+++ b/ui/platform_window/android/platform_window_android.h
@@ -24,8 +24,6 @@
 
 class ANDROID_WINDOW_EXPORT PlatformWindowAndroid : public PlatformWindow {
  public:
-  static bool Register(JNIEnv* env);
-
   explicit PlatformWindowAndroid(PlatformWindowDelegate* delegate);
   ~PlatformWindowAndroid() override;
 
diff --git a/ui/shell_dialogs/BUILD.gn b/ui/shell_dialogs/BUILD.gn
index 505bf26e..c3d9a05 100644
--- a/ui/shell_dialogs/BUILD.gn
+++ b/ui/shell_dialogs/BUILD.gn
@@ -51,8 +51,6 @@
 
   if (is_android && !use_aura) {
     sources += [
-      "android/shell_dialogs_jni_registrar.cc",
-      "android/shell_dialogs_jni_registrar.h",
       "select_file_dialog_android.cc",
       "select_file_dialog_android.h",
     ]
diff --git a/ui/shell_dialogs/android/shell_dialogs_jni_registrar.cc b/ui/shell_dialogs/android/shell_dialogs_jni_registrar.cc
deleted file mode 100644
index 6cdb835..0000000
--- a/ui/shell_dialogs/android/shell_dialogs_jni_registrar.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/shell_dialogs/android/shell_dialogs_jni_registrar.h"
-
-#include "base/android/jni_android.h"
-#include "base/android/jni_registrar.h"
-#include "base/macros.h"
-#include "ui/shell_dialogs/select_file_dialog_android.h"
-
-namespace ui {
-namespace shell_dialogs {
-
-static base::android::RegistrationMethod kUiRegisteredMethods[] = {
-  { "SelectFileDialog", ui::SelectFileDialogImpl::RegisterSelectFileDialog },
-};
-
-bool RegisterJni(JNIEnv* env) {
-  return RegisterNativeMethods(env, kUiRegisteredMethods,
-                               arraysize(kUiRegisteredMethods));
-}
-
-}  // namespace shell_dialogs
-}  // namespace ui
diff --git a/ui/shell_dialogs/android/shell_dialogs_jni_registrar.h b/ui/shell_dialogs/android/shell_dialogs_jni_registrar.h
deleted file mode 100644
index 5975080..0000000
--- a/ui/shell_dialogs/android/shell_dialogs_jni_registrar.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_SHELL_DIALOGS_ANDROID_UI_SHELL_DIALOGS_JNI_REGISTRAR_H_
-#define UI_SHELL_DIALOGS_ANDROID_UI_SHELL_DIALOGS_JNI_REGISTRAR_H_
-
-#include <jni.h>
-
-#include "ui/shell_dialogs/shell_dialogs_export.h"
-
-namespace ui {
-namespace shell_dialogs {
-
-// Register all JNI bindings necessary for chrome.
-SHELL_DIALOGS_EXPORT bool RegisterJni(JNIEnv* env);
-
-}  // namespace shell_dialogs
-}  // namespace ui
-
-#endif  // UI_SHELL_DIALOGS_ANDROID_UI_SHELL_DIALOGS_JNI_REGISTRAR_H_
diff --git a/ui/shell_dialogs/select_file_dialog_android.cc b/ui/shell_dialogs/select_file_dialog_android.cc
index 30c557d7..53ffb82 100644
--- a/ui/shell_dialogs/select_file_dialog_android.cc
+++ b/ui/shell_dialogs/select_file_dialog_android.cc
@@ -125,10 +125,6 @@
                                    owning_window->GetJavaObject());
 }
 
-bool SelectFileDialogImpl::RegisterSelectFileDialog(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 SelectFileDialogImpl::~SelectFileDialogImpl() {
 }
 
diff --git a/ui/shell_dialogs/select_file_dialog_android.h b/ui/shell_dialogs/select_file_dialog_android.h
index 5291cd3..d9b36b3 100644
--- a/ui/shell_dialogs/select_file_dialog_android.h
+++ b/ui/shell_dialogs/select_file_dialog_android.h
@@ -50,8 +50,6 @@
                       gfx::NativeWindow owning_window,
                       void* params) override;
 
-  static bool RegisterSelectFileDialog(JNIEnv* env);
-
  protected:
   ~SelectFileDialogImpl() override;
 
diff --git a/ui/views/view.cc b/ui/views/view.cc
index 19b9a6d9..7738915 100644
--- a/ui/views/view.cc
+++ b/ui/views/view.cc
@@ -2620,15 +2620,6 @@
   OnThemeChanged();
 }
 
-void View::PropagateLocaleChanged() {
-  {
-    internal::ScopedChildrenLock lock(this);
-    for (auto* child : base::Reversed(children_))
-      child->PropagateLocaleChanged();
-  }
-  OnLocaleChanged();
-}
-
 void View::PropagateDeviceScaleFactorChanged(float device_scale_factor) {
   {
     internal::ScopedChildrenLock lock(this);
diff --git a/ui/views/view.h b/ui/views/view.h
index 7a8a7b32..120cb40 100644
--- a/ui/views/view.h
+++ b/ui/views/view.h
@@ -1235,11 +1235,6 @@
   // Widget::ThemeChanged().
   virtual void OnThemeChanged() {}
 
-  // Called when the locale has changed, overriding allows individual Views to
-  // update locale-dependent strings.
-  // To dispatch a locale changed notification, call Widget::LocaleChanged().
-  virtual void OnLocaleChanged() {}
-
   // Tooltips ------------------------------------------------------------------
 
   // Views must invoke this when the tooltip text they are to display changes.
@@ -1525,10 +1520,6 @@
   // views in the hierarchy.
   void PropagateThemeChanged();
 
-  // Used to propagate locale changed notifications from the root view to all
-  // views in the hierarchy.
-  void PropagateLocaleChanged();
-
   // Used to propagate device scale factor changed notifications from the root
   // view to all views in the hierarchy.
   void PropagateDeviceScaleFactorChanged(float device_scale_factor);
diff --git a/ui/views/widget/root_view.cc b/ui/views/widget/root_view.cc
index 37e54bdf..52d55bd5 100644
--- a/ui/views/widget/root_view.cc
+++ b/ui/views/widget/root_view.cc
@@ -219,10 +219,6 @@
   View::PropagateThemeChanged();
 }
 
-void RootView::LocaleChanged() {
-  View::PropagateLocaleChanged();
-}
-
 void RootView::DeviceScaleFactorChanged(float device_scale_factor) {
   View::PropagateDeviceScaleFactorChanged(device_scale_factor);
 }
diff --git a/ui/views/widget/root_view.h b/ui/views/widget/root_view.h
index d8212a24..b119443 100644
--- a/ui/views/widget/root_view.h
+++ b/ui/views/widget/root_view.h
@@ -83,10 +83,6 @@
   // hierarchy.
   void ThemeChanged();
 
-  // Public API for broadcasting locale change notifications to this View
-  // hierarchy.
-  void LocaleChanged();
-
   // Public API for broadcasting device scale factor change notifications to
   // this View hierarchy.
   void DeviceScaleFactorChanged(float device_scale_factor);
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc
index 32a50e88..6e65021c 100644
--- a/ui/views/widget/widget.cc
+++ b/ui/views/widget/widget.cc
@@ -857,10 +857,6 @@
   root_view_->ThemeChanged();
 }
 
-void Widget::LocaleChanged() {
-  root_view_->LocaleChanged();
-}
-
 void Widget::DeviceScaleFactorChanged(float device_scale_factor) {
   root_view_->DeviceScaleFactorChanged(device_scale_factor);
 }
diff --git a/ui/views/widget/widget.h b/ui/views/widget/widget.h
index 63fcb9d6..c84057c 100644
--- a/ui/views/widget/widget.h
+++ b/ui/views/widget/widget.h
@@ -641,10 +641,6 @@
   // changed.
   void ThemeChanged();
 
-  // Notifies the view hierarchy contained in this widget that locale resources
-  // changed.
-  void LocaleChanged();
-
   // Notifies the view hierarchy contained in this widget that the device scale
   // factor changed.
   void DeviceScaleFactorChanged(float device_scale_factor);