diff --git a/DEPS b/DEPS
index 653354c9..c778604b 100644
--- a/DEPS
+++ b/DEPS
@@ -39,11 +39,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': 'f469fc0e0f04197f19c94c26801ba6888c6329dc',
+  'skia_revision': 'e9759286e8eb3a0ce00923bf9462818bc67cd9f8',
   # 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': 'd394e9b9635c49008a48c66fb5c4f1aa31084d09',
+  'v8_revision': '8ee0ef529bc0f5b171bfb92fa76051ca9a6f63b5',
   # 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/WATCHLISTS b/WATCHLISTS
index b0f8e55..385b1f94 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -1227,6 +1227,7 @@
                  'rouslan+autofill@chromium.org'],
     'automation': ['robertshield@chromium.org'],
     'background_sync': ['jkarlin+watch@chromium.org'],
+    'base': ['vmpstr+watch@chromium.org'],
     'base_allocator': ['dmikurube@chromium.org',
                        'wfh+watch@chromium.org'],
     'base_memory': ['gavinp+memory@chromium.org'],
@@ -1559,6 +1560,7 @@
                                  'dongseong.hwang@intel.com',
                                  'drott+blinkwatch@chromium.org',
                                  'junov@chromium.org',
+                                 'vmpstr+blinkwatch@chromium.org',
                                  'blink-reviews-platform-graphics@chromium.org' ],
     'blink_heap': [ 'ager@chromium.org',
                     'haraken@chromium.org',
diff --git a/android_webview/native/aw_web_contents_delegate.cc b/android_webview/native/aw_web_contents_delegate.cc
index e2a0b39d..55170f0 100644
--- a/android_webview/native/aw_web_contents_delegate.cc
+++ b/android_webview/native/aw_web_contents_delegate.cc
@@ -19,6 +19,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/file_chooser_file_info.h"
 #include "content/public/common/file_chooser_params.h"
@@ -237,14 +238,14 @@
     content::WebContents* web_contents, const GURL& origin) {
   WebContentsDelegateAndroid::EnterFullscreenModeForTab(web_contents, origin);
   is_fullscreen_ = true;
-  web_contents->GetRenderViewHost()->WasResized();
+  web_contents->GetRenderViewHost()->GetWidget()->WasResized();
 }
 
 void AwWebContentsDelegate::ExitFullscreenModeForTab(
     content::WebContents* web_contents) {
   WebContentsDelegateAndroid::ExitFullscreenModeForTab(web_contents);
   is_fullscreen_ = false;
-  web_contents->GetRenderViewHost()->WasResized();
+  web_contents->GetRenderViewHost()->GetWidget()->WasResized();
 }
 
 bool AwWebContentsDelegate::IsFullscreenForTabOrPending(
diff --git a/base/threading/post_task_and_reply_impl.cc b/base/threading/post_task_and_reply_impl.cc
index f3e88ab..80ca520 100644
--- a/base/threading/post_task_and_reply_impl.cc
+++ b/base/threading/post_task_and_reply_impl.cc
@@ -75,6 +75,9 @@
     const tracked_objects::Location& from_here,
     const Closure& task,
     const Closure& reply) {
+  // TODO(tzik): Use DCHECK here once the crash is gone. http://crbug.com/541319
+  CHECK(!task.is_null()) << from_here.ToString();
+  CHECK(!reply.is_null()) << from_here.ToString();
   PostTaskAndReplyRelay* relay =
       new PostTaskAndReplyRelay(from_here, task, reply);
   if (!PostTask(from_here, Bind(&PostTaskAndReplyRelay::Run,
diff --git a/base/trace_event/process_memory_dump.cc b/base/trace_event/process_memory_dump.cc
index 0ec007e..fab111f 100644
--- a/base/trace_event/process_memory_dump.cc
+++ b/base/trace_event/process_memory_dump.cc
@@ -43,6 +43,7 @@
   const size_t kMaxChunkSize = 32 * 1024 * 1024;
   size_t offset = 0;
   size_t total_resident_size = 0;
+  int result = 0;
   while (offset < mapped_size) {
     void* chunk_start = reinterpret_cast<void*>(start_pointer + offset);
     const size_t chunk_size = std::min(mapped_size - offset, kMaxChunkSize);
@@ -51,14 +52,23 @@
 
 #if defined(OS_MACOSX) || defined(OS_IOS)
     std::vector<char> vec(page_count + 1);
-    int res = mincore(chunk_start, chunk_size, vector_as_array(&vec));
-    DCHECK(!res);
+    // mincore in MAC does not fail with EAGAIN.
+    result = mincore(chunk_start, chunk_size, vector_as_array(&vec));
+    if (result)
+      break;
+
     for (size_t i = 0; i < page_count; i++)
       resident_page_count += vec[i] & MINCORE_INCORE ? 1 : 0;
 #else   // defined(OS_MACOSX) || defined(OS_IOS)
     std::vector<unsigned char> vec(page_count + 1);
-    int res = mincore(chunk_start, chunk_size, vector_as_array(&vec));
-    DCHECK(!res);
+    int error_counter = 0;
+    // HANDLE_EINTR tries for 100 times. So following the same pattern.
+    do {
+      result = mincore(chunk_start, chunk_size, vector_as_array(&vec));
+    } while (result == -1 && errno == EAGAIN && error_counter++ < 100);
+    if (result)
+      break;
+
     for (size_t i = 0; i < page_count; i++)
       resident_page_count += vec[i];
 #endif  // defined(OS_MACOSX) || defined(OS_IOS)
@@ -66,6 +76,12 @@
     total_resident_size += resident_page_count * page_size;
     offset += kMaxChunkSize;
   }
+
+  DCHECK_EQ(0, result);
+  if (result) {
+    total_resident_size = 0;
+    LOG(ERROR) << "mincore() call failed. The resident size is invalid";
+  }
   return total_resident_size;
 }
 #endif  // defined(COUNT_RESIDENT_BYTES_SUPPORTED)
diff --git a/blimp/engine/BUILD.gn b/blimp/engine/BUILD.gn
index 91ea226..7009257b 100644
--- a/blimp/engine/BUILD.gn
+++ b/blimp/engine/BUILD.gn
@@ -60,6 +60,11 @@
     data_deps = [
       ":blimp_engine_app",
       ":pak",
+      "//sandbox/linux:chrome_sandbox",
+
+      # TODO(maniscalco): Get rid of osmesa once we no longer depend on X
+      # (crbug.com/540932, crbug.com/541203).
+      "//third_party/mesa:osmesa",
     ]
   }
 
diff --git a/blimp/engine/Dockerfile b/blimp/engine/Dockerfile
index 766193c..c5ea7a3d 100644
--- a/blimp/engine/Dockerfile
+++ b/blimp/engine/Dockerfile
@@ -1,5 +1,7 @@
 FROM ubuntu:trusty
 
+# TODO(maniscalco): Remove X related packages once we no longer depend on X
+# (crbug.com/540932).
 RUN apt-get update && \
   apt-get install -yq libasound2 libatk1.0-0 libavahi-client3 libavahi-common3 \
   libcairo2 libcups2 libdatrie1 libdbus-glib-1-2 libffi6 libfontconfig1 \
@@ -15,9 +17,17 @@
 RUN useradd -ms /bin/bash blimp_user
 
 ADD * /engine/
+RUN mv /engine/chrome_sandbox /engine/chrome-sandbox
 RUN chown -R blimp_user /engine
 
 USER blimp_user
 WORKDIR "/engine"
-ENTRYPOINT [ "/usr/bin/xvfb-run", "--server-args=-screen 0 1600x1200x24", \
-  "./content_shell", "--no-sandbox" ]
+
+# Invoke xvfb-run using a shell command string to work around a bug where
+# xvfb-run fails to invoke the engine and hangs.
+#
+# TODO(maniscalco): Once we no longer depend on X, stop using the shell command
+# string, xvfb-run, and the use-gl flag. (crbug.com/540932, crbug.com/541203).
+ENTRYPOINT ["/bin/sh", "-c", \
+  "/usr/bin/xvfb-run -a /engine/blimp_engine_app --use-gl=osmesa $@", \
+  "/usr/bin/xvfb-run"]
diff --git a/blimp/engine/engine-manifest.txt b/blimp/engine/engine-manifest.txt
index 80eaf98..a5dcbf4 100644
--- a/blimp/engine/engine-manifest.txt
+++ b/blimp/engine/engine-manifest.txt
@@ -9,3 +9,5 @@
 natives_blob.bin
 snapshot_blob.bin
 blimp_engine.pak
+./chrome_sandbox
+./libosmesa.so
diff --git a/build/all.gyp b/build/all.gyp
index 8eabf88b..c87fc2d6 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -498,7 +498,7 @@
   ],
   'conditions': [
     # TODO(GYP): make gn_migration.gypi work unconditionally.
-    ['OS=="mac" or OS=="win" or (OS=="linux" and target_arch=="x64" and chromecast==0)', {
+    ['OS=="mac" or OS=="win" or (OS=="android" and chromecast==0) or (OS=="linux" and target_arch=="x64" and chromecast==0)', {
       'includes': [
         'gn_migration.gypi',
       ],
diff --git a/build/android/pylib/local/device/local_device_test_run.py b/build/android/pylib/local/device/local_device_test_run.py
index 0b45850..200ee4e 100644
--- a/build/android/pylib/local/device/local_device_test_run.py
+++ b/build/android/pylib/local/device/local_device_test_run.py
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import fnmatch
 import functools
 import logging
 
@@ -114,7 +115,15 @@
           all_fail_results[result.GetName()] = result
 
       results_names = set(r.GetName() for r in results.GetAll())
-      tests = [t for t in tests if self._GetTestName(t) not in results_names]
+
+      def has_test_result(name):
+        # When specifying a test filter, names can contain trailing wildcards.
+        # See local_device_gtest_run._ExtractTestsFromFilter()
+        if name.endswith('*'):
+          return any(fnmatch.fnmatch(n, name) for n in results_names)
+        return name in results_names
+
+      tests = [t for t in tests if not has_test_result(self._GetTestName(t))]
       tries += 1
       logging.info('FINISHED TRY #%d/%d', tries, self._env.max_tries)
       if tests:
diff --git a/build/android/pylib/perf/test_runner.py b/build/android/pylib/perf/test_runner.py
index 26e17add..6beb117 100644
--- a/build/android/pylib/perf/test_runner.py
+++ b/build/android/pylib/perf/test_runner.py
@@ -392,6 +392,21 @@
                  test_name, exit_code, end_time - start_time,
                  self.device_serial)
 
+    try:
+      # Some perf configs run the same benchmark with different options on
+      # different step names. Here we disambiguate those, so that data is
+      # uploaded to the perf dashoards based on their step name instead.
+      chart_data = json.loads(json_output)
+      if chart_data['benchmark_name'] != test_name:
+        logging.info('Benchmark %r will be reported as %r in chartjson.',
+                     chart_data['benchmark_name'], test_name)
+        chart_data['telemetry_benchmark_name'] = chart_data['benchmark_name']
+        chart_data['benchmark_name'] = test_name
+        json_output = json.dumps(chart_data, sort_keys=True, indent=2,
+                                 separators=(',', ': '))
+    except StandardError:
+      logging.exception('Could not read data from chartjson.')
+
     if exit_code == 0:
       result_type = base_test_result.ResultType.PASS
     else:
diff --git a/build/gn_migration.gypi b/build/gn_migration.gypi
index 0d5a7a5..6ce0cd4 100644
--- a/build/gn_migration.gypi
+++ b/build/gn_migration.gypi
@@ -37,25 +37,12 @@
         '../base/base.gyp:base_i18n_perftests',
         '../base/base.gyp:base_perftests',
         '../base/base.gyp:base_unittests',
-        '../base/base.gyp:build_utf8_validator_tables#host',
         '../base/base.gyp:check_example',
         '../cc/cc_tests.gyp:cc_perftests',
         '../cc/cc_tests.gyp:cc_unittests',
         '../cc/blink/cc_blink_tests.gyp:cc_blink_unittests',
-        '../chrome/chrome.gyp:chrome',
-        '../chrome/chrome.gyp:browser_tests',
-        '../chrome/chrome.gyp:chrome_app_unittests',
-        '../chrome/chrome.gyp:chromedriver',
-        '../chrome/chrome.gyp:chromedriver_tests',
-        '../chrome/chrome.gyp:chromedriver_unittests',
-        '../chrome/chrome.gyp:interactive_ui_tests',
         '../chrome/chrome.gyp:load_library_perf_tests',
-        '../chrome/chrome.gyp:performance_browser_tests',
-        '../chrome/chrome.gyp:sync_integration_tests',
-        '../chrome/chrome.gyp:sync_performance_tests',
         '../chrome/chrome.gyp:unit_tests',
-        '../chrome/tools/profile_reset/jtl_compiler.gyp:jtl_compiler',
-        '../cloud_print/cloud_print.gyp:cloud_print_unittests',
         '../components/components.gyp:network_hints_browser',
         '../components/components.gyp:policy_templates',
         '../components/components_tests.gyp:components_browsertests',
@@ -67,144 +54,45 @@
         '../content/content_shell_and_tests.gyp:content_gl_benchmark',
         '../content/content_shell_and_tests.gyp:content_gl_tests',
         '../content/content_shell_and_tests.gyp:content_perftests',
-        '../content/content_shell_and_tests.gyp:content_shell',
         '../content/content_shell_and_tests.gyp:content_unittests',
-        '../courgette/courgette.gyp:courgette',
-        '../courgette/courgette.gyp:courgette_fuzz',
-        '../courgette/courgette.gyp:courgette_minimal_tool',
-        '../courgette/courgette.gyp:courgette_unittests',
         '../crypto/crypto.gyp:crypto_unittests',
-        '../extensions/extensions_tests.gyp:extensions_browsertests',
-        '../extensions/extensions_tests.gyp:extensions_unittests',
         '../device/device_tests.gyp:device_unittests',
         '../gin/gin.gyp:gin_v8_snapshot_fingerprint',
-        '../gin/gin.gyp:gin_shell',
-        '../gin/gin.gyp:gin_unittests',
-        '../google_apis/gcm/gcm.gyp:gcm_unit_tests',
-        '../google_apis/gcm/gcm.gyp:mcs_probe',
-        '../google_apis/google_apis.gyp:google_apis_unittests',
         '../gpu/gpu.gyp:angle_unittests',
         '../gpu/gpu.gyp:gl_tests',
         '../gpu/gpu.gyp:gpu_perftests',
         '../gpu/gpu.gyp:gpu_unittests',
-        '../gpu/gles2_conform_support/gles2_conform_support.gyp:gles2_conform_support',  # TODO(GYP) crbug.com/471920
-        '../gpu/gles2_conform_support/gles2_conform_test.gyp:gles2_conform_test',  # TODO(GYP) crbug.com/471920
-        '../gpu/khronos_glcts_support/khronos_glcts_test.gyp:khronos_glcts_test',  # TODO(GYP) crbug.com/471903 to make this complete.
-        '../ipc/ipc.gyp:ipc_perftests',
         '../ipc/ipc.gyp:ipc_tests',
         '../ipc/mojo/ipc_mojo.gyp:ipc_mojo_unittests',
-        '../jingle/jingle.gyp:jingle_unittests',
-        '../media/media.gyp:ffmpeg_regression_tests',  # TODO(GYP) this should be conditional on media_use_ffmpeg
         '../media/media.gyp:media_perftests',
         '../media/media.gyp:media_unittests',
         '../media/midi/midi.gyp:midi_unittests',
-        '../media/cast/cast.gyp:cast_benchmarks',
-        '../media/cast/cast.gyp:cast_unittests',
-        '../media/cast/cast.gyp:generate_barcode_video',
-        '../media/cast/cast.gyp:generate_timecode_audio',
-        '../mojo/mojo.gyp:mojo',
         '../mojo/mojo_base.gyp:mojo_application_base',
-        '../mojo/mojo_base.gyp:mojo_common_unittests',
-        '../net/net.gyp:crash_cache',
-        '../net/net.gyp:crl_set_dump',
-        '../net/net.gyp:dns_fuzz_stub',
         '../net/net.gyp:dump_cache',
-        '../net/net.gyp:gdig',
-        '../net/net.gyp:get_server_time',
-        '../net/net.gyp:hpack_example_generator',
-        '../net/net.gyp:hpack_fuzz_mutator',
-        '../net/net.gyp:hpack_fuzz_wrapper',
         '../net/net.gyp:net_perftests',
         '../net/net.gyp:net_unittests',
-        '../net/net.gyp:net_watcher',  # TODO(GYP): This should be conditional on use_v8_in_net
-        '../net/net.gyp:run_testserver',
-        '../net/net.gyp:stress_cache',
-        '../net/net.gyp:tld_cleanup',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_audio',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_audio_input',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_c_stub',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_cc_stub',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_compositor',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_crxfs',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_enumerate_devices',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_file_chooser',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_flash_topmost',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_gamepad',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_gles2',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_gles2_spinning_cube',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_graphics_2d',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_ime',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_input',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_media_stream_audio',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_media_stream_video',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_mouse_cursor',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_mouse_lock',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_paint_manager',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_post_message',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_printing',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_scaling',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_scroll',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_simple_font',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_threading',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_url_loader',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_url_loader_file',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_vc',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_video_decode',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_video_decode_dev',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_video_effects',
-        '../ppapi/ppapi_internal.gyp:ppapi_example_video_encode',
-        '../ppapi/ppapi_internal.gyp:ppapi_tests',
-        '../ppapi/ppapi_internal.gyp:ppapi_perftests',
-        '../ppapi/ppapi_internal.gyp:ppapi_unittests',
-        '../ppapi/tools/ppapi_tools.gyp:pepper_hash_for_uma',
         '../printing/printing.gyp:printing_unittests',
         '../skia/skia_tests.gyp:skia_unittests',
-        '../skia/skia.gyp:filter_fuzz_stub',
-        '../skia/skia.gyp:image_operations_bench',
         '../sql/sql.gyp:sql_unittests',
-        '../sync/sync.gyp:run_sync_testserver',
         '../sync/sync.gyp:sync_unit_tests',
-        '../sync/tools/sync_tools.gyp:sync_client',
-        '../sync/tools/sync_tools.gyp:sync_listen_notifications',
         '../testing/gmock.gyp:gmock_main',
         '../third_party/WebKit/Source/platform/blink_platform_tests.gyp:blink_heap_unittests',
         '../third_party/WebKit/Source/platform/blink_platform_tests.gyp:blink_platform_unittests',
         '../third_party/WebKit/Source/web/web_tests.gyp:webkit_unit_tests',
         '../third_party/WebKit/Source/wtf/wtf_tests.gyp:wtf_unittests',
-        '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests',
-        '../third_party/codesighs/codesighs.gyp:codesighs',
-        '../third_party/codesighs/codesighs.gyp:maptsvdifftool',
         '../third_party/leveldatabase/leveldatabase.gyp:env_chromium_unittests',
-        '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_unittests',
         '../third_party/libaddressinput/libaddressinput.gyp:libaddressinput_unittests',
-        '../third_party/mojo/mojo_edk_tests.gyp:mojo_system_unittests',
-        '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_bindings_unittests',
-        '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_environment_unittests',
-        '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_system_perftests',
-        '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_system_unittests',
-        '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_utility_unittests',
         '../third_party/openh264/tests/openh264_unittests.gyp:*',
-        '../third_party/pdfium/samples/samples.gyp:pdfium_diff',
-        '../third_party/pdfium/samples/samples.gyp:pdfium_test',
         '../third_party/smhasher/smhasher.gyp:pmurhash',
-        '../tools/gn/gn.gyp:gn',
-        '../tools/gn/gn.gyp:generate_test_gn_data',
-        '../tools/gn/gn.gyp:gn_unittests',
-        '../tools/imagediff/image_diff.gyp:image_diff',
-        '../tools/perf/clear_system_cache/clear_system_cache.gyp:clear_system_cache',
         '../tools/telemetry/telemetry.gyp:bitmaptools#host',
         '../ui/accessibility/accessibility.gyp:accessibility_unittests',
-        '../ui/app_list/app_list.gyp:app_list_unittests',
         '../ui/base/ui_base_tests.gyp:ui_base_unittests',
-        '../ui/compositor/compositor.gyp:compositor_unittests',
         '../ui/display/display.gyp:display_unittests',
         '../ui/events/events.gyp:events_unittests',
         '../ui/gfx/gfx_tests.gyp:gfx_unittests',
         '../ui/gl/gl_tests.gyp:gl_unittests',
-        '../ui/message_center/message_center.gyp:message_center_unittests',
         '../ui/snapshot/snapshot.gyp:snapshot_unittests',
         '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests',
-        '../ui/views/examples/examples.gyp:views_examples_with_content_exe',
         '../url/url.gyp:url_unittests',
         '../v8/tools/gyp/v8.gyp:v8_snapshot',
         '../v8/tools/gyp/v8.gyp:postmortem-metadata',
@@ -288,10 +176,13 @@
         ['OS=="android"', {
           'dependencies': [
             '../base/base.gyp:chromium_android_linker',
-            '../breakpad/breakpad.gyp:dump_syms',
+            '../breakpad/breakpad.gyp:dump_syms#host',
+            '../breakpad/breakpad.gyp:symupload#host',
+            '../breakpad/breakpad.gyp:minidump_dump#host',
+            '../breakpad/breakpad.gyp:minidump_stackwalk#host',
             '../build/android/rezip.gyp:rezip_apk_jar',
             #"//clank" TODO(GYP) - conditional somehow?
-            '../tools/android/heap_profiler/heap_profiler_unittests_apk',
+            '../tools/android/heap_profiler/heap_profiler.gyp:heap_profiler_unittests_apk',
             '../tools/imagediff/image_diff.gyp:image_diff#host',
             '../tools/telemetry/telemetry.gyp:bitmaptools#host',
 
@@ -328,39 +219,139 @@
             #"//ui/message_center:test_support",
           ],
           'dependencies!': [
-            '../breakpad/breakpad.gyp:symupload',
-            '../chrome/chrome.gyp:browser_tests',
-            '../chrome/chrome.gyp:chromedriver',
-            '../chrome/chrome.gyp:chromedriver_unitests',
-            '../chrome/chrome.gyp:interactive_ui_tests',
-            '../chrome/chrome.gyp:performance_browser_tests',
-            '../chrome/chrome.gyp:sync_integration_tests',
+            # TODO(GYP): All of these targets need to be ported over.
             '../chrome/chrome.gyp:unit_tests',
-            '../extensions/extensions_tests.gyp:extensions_browsertests',
-            '../extensions/extensions_tests.gyp:extensions_unittests',
-            '../google_apis/gcm/gcm.gyp:gcm_unit_tests',
-            '../ipc/ipc.gyp:ipc_tests',
-            '../jingle/jingle.gyp:jingle_unittests',
-            '../net/net.gyp:net_unittests',
-            #"//ppapi/examples",
-            '../third_party/pdfium/samples/samples.gyp:pdfium_test',
-            '../tools/gn/gn.gyp:gn',
-            '../tools/gn/gn.gyp:gn_unittests',
-            '../tools/imagediff/image_diff.gyp:image_diff',
-            '../tools/gn/gn.gyp:gn',
-            '../tools/gn/gn.gyp:gn_unittests',
-            '../ui/app_list/app_list.gyp:app_list_unittests',
             '../url/url.gyp:url_unittests',
           ],
         }],
         ['OS=="android" and chromecast==0', {
           'dependencies': [
-            '../chrome/chrome.gyp:chrome_public_apk',
-            '../chrome/chrome.gyp:chrome_public_test_apk',
+            '../chrome/android/chrome_apk.gyp:chrome_public_apk',
+            '../chrome/android/chrome_apk.gyp:chrome_public_test_apk',
             '../chrome/chrome.gyp:chromedriver_webview_shell_apk',
             '../third_party/custom_tabs_client/custom_tabs_client.gyp:custom_tabs_client_example_apk',
           ],
         }],
+        ['OS!="android"', {
+          'dependencies': [
+            '../base/base.gyp:build_utf8_validator_tables#host',
+            '../chrome/chrome.gyp:chrome_app_unittests',
+            '../chrome/chrome.gyp:chromedriver',
+            '../chrome/chrome.gyp:chromedriver_tests',
+            '../chrome/chrome.gyp:chromedriver_unittests',
+            '../cloud_print/cloud_print.gyp:cloud_print_unittests',
+            '../content/content_shell_and_tests.gyp:content_shell',
+            '../courgette/courgette.gyp:courgette',
+            '../courgette/courgette.gyp:courgette_fuzz',
+            '../courgette/courgette.gyp:courgette_minimal_tool',
+            '../courgette/courgette.gyp:courgette_unittests',
+            '../gin/gin.gyp:gin_unittests',
+            '../gpu/gles2_conform_support/gles2_conform_support.gyp:gles2_conform_support',  # TODO(GYP) crbug.com/471920
+            '../google_apis/gcm/gcm.gyp:gcm_unit_tests',
+            '../google_apis/gcm/gcm.gyp:mcs_probe',
+            '../google_apis/google_apis.gyp:google_apis_unittests',
+            '../jingle/jingle.gyp:jingle_unittests',
+            '../media/cast/cast.gyp:cast_benchmarks',
+            '../media/cast/cast.gyp:cast_unittests',
+            '../media/cast/cast.gyp:generate_barcode_video',
+            '../media/cast/cast.gyp:generate_timecode_audio',
+            '../mojo/mojo.gyp:mojo',
+            '../net/net.gyp:crash_cache',
+            '../net/net.gyp:crl_set_dump',
+            '../net/net.gyp:dns_fuzz_stub',
+            '../net/net.gyp:gdig',
+            '../net/net.gyp:get_server_time',
+            '../net/net.gyp:hpack_example_generator',
+            '../net/net.gyp:hpack_fuzz_mutator',
+            '../net/net.gyp:hpack_fuzz_wrapper',
+            '../net/net.gyp:net_watcher',  # TODO(GYP): This should be conditional on use_v8_in_net
+            '../net/net.gyp:run_testserver',
+            '../net/net.gyp:stress_cache',
+            '../net/net.gyp:tld_cleanup',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_audio',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_audio_input',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_c_stub',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_cc_stub',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_compositor',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_crxfs',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_enumerate_devices',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_file_chooser',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_flash_topmost',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_gamepad',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_gles2',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_gles2_spinning_cube',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_graphics_2d',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_ime',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_input',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_media_stream_audio',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_media_stream_video',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_mouse_cursor',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_mouse_lock',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_paint_manager',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_post_message',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_printing',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_scaling',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_scroll',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_simple_font',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_threading',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_url_loader',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_url_loader_file',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_vc',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_video_decode',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_video_decode_dev',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_video_effects',
+            '../ppapi/ppapi_internal.gyp:ppapi_example_video_encode',
+            '../ppapi/ppapi_internal.gyp:ppapi_tests',
+            '../ppapi/ppapi_internal.gyp:ppapi_perftests',
+            '../ppapi/ppapi_internal.gyp:ppapi_unittests',
+            '../sync/sync.gyp:run_sync_testserver',
+            '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests',
+            '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_unittests',
+            '../third_party/mojo/mojo_edk_tests.gyp:mojo_system_unittests',
+            '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_bindings_unittests',
+            '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_environment_unittests',
+            '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_system_perftests',
+            '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_system_unittests',
+            '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_utility_unittests',
+            '../tools/imagediff/image_diff.gyp:image_diff',
+            '../ui/app_list/app_list.gyp:app_list_unittests',
+            '../ui/compositor/compositor.gyp:compositor_unittests',
+          ],
+        }],
+        ['OS!="android" and chromecast==0', {
+          'dependencies': [
+            '../chrome/chrome.gyp:browser_tests',
+            '../chrome/chrome.gyp:chrome',
+            '../chrome/chrome.gyp:interactive_ui_tests',
+            '../chrome/chrome.gyp:performance_browser_tests',
+            '../chrome/chrome.gyp:sync_integration_tests',
+            '../chrome/chrome.gyp:sync_performance_tests',
+            '../chrome/tools/profile_reset/jtl_compiler.gyp:jtl_compiler',
+            '../extensions/extensions_tests.gyp:extensions_browsertests',
+            '../extensions/extensions_tests.gyp:extensions_unittests',
+            '../gin/gin.gyp:gin_shell',
+            '../gpu/gles2_conform_support/gles2_conform_test.gyp:gles2_conform_test',  # TODO(GYP) crbug.com/471920
+            '../gpu/khronos_glcts_support/khronos_glcts_test.gyp:khronos_glcts_test',  # TODO(GYP) crbug.com/471903 to make this complete.
+            '../ipc/ipc.gyp:ipc_perftests',
+            '../media/media.gyp:ffmpeg_regression_tests',  # TODO(GYP) this should be conditional on media_use_ffmpeg
+            '../mojo/mojo_base.gyp:mojo_common_unittests',
+            '../ppapi/tools/ppapi_tools.gyp:pepper_hash_for_uma',
+            '../skia/skia.gyp:filter_fuzz_stub',
+            '../skia/skia.gyp:image_operations_bench',
+            '../sync/tools/sync_tools.gyp:sync_client',
+            '../sync/tools/sync_tools.gyp:sync_listen_notifications',
+            '../third_party/codesighs/codesighs.gyp:codesighs',
+            '../third_party/codesighs/codesighs.gyp:maptsvdifftool',
+            '../third_party/pdfium/samples/samples.gyp:pdfium_diff',
+            '../third_party/pdfium/samples/samples.gyp:pdfium_test',
+            '../tools/gn/gn.gyp:generate_test_gn_data',
+            '../tools/gn/gn.gyp:gn',
+            '../tools/gn/gn.gyp:gn_unittests',
+            '../tools/perf/clear_system_cache/clear_system_cache.gyp:clear_system_cache',
+            '../ui/message_center/message_center.gyp:message_center_unittests',
+            '../ui/views/examples/examples.gyp:views_examples_with_content_exe',
+          ],
+        }],
         ['OS=="android" or OS=="linux"', {
           'dependencies': [
             '../net/net.gyp:disk_cache_memory_test',
@@ -379,7 +370,7 @@
             '../rlz/rlz.gyp:rlz_unittests',
           ],
         }],
-        ['OS=="android" or OS=="linux" or os_bsd==1', {
+        ['OS=="linux" or os_bsd==1', {
           'dependencies': [
             '../breakpad/breakpad.gyp:core-2-minidump',
             '../breakpad/breakpad.gyp:microdump_stackwalk',
@@ -718,6 +709,13 @@
             '../components/components.gyp:policy_win64',
           ]
         }],
+        ['OS=="android"', {
+          'dependencies': [
+            # TODO(GYP): All of these targets need to be ported over.
+            '../chrome/chrome.gyp:unit_tests',
+            '../url/url.gyp:url_unittests',
+          ],
+        }],
       ],
     },
   ]
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 852a5f9c..2cd502a 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -661,10 +661,6 @@
   ]
 
   configs += [ "//build/config:precompiled_headers" ]
-  include_dirs = [
-    ".",
-    "test",
-  ]
 
   public_deps = [
     ":cc",
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index 419f68c..559786a 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -299,10 +299,6 @@
         '<@(cc_unit_tests_source_files)',
         '<@(cc_surfaces_unit_tests_source_files)',
       ],
-      'include_dirs': [
-        'test',
-        '.',
-      ],
       'conditions': [
         ['OS == "android"',
           {
@@ -363,10 +359,6 @@
         'trees/layer_tree_host_perftest.cc',
         'trees/occlusion_tracker_perftest.cc',
       ],
-      'include_dirs': [
-        'test',
-        '.',
-      ],
       'conditions': [
         ['OS == "android"',
           {
@@ -388,11 +380,6 @@
     {
       'target_name': 'cc_test_support',
       'type': 'static_library',
-      'include_dirs': [
-        'test',
-        '.',
-        '..',
-      ],
       'dependencies': [
         '../base/base.gyp:base',
         '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
diff --git a/cc/layers/render_surface_impl.cc b/cc/layers/render_surface_impl.cc
index 560c75c..4e88bda 100644
--- a/cc/layers/render_surface_impl.cc
+++ b/cc/layers/render_surface_impl.cc
@@ -47,6 +47,14 @@
         replica_draw_transform_, gfx::RectF(content_rect_)));
   }
 
+  // If the rect has a NaN coordinate, we return empty rect to avoid crashes in
+  // functions (for example, gfx::ToEnclosedRect) that are called on this rect.
+  if (std::isnan(drawable_content_rect.x()) ||
+      std::isnan(drawable_content_rect.y()) ||
+      std::isnan(drawable_content_rect.right()) ||
+      std::isnan(drawable_content_rect.bottom()))
+    return gfx::RectF();
+
   return drawable_content_rect;
 }
 
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc
index ac25fbb3..51679c50 100644
--- a/cc/trees/layer_tree_host_common.cc
+++ b/cc/trees/layer_tree_host_common.cc
@@ -2624,7 +2624,7 @@
         layer->render_surface()->accumulated_content_rect());
 
   if (render_to_separate_surface && !IsRootLayer(layer) &&
-      layer->render_surface()->content_rect().IsEmpty()) {
+      layer->render_surface()->DrawableContentRect().IsEmpty()) {
     RemoveSurfaceForEarlyExit(layer, render_surface_layer_list);
     return;
   }
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc
index c90ea949..ac77ea4 100644
--- a/cc/trees/layer_tree_host_common_unittest.cc
+++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -8036,5 +8036,48 @@
   EXPECT_EQ(gfx::Rect(-10, -10, 30, 30), render_surface2->clip_rect());
 }
 
+TEST_F(LayerTreeHostCommonTest, LargeTransformTest) {
+  LayerImpl* root = root_layer();
+  LayerImpl* render_surface1 = AddChild<LayerImpl>(root);
+  LayerImpl* render_surface2 = AddChild<LayerImpl>(render_surface1);
+
+  const gfx::Transform identity_matrix;
+  render_surface1->SetDrawsContent(true);
+  render_surface2->SetDrawsContent(true);
+
+  gfx::Transform large_transform;
+  large_transform.Scale(99999999999999999999.f, 99999999999999999999.f);
+  large_transform.Scale(9999999999999999999.f, 9999999999999999999.f);
+  EXPECT_TRUE(std::isinf(large_transform.matrix().get(0, 0)));
+  EXPECT_TRUE(std::isinf(large_transform.matrix().get(1, 1)));
+
+  SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(),
+                               gfx::PointF(), gfx::Size(30, 30), true, false,
+                               true);
+  SetLayerPropertiesForTesting(render_surface1, large_transform, gfx::Point3F(),
+                               gfx::PointF(), gfx::Size(30, 30), true, false,
+                               true);
+  SetLayerPropertiesForTesting(render_surface2, identity_matrix, gfx::Point3F(),
+                               gfx::PointF(), gfx::Size(30, 30), true, false,
+                               true);
+
+  ExecuteCalculateDrawProperties(root);
+
+  EXPECT_TRUE(std::isinf(
+      render_surface2->render_surface()->draw_transform().matrix().get(0, 0)));
+  EXPECT_TRUE(std::isinf(
+      render_surface2->render_surface()->draw_transform().matrix().get(1, 1)));
+  EXPECT_EQ(gfx::RectF(),
+            render_surface2->render_surface()->DrawableContentRect());
+
+  std::vector<LayerImpl*>* rsll = render_surface_layer_list_impl();
+  bool root_in_rsll =
+      std::find(rsll->begin(), rsll->end(), root) != rsll->end();
+  EXPECT_TRUE(root_in_rsll);
+  bool render_surface2_in_rsll =
+      std::find(rsll->begin(), rsll->end(), render_surface2) != rsll->end();
+  EXPECT_FALSE(render_surface2_in_rsll);
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/chrome/android/java/res/menu/chrome_context_menu.xml b/chrome/android/java/res/menu/chrome_context_menu.xml
index 4306864..bf49f8b 100644
--- a/chrome/android/java/res/menu/chrome_context_menu.xml
+++ b/chrome/android/java/res/menu/chrome_context_menu.xml
@@ -28,14 +28,6 @@
             android:title="@string/contextmenu_save_image"/>
         <item android:id="@+id/contextmenu_open_image"
             android:title="@string/contextmenu_open_image"/>
-        <item android:id="@+id/contextmenu_open_image_in_new_tab"
-            android:title="@string/contextmenu_open_image_in_new_tab"/>
-        <item android:id="@+id/contextmenu_open_original_image_in_new_tab"
-            android:title="@string/contextmenu_open_original_image_in_new_tab"/>
-        <item android:id="@+id/contextmenu_copy_image"
-            android:title="@string/contextmenu_copy_image"/>
-        <item android:id="@+id/contextmenu_copy_image_url"
-            android:title="@string/contextmenu_copy_image_url"/>
     </group>
     <group android:id="@+id/contextmenu_group_video">
         <item android:id="@+id/contextmenu_save_video"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
index c3d4a03..5c5220e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
@@ -34,9 +34,6 @@
         static final int ACTION_SAVE_LINK = 5;
         static final int ACTION_SAVE_IMAGE = 6;
         static final int ACTION_OPEN_IMAGE = 7;
-        static final int ACTION_OPEN_IMAGE_IN_NEW_TAB = 8;
-        static final int ACTION_COPY_IMAGE = 9;
-        static final int ACTION_COPY_IMAGE_URL = 10;
         static final int ACTION_LOAD_IMAGES = 12;
         static final int ACTION_LOAD_ORIGINAL_IMAGE = 13;
         static final int ACTION_SAVE_VIDEO = 14;
@@ -99,7 +96,7 @@
             menu.findItem(R.id.contextmenu_open_in_incognito_tab).setVisible(false);
         }
 
-        if (params.getLinkText().trim().isEmpty()) {
+        if (params.getLinkText().trim().isEmpty() || params.isImage()) {
             menu.findItem(R.id.contextmenu_copy_link_text).setVisible(false);
         }
 
@@ -136,20 +133,12 @@
             // new tab," and "Copy image URL" should be disabled on Lo-Fi images.
             menu.findItem(R.id.contextmenu_save_image).setVisible(false);
             menu.findItem(R.id.contextmenu_open_image).setVisible(false);
-            menu.findItem(R.id.contextmenu_open_image_in_new_tab).setVisible(false);
-            menu.findItem(R.id.contextmenu_copy_image).setVisible(false);
         } else if (params.isImage() && !params.imageWasFetchedLoFi()) {
             menu.findItem(R.id.contextmenu_load_original_image).setVisible(false);
 
             menu.findItem(R.id.contextmenu_save_image).setVisible(
                     UrlUtilities.isDownloadableScheme(params.getSrcUrl()));
 
-            if (mDelegate.canLoadOriginalImage()) {
-                menu.findItem(R.id.contextmenu_open_image_in_new_tab).setVisible(false);
-            } else {
-                menu.findItem(R.id.contextmenu_open_original_image_in_new_tab).setVisible(false);
-            }
-
             // Avoid showing open image option for same image which is already opened.
             if (mDelegate.getPageUrl().equals(params.getSrcUrl())) {
                 menu.findItem(R.id.contextmenu_open_image).setVisible(false);
@@ -168,10 +157,6 @@
         } else if (itemId == R.id.contextmenu_open_image) {
             ContextMenuUma.record(params, ContextMenuUma.ACTION_OPEN_IMAGE);
             mDelegate.onOpenImageUrl(params.getSrcUrl(), params.getReferrer());
-        } else if (itemId == R.id.contextmenu_open_image_in_new_tab
-                || itemId == R.id.contextmenu_open_original_image_in_new_tab) {
-            ContextMenuUma.record(params, ContextMenuUma.ACTION_OPEN_IMAGE_IN_NEW_TAB);
-            mDelegate.onOpenImageInNewTab(params.getSrcUrl(), params.getReferrer());
         } else if (itemId == R.id.contextmenu_load_images) {
             ContextMenuUma.record(params, ContextMenuUma.ACTION_LOAD_IMAGES);
             DataReductionProxyUma.dataReductionProxyLoFiUIAction(
@@ -215,13 +200,6 @@
             if (mDelegate.startDownload(params.getUnfilteredLinkUrl(), true)) {
                 helper.startContextMenuDownload(true, false);
             }
-        } else if (itemId == R.id.contextmenu_copy_image) {
-            ContextMenuUma.record(params, ContextMenuUma.ACTION_COPY_IMAGE);
-            mDelegate.onSaveImageToClipboard(params.getSrcUrl());
-        } else if (itemId == R.id.contextmenu_copy_image_url) {
-            ContextMenuUma.record(params, ContextMenuUma.ACTION_COPY_IMAGE_URL);
-            mDelegate.onSaveToClipboard(
-                    params.getSrcUrl(), ContextMenuItemDelegate.CLIPBOARD_TYPE_IMAGE_URL);
         } else {
             assert false;
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemDelegate.java
index c26d5b0..d5819b19 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemDelegate.java
@@ -29,12 +29,6 @@
     boolean isIncognitoSupported();
 
     /**
-     * @return Whether or not the context menu should give the user the chance to show the original
-     *         image.
-     */
-    boolean canLoadOriginalImage();
-
-    /**
      * Returns whether or not the Data Reduction Proxy is enabled for input url.
      * @param url Input url to check for the Data Reduction Proxy setting.
      * @return true if the Data Reduction Proxy is enabled for the url.
@@ -69,12 +63,6 @@
     void onOpenImageUrl(String url, Referrer referrer);
 
     /**
-     * Called when the {@code url} is of an image and should be opened in a new tab.
-     * @param url The image URL to open.
-     */
-    void onOpenImageInNewTab(String url, Referrer referrer);
-
-    /**
      * Called when the page should be reloaded ignoring the cache.
      */
     void onReloadIgnoringCache();
@@ -91,13 +79,6 @@
      */
     void onSaveToClipboard(String text, int clipboardType);
 
-    /**
-     * Called when the {@code url} is of an image and a link to the image should be saved to the
-     * clipboard.
-     * @param url The image URL.
-     */
-    void onSaveImageToClipboard(String url);
-
    /**
     * @return page url.
     */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTab.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTab.java
index 4664ad7..70a4fb7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTab.java
@@ -238,7 +238,7 @@
 
                 String linkText = params.getLinkText();
                 if (linkText != null) linkText = linkText.trim();
-                if (!TextUtils.isEmpty(linkText)) {
+                if (!TextUtils.isEmpty(linkText)  && !params.isImage()) {
                     menu.add(Menu.NONE, org.chromium.chrome.R.id.contextmenu_copy_link_text,
                             Menu.NONE, org.chromium.chrome.R.string.contextmenu_copy_link_text);
                 }
@@ -247,10 +247,6 @@
                             R.string.contextmenu_save_image);
                     menu.add(Menu.NONE, R.id.contextmenu_open_image, Menu.NONE,
                             R.string.contextmenu_open_image);
-                    menu.add(Menu.NONE, R.id.contextmenu_copy_image, Menu.NONE,
-                            R.string.contextmenu_copy_image);
-                    menu.add(Menu.NONE, R.id.contextmenu_copy_image_url, Menu.NONE,
-                            R.string.contextmenu_copy_image_url);
                 } else if (UrlUtilities.isDownloadableScheme(params.getLinkUrl())) {
                     // "Save link" is not shown for image.
                     menu.add(Menu.NONE, R.id.contextmenu_save_link_as, Menu.NONE,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/AbstractMediaRouteController.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/AbstractMediaRouteController.java
index b770fe5..fac9f5c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/AbstractMediaRouteController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/AbstractMediaRouteController.java
@@ -180,9 +180,6 @@
     private final Set<UiListener> mUiListeners;
     private boolean mWatchingRouteSelection = false;
 
-    /**
-     * Sole constructor
-     */
     protected AbstractMediaRouteController() {
 
         mDebug = CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_CAST_DEBUG_LOGS);
@@ -285,9 +282,6 @@
         return mHandler;
     }
 
-    /**
-     * @return the mMediaRouter
-     */
     protected final MediaRouter getMediaRouter() {
         return mMediaRouter;
     }
@@ -307,10 +301,6 @@
         return mCurrentRoute == null ? null : mCurrentRoute.getName();
     }
 
-    /**
-     * @return The list of MediaRouteController.Listener objects that will receive messages from
-     *         this class.
-     */
     protected final Set<UiListener> getUiListeners() {
         return mUiListeners;
     }
@@ -347,7 +337,23 @@
         for (UiListener listener : mUiListeners) {
             listener.onRouteSelected(route.getName(), this);
         }
-        if (mMediaStateListener != null) mMediaStateListener.onRouteSelected(route.getName());
+        if (mMediaStateListener == null) return;
+        if (!canCastMedia()) return;
+        startCastingVideo(route);
+    }
+
+    private void startCastingVideo(RouteInfo route) {
+        mMediaStateListener.pauseLocal();
+        mMediaStateListener.onCastStarting(route.getName());
+        setDataSource(Uri.parse(mMediaStateListener.getSourceUrl()),
+                mMediaStateListener.getCookies(), mMediaStateListener.getUserAgent());
+        prepareAsync(
+                mMediaStateListener.getFrameUrl(), mMediaStateListener.getStartPositionMillis());
+    }
+
+    private boolean canCastMedia() {
+        return isRemotePlaybackAvailable() && !routeIsDefaultRoute()
+                && currentRouteSupportsRemotePlayback();
     }
 
     @Override
@@ -440,12 +446,17 @@
         mMediaStateListener = mediaStateListener;
     }
 
-    private void setPrepared() {
+    private void onCasting() {
         if (!mIsPrepared) {
             for (UiListener listener : mUiListeners) {
                 listener.onPrepared(this);
             }
-            if (mMediaStateListener != null) mMediaStateListener.onPrepared();
+            if (mMediaStateListener.isPauseRequested()) pause();
+            if (mMediaStateListener.isSeekRequested()) {
+                seekTo(mMediaStateListener.getSeekLocation());
+            } else {
+                seekTo(mMediaStateListener.getLocalPosition());
+            }
             RecordCastAction.castDefaultPlayerResult(true);
             mIsPrepared = true;
         }
@@ -551,12 +562,12 @@
                             System.currentTimeMillis());
                     RemotePlaybackSettings.setShouldReconnectToRemote(getContext(),
                             !mCurrentRoute.isDefault());
-                    setPrepared();
+                    onCasting();
                     break;
                 case PAUSED:
                     RemotePlaybackSettings.setShouldReconnectToRemote(getContext(),
                             !mCurrentRoute.isDefault());
-                    setPrepared();
+                    onCasting();
                     break;
                 case FINISHED:
                     release();
@@ -600,4 +611,17 @@
      * @param cookies
      */
     public void setDataSource(Uri uri, String cookies) {};
+
+    @Override
+    public boolean playerTakesOverCastDevice(MediaStateListener mediaStateListener) {
+        // Check if this MediaRouteControler is casting something.
+        if (!isBeingCast()) return false;
+        // Check if we want to cast the new video
+        if (!canCastMedia()) return false;
+        // Take over the cast device
+        if (mMediaStateListener != null) mMediaStateListener.onCastStopping();
+        mMediaStateListener = mediaStateListener;
+        startCastingVideo(mCurrentRoute);
+        return true;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/MediaRouteController.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/MediaRouteController.java
index 858001e..d2eaa6f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/MediaRouteController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/MediaRouteController.java
@@ -27,49 +27,87 @@
          * is removed.
          * @param available whether routes are available.
          */
-        public void onRouteAvailabilityChanged(boolean available);
+        void onRouteAvailabilityChanged(boolean available);
 
         /**
          * Called when an error is detected by the media route controller
          */
-        public void onError();
+        void onError();
 
         /**
          * Called when a seek completes on the current route
          */
-        public void onSeekCompleted();
-
-        /**
-         * Called when the current route is ready to be used
-         */
-        public void onPrepared();
-
-        /**
-         * Called when a new route has been selected for Cast
-         * @param name the name of the route
-         */
-        public void onRouteSelected(String name);
+        void onSeekCompleted();
 
         /**
          * Called when the current route is unselected
          */
-        public void onRouteUnselected();
+        void onRouteUnselected();
 
         /**
          * Called when the playback state changes (e.g. from Playing to Paused)
          * @param newState the new playback state
          */
-        public void onPlaybackStateChanged(PlayerState newState);
+        void onPlaybackStateChanged(PlayerState newState);
+
+        String getTitle();
+
+        Bitmap getPosterBitmap();
+
+        void pauseLocal();
+
+        int getLocalPosition();
 
         /**
-         * @return the title of the video
+         * Tells the rest of Chrome that we are starting to cast, so that user inputs control cast
+         * in place of local playback
          */
-        public String getTitle();
+        void onCastStarting(String routeName);
 
         /**
-         * @return the poster bitmap
+         * Tells the rest of Chrome that we are no longer casting the video.
          */
-        public Bitmap getPosterBitmap();
+        void onCastStopping();
+
+        /**
+         * @return the source URL
+         */
+        String getSourceUrl();
+
+        /**
+         * @return the Cookies
+         */
+        String getCookies();
+
+        /**
+         * @return the User Agent string
+         */
+        String getUserAgent();
+
+        /**
+         * @return the frame URL
+         */
+        String getFrameUrl();
+
+        /**
+         * @return the start position
+         */
+        long getStartPositionMillis();
+
+        /**
+         * @return true if the user has pressed the pause button (or requested pause some other way)
+         */
+        boolean isPauseRequested();
+
+        /**
+         * @return true if the user has requested a seek
+         */
+        boolean isSeekRequested();
+
+        /**
+         * @return the requested seek location. Only meaningful if isSeekRequested is true.
+         */
+        int getSeekLocation();
     }
 
     /**
@@ -137,7 +175,7 @@
      *
      * @return false if device doesn't support cast, true otherwise.
      */
-    public boolean initialize();
+    boolean initialize();
 
     /**
      * Can this mediaRouteController handle a media element?
@@ -145,28 +183,28 @@
      * @param frameUrl
      * @return true if it can, false if it can't.
      */
-    public boolean canPlayMedia(String sourceUrl, String frameUrl);
+    boolean canPlayMedia(String sourceUrl, String frameUrl);
 
     /**
      * @return A new MediaRouteSelector filtering the remote playback devices from all the routes.
      */
-    public MediaRouteSelector buildMediaRouteSelector();
+    MediaRouteSelector buildMediaRouteSelector();
 
     /**
      * @return Whether there're remote playback devices available.
      */
-    public boolean isRemotePlaybackAvailable();
+    boolean isRemotePlaybackAvailable();
 
     /**
      * @return Whether the currently selected device supports remote playback
      */
-    public boolean currentRouteSupportsRemotePlayback();
+    boolean currentRouteSupportsRemotePlayback();
 
     /**
      * Checks if we want to reconnect, and if so starts trying to do so. Otherwise clears out the
      * persistent request to reconnect.
      */
-    public boolean reconnectAnyExistingRoute();
+    boolean reconnectAnyExistingRoute();
 
     /**
      * Sets the video URL when it becomes known.
@@ -177,36 +215,36 @@
      * @param uri The video URL.
      * @param userAgent The browser user agent.
      */
-    public void setDataSource(Uri uri, String cookies, String userAgent);
+    void setDataSource(Uri uri, String cookies, String userAgent);
 
     /**
      * Setup this object to discover new routes and register the necessary players.
      */
-    public void prepareMediaRoute();
+    void prepareMediaRoute();
 
     /**
      * Add a Listener that will listen to events from this object
      *
      * @param listener the Listener that will receive the events
      */
-    public void addUiListener(UiListener listener);
+    void addUiListener(UiListener listener);
 
     /**
      * Removes a Listener from this object
      *
      * @param listener the Listener to remove
      */
-    public void removeUiListener(UiListener listener);
+    void removeUiListener(UiListener listener);
 
     /**
      * @return The currently selected route's friendly name, or null if there is none selected
      */
-    public String getRouteName();
+    String getRouteName();
 
     /**
      * @return true if this is currently using the default route, false if not.
      */
-    public boolean routeIsDefaultRoute();
+    boolean routeIsDefaultRoute();
 
     /**
      * Called to prepare the remote playback asyncronously. onPrepared() of the current remote media
@@ -214,24 +252,24 @@
      *
      * @param startPositionMillis indicates where in the stream to start playing
      */
-    public void prepareAsync(String frameUrl, long startPositionMillis);
+    void prepareAsync(String frameUrl, long startPositionMillis);
 
     /**
      * Sets the remote volume of the current route.
      *
      * @param delta The delta value in arbitrary "Android Volume Units".
      */
-    public void setRemoteVolume(int delta);
+    void setRemoteVolume(int delta);
 
     /**
      * Resume paused playback of the current video.
      */
-    public void resume();
+    void resume();
 
     /**
      * Pauses the currently playing video if any.
      */
-    public void pause();
+    void pause();
 
     /**
      * Returns the current remote playback position. Estimates the current position by using the
@@ -242,68 +280,77 @@
      *
      * @return The current position of the remote playback in milliseconds.
      */
-    public int getPosition();
+    int getPosition();
 
     /**
      * @return The stream duration in milliseconds.
      */
-    public int getDuration();
+    int getDuration();
 
     /**
      * @return Whether the video is currently being played.
      */
-    public boolean isPlaying();
+    boolean isPlaying();
 
     /**
      * @return Whether the video is being cast (any of playing/paused/loading/stopped).
      */
-    public boolean isBeingCast();
+    boolean isBeingCast();
 
     /**
      * Initiates a seek request for the remote playback device to the specified position.
      *
      * @param msec The position to seek to, in milliseconds.
      */
-    public void seekTo(int msec);
+    void seekTo(int msec);
 
     /**
      * Stop the current remote playback completely and release all resources.
      */
-    public void release();
+    void release();
 
     /**
      * @param player - the current player using this media route controller.
      */
-    public void setMediaStateListener(MediaStateListener listener);
+    void setMediaStateListener(MediaStateListener listener);
 
     /**
      * @return the current VideoStateListener
      */
-    public MediaStateListener getMediaStateListener();
+    MediaStateListener getMediaStateListener();
 
     /**
      * @return true if the video is new
      */
-    public boolean shouldResetState(MediaStateListener newListener);
+    boolean shouldResetState(MediaStateListener newListener);
 
-    @VisibleForTesting
-    public PlayerState getPlayerState();
+    @VisibleForTesting PlayerState getPlayerState();
 
     /**
      * Remove an existing media state listener
      * @param listener
      */
-    public void removeMediaStateListener(MediaStateListener listener);
+    void removeMediaStateListener(MediaStateListener listener);
 
     /**
      * Add a media state listener
      * @param listener
      */
-    public void addMediaStateListener(MediaStateListener listener);
+    void addMediaStateListener(MediaStateListener listener);
 
     /**
      * Get the poster for the video, if any
      * @return the poster bitmap, or Null.
      */
-    public Bitmap getPoster();
+    Bitmap getPoster();
+
+    /**
+     * Used to switch video or audio streams when already casting.
+     * If the mediaRouteController not casting does nothing.
+     * If the mediaRouteController is already casting, then the calling RemoteMediaPlayerBridge
+     * takes over the cast device and starts casting its stream.
+     * @param mMediaStateListener
+     * @return true if the new stream has been cast, false if not.
+     */
+    boolean playerTakesOverCastDevice(MediaStateListener mediaStateListener);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/OWNERS
index b94ea03..ef2ec5b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/OWNERS
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/OWNERS
@@ -1,3 +1,3 @@
 aberent@chromium.org
-avayod@chromium.org
+avayvod@chromium.org
 dgn@chromium.org
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerBridge.java
index 7598ff7..0bf0d0bc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerBridge.java
@@ -8,7 +8,6 @@
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.media.MediaPlayer;
-import android.net.Uri;
 import android.os.Build;
 import android.util.Log;
 
@@ -37,10 +36,15 @@
     private MediaPlayer.OnPreparedListener mOnPreparedListener;
 
     private final MediaRouteController mRouteController;
-    private final String mSourceUrl;
     private final String mFrameUrl;
     private final boolean mDebug;
+    private final String mSourceUrl;
+    private final String mUserAgent;
     private Bitmap mPosterBitmap;
+    private String mCookies;
+    private boolean mPauseRequested;
+    private boolean mSeekRequested;
+    private int mSeekLocation;
 
     // mActive is true when the Chrome is playing, or preparing to play, this player's video
     // remotely.
@@ -48,7 +52,7 @@
 
     private static final String TAG = "RemoteMediaPlayerBridge";
 
-    private MediaRouteController.MediaStateListener mMediaStateListener =
+    private final MediaRouteController.MediaStateListener mMediaStateListener =
             new MediaRouteController.MediaStateListener() {
         @Override
         public void onRouteAvailabilityChanged(boolean available) {
@@ -75,20 +79,6 @@
         }
 
         @Override
-        public void onPrepared() {
-            if (mActive && mOnPreparedListener != null) {
-                mOnPreparedListener.onPrepared(null);
-            }
-        }
-
-        @Override
-        public void onRouteSelected(String name) {
-            if (mNativeRemoteMediaPlayerBridge == 0) return;
-            nativeOnRouteSelected(mNativeRemoteMediaPlayerBridge,
-                    RemoteMediaPlayerController.instance().getCastingMessage(name));
-        }
-
-        @Override
         public void onRouteUnselected() {
             if (mNativeRemoteMediaPlayerBridge == 0) return;
             nativeOnRouteUnselected(mNativeRemoteMediaPlayerBridge);
@@ -117,10 +107,73 @@
         public Bitmap getPosterBitmap() {
             return mPosterBitmap;
         }
+
+        @Override
+        public void pauseLocal() {
+            nativePauseLocal(mNativeRemoteMediaPlayerBridge);
+        }
+
+        @Override
+        public int getLocalPosition() {
+            return nativeGetLocalPosition(mNativeRemoteMediaPlayerBridge);
+        }
+
+        @Override
+        public void onCastStarting(String routeName) {
+            nativeOnCastStarting(mNativeRemoteMediaPlayerBridge,
+                    RemoteMediaPlayerController.instance().getCastingMessage(routeName));
+            mActive = true;
+        }
+
+        @Override
+        public void onCastStopping() {
+            nativeOnCastStopping(mNativeRemoteMediaPlayerBridge);
+            mActive = false;
+        }
+
+        @Override
+        public String getSourceUrl() {
+            return mSourceUrl;
+        }
+
+        @Override
+        public String getCookies() {
+            return mCookies;
+        }
+
+        @Override
+        public String getUserAgent() {
+            return mUserAgent;
+        }
+
+        @Override
+        public String getFrameUrl() {
+            return mFrameUrl;
+        }
+
+        @Override
+        public long getStartPositionMillis() {
+            return mStartPositionMillis;
+        }
+
+        @Override
+        public boolean isPauseRequested() {
+            return mPauseRequested;
+        }
+
+        @Override
+        public boolean isSeekRequested() {
+            return mSeekRequested;
+        }
+
+        @Override
+        public int getSeekLocation() {
+            return mSeekLocation;
+        }
     };
 
     private RemoteMediaPlayerBridge(long nativeRemoteMediaPlayerBridge, long startPositionMillis,
-            String sourceUrl, String frameUrl) {
+            String sourceUrl, String frameUrl, String userAgent) {
 
         mDebug = CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_CAST_DEBUG_LOGS);
 
@@ -129,6 +182,7 @@
         mStartPositionMillis = startPositionMillis;
         mSourceUrl = sourceUrl;
         mFrameUrl = frameUrl;
+        mUserAgent = userAgent;
         // This will get null if there isn't a mediaRouteController that can play this media.
         mRouteController = RemoteMediaPlayerController.instance()
                 .getMediaRouteController(sourceUrl, frameUrl);
@@ -136,9 +190,9 @@
 
     @CalledByNative
     private static RemoteMediaPlayerBridge create(long nativeRemoteMediaPlayerBridge,
-            long startPositionMillis, String sourceUrl, String frameUrl) {
+            long startPositionMillis, String sourceUrl, String frameUrl, String userAgent) {
         return new RemoteMediaPlayerBridge(nativeRemoteMediaPlayerBridge, startPositionMillis,
-                sourceUrl, frameUrl);
+                sourceUrl, frameUrl, userAgent);
     }
 
     /**
@@ -148,6 +202,9 @@
     @CalledByNative
     private void requestRemotePlayback() {
         if (mDebug) Log.i(TAG, "requestRemotePlayback");
+        // Clear out the state
+        mPauseRequested = false;
+        mSeekRequested = false;
         RemoteMediaPlayerController.instance().requestRemotePlayback(
                 mMediaStateListener, mRouteController);
     }
@@ -185,14 +242,6 @@
     }
 
     /**
-     * @return Whether there're remote playback devices available.
-     */
-    @CalledByNative
-    private boolean isRemotePlaybackAvailable() {
-        return mRouteController.isRemotePlaybackAvailable();
-    }
-
-    /**
      * @param bitmap The bitmap of the poster for the video, null if no poster image exists.
      *
      *         TODO(cimamoglu): Notify the clients (probably through MediaRouteController.Listener)
@@ -204,27 +253,6 @@
         mPosterBitmap = bitmap;
     }
 
-    /**
-     * @return Whether the video should be played remotely if possible
-     */
-    @CalledByNative
-    private boolean isRemotePlaybackPreferredForFrame() {
-        return !mRouteController.routeIsDefaultRoute()
-                && mRouteController.currentRouteSupportsRemotePlayback();
-    }
-
-    @CalledByNative
-    private boolean isMediaPlayableRemotely() {
-        return mRouteController != null;
-    }
-
-    @Override
-    @CalledByNative
-    protected boolean prepareAsync() {
-        mRouteController.prepareAsync(mFrameUrl, mStartPositionMillis);
-        return true;
-    }
-
     @Override
     @CalledByNative
     protected boolean isPlaying() {
@@ -260,26 +288,28 @@
     @Override
     @CalledByNative
     protected void start() throws IllegalStateException {
-        mRouteController.resume();
+        mPauseRequested = false;
+        if (mRouteController.isBeingCast()) mRouteController.resume();
     }
 
     @Override
     @CalledByNative
     protected void pause() throws IllegalStateException {
-        mRouteController.pause();
+        mPauseRequested = true;
+        if (mRouteController.isBeingCast()) mRouteController.pause();
     }
 
     @Override
     @CalledByNative
     protected void seekTo(int msec) throws IllegalStateException {
-        mRouteController.seekTo(msec);
+        mSeekRequested = true;
+        mSeekLocation = msec;
+        if (mRouteController.isBeingCast()) mRouteController.seekTo(msec);
     }
 
     @Override
-    @CalledByNative
     protected boolean setDataSource(
             Context context, String url, String cookies, String userAgent, boolean hideUrlLog) {
-        mRouteController.setDataSource(Uri.parse(url), cookies, userAgent);
         return true;
     }
 
@@ -304,7 +334,6 @@
 
     @Override
     protected void setOnPreparedListener(MediaPlayer.OnPreparedListener listener) {
-        mOnPreparedListener = listener;
     }
 
     @Override
@@ -330,15 +359,28 @@
         mNativeRemoteMediaPlayerBridge = 0;
     }
 
+    @CalledByNative
+    private boolean takesOverCastDevice() {
+        if (mRouteController == null) return false;
+        return mRouteController.playerTakesOverCastDevice(mMediaStateListener);
+    }
+
+    @CalledByNative
+    private void setCookies(String cookies) {
+        mCookies = cookies;
+    }
+
     private native String nativeGetFrameUrl(long nativeRemoteMediaPlayerBridge);
     private native void nativeOnPlaying(long nativeRemoteMediaPlayerBridge);
     private native void nativeOnPaused(long nativeRemoteMediaPlayerBridge);
-    private native void nativeOnRouteSelected(long nativeRemoteMediaPlayerBridge,
-            String playerName);
     private native void nativeOnRouteUnselected(long nativeRemoteMediaPlayerBridge);
     private native void nativeOnPlaybackFinished(long nativeRemoteMediaPlayerBridge);
     private native void nativeOnRouteAvailabilityChanged(long nativeRemoteMediaPlayerBridge,
             boolean available);
     private native String nativeGetTitle(long nativeRemoteMediaPlayerBridge);
-
+    private native void nativePauseLocal(long nativeRemoteMediaPlayerBridge);
+    private native int nativeGetLocalPosition(long nativeRemoteMediaPlayerBridge);
+    private native void nativeOnCastStarting(long nativeRemoteMediaPlayerBridge,
+            String castingMessage);
+    private native void nativeOnCastStopping(long nativeRemoteMediaPlayerBridge);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerController.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerController.java
index 9723794..e2289f5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerController.java
@@ -185,6 +185,11 @@
      */
     public void requestRemotePlayback(
             MediaRouteController.MediaStateListener player, MediaRouteController controller) {
+        // If we are already casting then simply switch to new video.
+        if (controller.isBeingCast()) {
+            controller.playerTakesOverCastDevice(player);
+            return;
+        }
         Activity currentActivity = ApplicationStatus.getLastTrackedFocusedActivity();
         mChromeVideoActivity = new WeakReference<Activity>(currentActivity);
 
@@ -272,41 +277,6 @@
     }
 
     /**
-     * Returns the current remote playback position.
-     *
-     * @return The current position of the remote playback in milliseconds.
-     */
-    public int getPosition() {
-        if (mCurrentRouteController == null) return -1;
-        return mCurrentRouteController.getPosition();
-    }
-
-    /**
-     * @return The stream duration in milliseconds.
-     */
-    public int getDuration() {
-        if (mCurrentRouteController == null) return 0;
-        return mCurrentRouteController.getDuration();
-    }
-
-    /**
-     * @return Whether the video is currently being played.
-     */
-    public boolean isPlaying() {
-        return mCurrentRouteController != null && mCurrentRouteController.isPlaying();
-    }
-
-    /**
-     * Initiates a seek request for the remote playback device to the specified position.
-     *
-     * @param msec The position to seek to, in milliseconds.
-     */
-    public void seekTo(int msec) {
-        if (mCurrentRouteController == null) return;
-        mCurrentRouteController.seekTo(msec);
-    }
-
-    /**
      * @return the currently playing MediaRouteController
      */
     public MediaRouteController getCurrentlyPlayingMediaRouteController() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabContextMenuItemDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabContextMenuItemDelegate.java
index d9e083f..c0ed65e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabContextMenuItemDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabContextMenuItemDelegate.java
@@ -4,8 +4,6 @@
 
 package org.chromium.chrome.browser.tab;
 
-import android.text.TextUtils;
-
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.contextmenu.ContextMenuItemDelegate;
@@ -23,55 +21,17 @@
  * A default {@link ContextMenuItemDelegate} that supports the context menu functionality in Tab.
  */
 public class TabContextMenuItemDelegate implements ContextMenuItemDelegate {
-    public static final String PAGESPEED_PASSTHROUGH_HEADERS =
-            "Chrome-Proxy: pass-through\nCache-Control: no-cache";
-
     private final Clipboard mClipboard;
     private final Tab mTab;
     private final ChromeActivity mActivity;
 
     /**
-     * The data reduction proxy was in use on the last page load if true.
-     */
-    protected boolean mUsedSpdyProxy;
-
-    /**
-     * The data reduction proxy was in pass through mode on the last page load if true.
-     */
-    protected boolean mUsedSpdyProxyWithPassthrough;
-
-    /**
-     * The last page load had request headers indicating that the data reduction proxy should
-     * be put in pass through mode, if true.
-     */
-    protected boolean mLastPageLoadHasSpdyProxyPassthroughHeaders;
-
-    /**
      * Builds a {@link TabContextMenuItemDelegate} instance.
      */
     public TabContextMenuItemDelegate(Tab tab, ChromeActivity activity) {
         mTab = tab;
         mActivity = activity;
         mClipboard = new Clipboard(mTab.getApplicationContext());
-        mTab.addObserver(new EmptyTabObserver() {
-            @Override
-            public void onLoadUrl(Tab tab, LoadUrlParams params, int loadType) {
-                super.onLoadUrl(tab, params, loadType);
-                // The data reduction proxy can only be set to pass through mode via loading an
-                // image in a new tab. We squirrel away whether pass through mode was set, and check
-                // it in: @see TabWebContentsDelegateAndroid#onLoadStopped()
-                mLastPageLoadHasSpdyProxyPassthroughHeaders = false;
-                if (TextUtils.equals(params.getVerbatimHeaders(), PAGESPEED_PASSTHROUGH_HEADERS)) {
-                    mLastPageLoadHasSpdyProxyPassthroughHeaders = true;
-                }
-            }
-
-            @Override
-            public void onPageLoadFinished(Tab tab) {
-                super.onPageLoadFinished(tab);
-                maybeSetDataReductionProxyUsed();
-            }
-        });
     }
 
     @Override
@@ -85,11 +45,6 @@
     }
 
     @Override
-    public boolean canLoadOriginalImage() {
-        return mUsedSpdyProxy && !mUsedSpdyProxyWithPassthrough;
-    }
-
-    @Override
     public boolean isDataReductionProxyEnabledForURL(String url) {
         return isSpdyProxyEnabledForUrl(url);
     }
@@ -105,11 +60,6 @@
     }
 
     @Override
-    public void onSaveImageToClipboard(String url) {
-        mClipboard.setHTMLText("<img src=\"" + url + "\">", url, url);
-    }
-
-    @Override
     public void onOpenInNewTab(String url, Referrer referrer) {
         RecordUserAction.record("MobileNewTabOpened");
         LoadUrlParams loadUrlParams = new LoadUrlParams(url);
@@ -148,22 +98,12 @@
         mTab.loadUrl(loadUrlParams);
     }
 
-    @Override
-    public void onOpenImageInNewTab(String url, Referrer referrer) {
-        boolean useOriginal = isSpdyProxyEnabledForUrl(url);
-        LoadUrlParams loadUrlParams = new LoadUrlParams(url);
-        loadUrlParams.setVerbatimHeaders(useOriginal ? PAGESPEED_PASSTHROUGH_HEADERS : null);
-        loadUrlParams.setReferrer(referrer);
-        mActivity.getTabModelSelector().openNewTab(loadUrlParams,
-                TabLaunchType.FROM_LONGPRESS_BACKGROUND, mTab, isIncognito());
-    }
-
     /**
      * Checks if spdy proxy is enabled for input url.
      * @param url Input url to check for spdy setting.
      * @return true if url is enabled for spdy proxy.
     */
-    boolean isSpdyProxyEnabledForUrl(String url) {
+    private boolean isSpdyProxyEnabledForUrl(String url) {
         if (DataReductionProxySettings.getInstance().isDataReductionProxyEnabled()
                 && url != null && !url.toLowerCase(Locale.US).startsWith("https://")
                 && !isIncognito()) {
@@ -171,25 +111,4 @@
         }
         return false;
     }
-
-    /**
-     * Remember if the last load used the data reduction proxy, and if so,
-     * also remember if it used pass through mode.
-     */
-    private void maybeSetDataReductionProxyUsed() {
-        // Ignore internal URLs.
-        String url = mTab.getUrl();
-        if (url != null && url.toLowerCase(Locale.US).startsWith("chrome://")) {
-            return;
-        }
-        mUsedSpdyProxy = false;
-        mUsedSpdyProxyWithPassthrough = false;
-        if (isSpdyProxyEnabledForUrl(url)) {
-            mUsedSpdyProxy = true;
-            if (mLastPageLoadHasSpdyProxyPassthroughHeaders) {
-                mLastPageLoadHasSpdyProxyPassthroughHeaders = false;
-                mUsedSpdyProxyWithPassthrough = true;
-            }
-        }
-    }
 }
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 38063ee..54141b6 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -1243,24 +1243,12 @@
       <message name="IDS_CONTEXTMENU_OPEN_IMAGE" desc="Context sensitive menu item for opening/viewing the selected image. [CHAR-LIMIT=30]">
         Open image
       </message>
-      <message name="IDS_CONTEXTMENU_OPEN_IMAGE_IN_NEW_TAB" desc="Context sensitive menu item for opening/viewing the selected image in a new tab. [CHAR-LIMIT=30]">
-        Open image in new tab
-      </message>
-      <message name="IDS_CONTEXTMENU_OPEN_ORIGINAL_IMAGE_IN_NEW_TAB" desc="Context sensitive menu item for opening/viewing the original version of the selected image in a new tab. [CHAR-LIMIT=30]">
-        Open original image in new tab
-      </message>
       <message name="IDS_CONTEXTMENU_LOAD_IMAGES" desc="Context sensitive menu item for Data Saver low fidelity placeholder images that reloads the page with the original images. [CHAR-LIMIT=30]">
         Load images
       </message>
       <message name="IDS_CONTEXTMENU_LOAD_ORIGINAL_IMAGE" desc="Context sensitive menu item for Data Saver low fidelity placeholder images that loads the original version in place. [CHAR-LIMIT=30]">
         Load image
       </message>
-      <message name="IDS_CONTEXTMENU_COPY_IMAGE" desc="Context sensitive menu item for copying an image to the clipboard. [CHAR-LIMIT=30]">
-        Copy image
-      </message>
-      <message name="IDS_CONTEXTMENU_COPY_IMAGE_URL" desc="Context sensitive menu item for copying an image url to the clipboard. [CHAR-LIMIT=30]">
-        Copy image URL
-      </message>
       <message name="IDS_CONTEXTMENU_SAVE_VIDEO" desc="Context sensitive menu item for saving the selected video. [CHAR-LIMIT=30]">
         Save video
       </message>
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java
index 8a9e5e3..cc00414d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java
@@ -89,20 +89,7 @@
                 R.id.contextmenu_copy_link_text);
 
         assertEquals("Clipboard text was not what was expected",
-                "This is pretty   extreme \n(newline). ", getClipboardText());
-    }
-
-    @MediumTest
-    @Feature({"Browser"})
-    public void testCopyImageToClipboard() throws InterruptedException, TimeoutException {
-        Tab tab = getActivity().getActivityTab();
-        ContextMenuUtils.selectContextMenuItem(this, tab, "testImage",
-                R.id.contextmenu_copy_image);
-
-        String expectedUrl = TestHttpServerClient.getUrl(
-                "chrome/test/data/android/contextmenu/test_image.png");
-
-        assertEquals("Clipboard text is not correct", expectedUrl, getClipboardText());
+                "This is pretty extreme \n(newline). ", getClipboardText());
     }
 
     @MediumTest
@@ -199,19 +186,6 @@
 
     @MediumTest
     @Feature({"Browser"})
-    public void testCopyImageURL() throws InterruptedException, TimeoutException {
-        Tab tab = getActivity().getActivityTab();
-        ContextMenuUtils.selectContextMenuItem(this, tab, "testImage",
-                R.id.contextmenu_copy_image_url);
-
-        String expectedUrl = TestHttpServerClient.getUrl(
-                "chrome/test/data/android/contextmenu/test_image.png");
-
-        assertEquals("Copied image URL is not correct", expectedUrl, getClipboardText());
-    }
-
-    @MediumTest
-    @Feature({"Browser"})
     public void testCopyEmailAddress() throws InterruptedException, TimeoutException {
         Tab tab = getActivity().getActivityTab();
         ContextMenuUtils.selectContextMenuItem(this, tab, "testEmail",
@@ -281,10 +255,10 @@
                     }
                 }));
 
-        ContextMenuUtils.selectContextMenuItem(this, tab, "testImage",
-                R.id.contextmenu_open_image_in_new_tab);
+        ContextMenuUtils.selectContextMenuItem(this, tab, "testLink2",
+                R.id.contextmenu_open_in_new_tab);
         getInstrumentation().waitForIdleSync();
-        int indexOfImagePage = numOpenedTabs;
+        int indexOfLinkPage2 = numOpenedTabs;
         numOpenedTabs += 1;
         assertEquals("Number of open tabs does not match", numOpenedTabs, tabModel.getCount());
 
@@ -297,8 +271,8 @@
         assertEquals(newTabUrl, tabModel.getTabAt(indexOfLinkPage).getUrl());
 
         String imageUrl = TestHttpServerClient.getUrl(
-                "chrome/test/data/android/contextmenu/test_image.png");
-        assertEquals(imageUrl, tabModel.getTabAt(indexOfImagePage).getUrl());
+                "chrome/test/data/android/contextmenu/test_link2.html");
+        assertEquals(imageUrl, tabModel.getTabAt(indexOfLinkPage2).getUrl());
     }
 
     private void saveMediaFromContextMenu(String mediaDOMElement, int saveMenuID,
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
index b3eb872..73ceea9e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -175,13 +175,11 @@
     public void testContextMenuEntriesForImage() throws InterruptedException, TimeoutException {
         startCustomTabActivityWithIntent(createMinimalCustomTabIntent());
 
-        final int expectedMenuSize = 4;
+        final int expectedMenuSize = 2;
         Menu menu = ContextMenuUtils.openContextMenu(this, getActivity().getActivityTab(), "logo");
         assertEquals(expectedMenuSize, menu.size());
         assertNotNull(menu.findItem(R.id.contextmenu_save_image));
         assertNotNull(menu.findItem(R.id.contextmenu_open_image));
-        assertNotNull(menu.findItem(R.id.contextmenu_copy_image));
-        assertNotNull(menu.findItem(R.id.contextmenu_copy_image_url));
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/OWNERS b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/OWNERS
index 1c73e334..107320240 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/OWNERS
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/OWNERS
@@ -1,2 +1,3 @@
 dfalcantara@chromium.org
 changwan@chromium.org
+mlamouri@chromium.org
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 0a8c55f..2b63aab 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -6111,17 +6111,17 @@
       <message name="IDS_FLAGS_V8_PAC_MOJO_OUT_OF_PROCESS_DESCRIPTION" desc="Description for the flag to enable out-of-process V8 proxy resolver.">
         Enable Out-of-process V8 Proxy Resolver. Runs the V8 proxy resolver in a utility process instead of inside the browser process.
       </message>
-      <message name="IDS_FLAGS_V8_CACHE_OPTIONS_NAME" desc="Name of the about::flags setting for JavaScript cache options.">
-        JavaScript caching mode.
+      <message name="IDS_FLAGS_V8_CACHE_OPTIONS_NAME" desc="Name of the about::flags setting for V8 cache options. The V8 JavaScript engine supports three caching modes: disabled; parser; code. This is the option to choose among them.">
+        V8 caching mode.
       </message>
-      <message name="IDS_FLAGS_V8_CACHE_OPTIONS_DESCRIPTION" desc="Description of the about::flags setting for JavaScript cache options.">
+      <message name="IDS_FLAGS_V8_CACHE_OPTIONS_DESCRIPTION" desc="Description of the about::flags setting for V8 cache options. The V8 JavaScript engine supports three caching modes: disabled; parser; code.">
         Caching mode for the V8 JavaScript engine.
       </message>
-      <message name="IDS_FLAGS_V8_CACHE_OPTIONS_PARSE" desc="The JavaScript engine supports three 'caching' modes: disabled; caching data generated by the JavaScript parser; or caching data generated by the JavaScript compiler. This option describes the 2nd of these, caching data generated by the parser.">
-        Cache JavaScript parser data.
+      <message name="IDS_FLAGS_V8_CACHE_OPTIONS_PARSE" desc="The V8 JavaScript engine supports three 'caching' modes: disabled; caching data generated by the JavaScript parser; or caching data generated by the JavaScript compiler. This option describes the 2nd of these, caching data generated by the parser.">
+        Cache V8 parser data.
       </message>
-      <message name="IDS_FLAGS_V8_CACHE_OPTIONS_CODE" desc="The JavaScript engine supports three 'caching' modes: disabled; caching data generated by the JavaScript parser; or caching data generated by the JavaScript compiler. This option describes the 3rd of these, caching data generated by the compiler.">
-        Cache JavaScript compiler data.
+      <message name="IDS_FLAGS_V8_CACHE_OPTIONS_CODE" desc="The V8 JavaScript engine supports three 'caching' modes: disabled; caching data generated by the JavaScript parser; or caching data generated by the JavaScript compiler. This option describes the 3rd of these, caching data generated by the compiler.">
+        Cache V8 compiler data.
       </message>
 
       <!-- Data Reduction Proxy -->
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index c22e542a..e4478cc8 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -132,6 +132,7 @@
     "//components/metrics:gpu",
     "//components/metrics:net",
     "//components/metrics:profiler",
+    "//components/metrics:profiler_content",
     "//components/metrics/proto:proto",
     "//components/metrics:ui",
     "//components/mime_util",
diff --git a/chrome/browser/android/compositor/tab_content_manager.cc b/chrome/browser/android/compositor/tab_content_manager.cc
index 6b05ed1e..42a68ac 100644
--- a/chrome/browser/android/compositor/tab_content_manager.cc
+++ b/chrome/browser/android/compositor/tab_content_manager.cc
@@ -18,6 +18,7 @@
 #include "content/public/browser/android/content_view_core.h"
 #include "content/public/browser/readback_types.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents.h"
 #include "jni/TabContentManager_jni.h"
 #include "ui/android/resources/ui_resource_provider.h"
@@ -71,7 +72,10 @@
     }
 
     DCHECK(view->GetWebContents());
-    view->GetWebContents()->GetRenderViewHost()->LockBackingStore();
+    view->GetWebContents()
+        ->GetRenderViewHost()
+        ->GetWidget()
+        ->LockBackingStore();
 
     SkColorType color_type = kN32_SkColorType;
 
@@ -91,7 +95,10 @@
 
     if (view) {
       DCHECK(view->GetWebContents());
-      view->GetWebContents()->GetRenderViewHost()->UnlockBackingStore();
+      view->GetWebContents()
+          ->GetRenderViewHost()
+          ->GetWidget()
+          ->UnlockBackingStore();
     }
 
     if (response != content::READBACK_SUCCESS || drop_after_readback_) {
@@ -249,6 +256,7 @@
     if (!view ||
         !view->GetWebContents()
              ->GetRenderViewHost()
+             ->GetWidget()
              ->CanCopyFromBackingStore() ||
         pending_tab_readbacks_.find(tab_id) != pending_tab_readbacks_.end() ||
         pending_tab_readbacks_.size() >= kMaxReadbacks) {
diff --git a/chrome/browser/android/tab/thumbnail_tab_helper_android.cc b/chrome/browser/android/tab/thumbnail_tab_helper_android.cc
index c93d41c..293f04a 100644
--- a/chrome/browser/android/tab/thumbnail_tab_helper_android.cc
+++ b/chrome/browser/android/tab/thumbnail_tab_helper_android.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/thumbnails/thumbnailing_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "jni/ThumbnailTabHelper_jni.h"
@@ -70,7 +71,7 @@
     const gfx::Size& thumbnail_size) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   content::RenderWidgetHost* render_widget_host =
-      web_contents->GetRenderViewHost();
+      web_contents->GetRenderViewHost()->GetWidget();
   content::RenderWidgetHostView* view = render_widget_host->GetView();
   if (!view)
     return;
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
index 6b14401..0b611c8 100644
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -38,6 +38,7 @@
 #include "content/public/browser/interstitial_page_delegate.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/common/child_process_host.h"
@@ -665,9 +666,11 @@
     mouse_event.button = blink::WebMouseEvent::ButtonRight;
     mouse_event.x = 1;
     mouse_event.y = 1;
-    web_contents->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+    web_contents->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(
+        mouse_event);
     mouse_event.type = blink::WebInputEvent::MouseUp;
-    web_contents->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+    web_contents->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(
+        mouse_event);
   }
 
   content::WebContents* GetGuestWebContents() {
diff --git a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
index 456136b..7d6286b 100644
--- a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
@@ -24,6 +24,7 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_iterator.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
@@ -383,7 +384,8 @@
 
     content::RenderViewHost* embedder_rvh =
         GetFirstAppWindowWebContents()->GetRenderViewHost();
-    gfx::Rect embedder_bounds = embedder_rvh->GetView()->GetViewBounds();
+    gfx::Rect embedder_bounds =
+        embedder_rvh->GetWidget()->GetView()->GetViewBounds();
     gfx::Vector2d diff = popup_bounds.origin() - embedder_bounds.origin();
     LOG(INFO) << "DIFF: x = " << diff.x() << ", y = " << diff.y();
 
@@ -616,7 +618,7 @@
                   "window.runCommand('testFocusTracksEmbedderRunNextStep');"));
 
   // Blur the embedder.
-  embedder_web_contents->GetRenderViewHost()->Blur();
+  embedder_web_contents->GetRenderViewHost()->GetWidget()->Blur();
   // Ensure that the guest is also blurred.
   ASSERT_TRUE(next_step_listener.WaitUntilSatisfied());
 }
@@ -634,8 +636,9 @@
   {
     ExtensionTestMessageListener listener("button1-focused", false);
     listener.set_failure_message("TEST_FAILED");
-    SimulateRWHMouseClick(embedder_web_contents->GetRenderViewHost(),
-                          blink::WebMouseEvent::ButtonLeft, 200, 20);
+    SimulateRWHMouseClick(
+        embedder_web_contents->GetRenderViewHost()->GetWidget(),
+        blink::WebMouseEvent::ButtonLeft, 200, 20);
     content::SimulateKeyPress(embedder_web_contents, ui::VKEY_TAB,
         false, false, false, false);
     ASSERT_TRUE(listener.WaitUntilSatisfied());
@@ -850,7 +853,7 @@
   ASSERT_TRUE(guest_web_contents());
 
   ContextMenuWaiter menu_observer(content::NotificationService::AllSources());
-  SimulateRWHMouseClick(guest_web_contents()->GetRenderViewHost(),
+  SimulateRWHMouseClick(guest_web_contents()->GetRenderViewHost()->GetWidget(),
                         blink::WebMouseEvent::ButtonRight, 10, 20);
   // Wait until the context menu is opened and closed.
   menu_observer.WaitForMenuOpenAndClose();
@@ -896,10 +899,11 @@
     gfx::Point embedder_window_point = guest_window_point;
     embedder_window_point += guest_view_bounds.OffsetFromOrigin();
     embedder_window_point -= embedder_view_bounds.OffsetFromOrigin();
-    SimulateRWHMouseClick(embedder_web_contents()->GetRenderViewHost(),
-                          blink::WebMouseEvent::ButtonRight,
-                          /* Using window coordinates for the embedder */
-                          embedder_window_point.x(), embedder_window_point.y());
+    SimulateRWHMouseClick(
+        embedder_web_contents()->GetRenderViewHost()->GetWidget(),
+        blink::WebMouseEvent::ButtonRight,
+        /* Using window coordinates for the embedder */
+        embedder_window_point.x(), embedder_window_point.y());
 
     menu_observer.WaitForMenuOpenAndClose();
     EXPECT_EQ(menu_observer.params().x, guest_window_point.x());
@@ -1116,7 +1120,9 @@
   // |text_input_client| is not available for mac and android.
 #if !defined(OS_MACOSX) && !defined(OS_ANDROID)
   ui::TextInputClient* text_input_client =
-      embedder_web_contents->GetRenderViewHost()->GetView()
+      embedder_web_contents->GetRenderViewHost()
+          ->GetWidget()
+          ->GetView()
           ->GetTextInputClient();
   ASSERT_TRUE(text_input_client);
   ASSERT_TRUE(text_input_client->GetTextInputType() !=
@@ -1134,7 +1140,9 @@
   ASSERT_TRUE(done_listener->WaitUntilSatisfied());
 
   ui::TextInputClient* text_input_client =
-      embedder_web_contents->GetRenderViewHost()->GetView()
+      embedder_web_contents->GetRenderViewHost()
+          ->GetWidget()
+          ->GetView()
           ->GetTextInputClient();
   ASSERT_TRUE(text_input_client);
 
@@ -1209,7 +1217,7 @@
   // Wait until guest sees a context menu, select an arbitrary item (copy).
   ExtensionTestMessageListener ctx_listener("MSG_CONTEXTMENU", false);
   ContextMenuNotificationObserver menu_observer(IDC_CONTENT_CONTEXT_COPY);
-  SimulateRWHMouseClick(guest_web_contents()->GetRenderViewHost(),
+  SimulateRWHMouseClick(guest_web_contents()->GetRenderViewHost()->GetWidget(),
                         blink::WebMouseEvent::ButtonRight, 20, 20);
   ASSERT_TRUE(ctx_listener.WaitUntilSatisfied());
 
diff --git a/chrome/browser/autofill/autofill_browsertest.cc b/chrome/browser/autofill/autofill_browsertest.cc
index a298a6e..0e793f4 100644
--- a/chrome/browser/autofill/autofill_browsertest.cc
+++ b/chrome/browser/autofill/autofill_browsertest.cc
@@ -43,6 +43,7 @@
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_renderer_host.h"
 #include "content/public/test/test_utils.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -127,6 +128,9 @@
   void SetUpOnMainThread() override {
     // Don't want Keychain coming up on Mac.
     test::DisableSystemServices(browser()->profile()->GetPrefs());
+
+    ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+    InProcessBrowserTest::SetUpOnMainThread();
   }
 
   void TearDownOnMainThread() override {
@@ -194,7 +198,7 @@
                                     const std::string& submit_js,
                                     bool simulate_click,
                                     bool expect_personal_data_change) {
-    GURL url = test_server()->GetURL("files/autofill/" + filename);
+    GURL url = embedded_test_server()->GetURL("/autofill/" + filename);
     chrome::NavigateParams params(browser(), url,
                                   ui::PAGE_TRANSITION_LINK);
     params.disposition = NEW_FOREGROUND_TAB;
@@ -235,8 +239,6 @@
   // Aggregate profiles from forms into Autofill preferences. Returns the number
   // of parsed profiles.
   int AggregateProfilesIntoAutofillPrefs(const std::string& filename) {
-    CHECK(test_server()->Start());
-
     std::string data;
     base::FilePath data_file =
         ui_test_utils::GetTestFilePath(base::FilePath().AppendASCII("autofill"),
@@ -524,7 +526,6 @@
     return;
 #endif
 
-  ASSERT_TRUE(test_server()->Start());
   std::string card("4408 0412 3456 7890");
   ASSERT_FALSE(autofill::IsValidCreditCardNumber(ASCIIToUTF16(card)));
   SubmitCreditCard("Bob Smith", card.c_str(), "12", "2014");
@@ -545,7 +546,6 @@
     return;
 #endif
 
-  ASSERT_TRUE(test_server()->Start());
   SubmitCreditCard("Bob Smith", "4408 0412 3456 7893", "12", "2014");
   SubmitCreditCard("Jane Doe", "4417-1234-5678-9113", "10", "2013");
 
@@ -562,7 +562,6 @@
 // The minimum required address fields must be specified: First Name, Last Name,
 // Address Line 1, City, Zip Code, and State.
 IN_PROC_BROWSER_TEST_F(AutofillTest, AggregatesMinValidProfile) {
-  ASSERT_TRUE(test_server()->Start());
   FormMap data;
   data["NAME_FIRST"] = "Bob";
   data["NAME_LAST"] = "Smith";
@@ -577,7 +576,6 @@
 
 // Different Javascript to submit the form.
 IN_PROC_BROWSER_TEST_F(AutofillTest, AggregatesMinValidProfileDifferentJS) {
-  ASSERT_TRUE(test_server()->Start());
   FormMap data;
   data["NAME_FIRST"] = "Bob";
   data["NAME_LAST"] = "Smith";
@@ -597,7 +595,6 @@
 // which prevents submission of the form. Will not update the user's personal
 // data.
 IN_PROC_BROWSER_TEST_F(AutofillTest, ProfilesNotAggregatedWithSubmitHandler) {
-  ASSERT_TRUE(test_server()->Start());
   FormMap data;
   data["NAME_FIRST"] = "Bob";
   data["NAME_LAST"] = "Smith";
@@ -642,7 +639,6 @@
 // The minimum required address fields must be specified: First Name, Last Name,
 // Address Line 1, City, Zip Code, and State.
 IN_PROC_BROWSER_TEST_F(AutofillTest, ProfilesNotAggregatedWithNoAddress) {
-  ASSERT_TRUE(test_server()->Start());
   FormMap data;
   data["NAME_FIRST"] = "Bob";
   data["NAME_LAST"] = "Smith";
@@ -657,7 +653,6 @@
 
 // Test Autofill does not aggregate profiles with an invalid email.
 IN_PROC_BROWSER_TEST_F(AutofillTest, ProfilesNotAggregatedWithInvalidEmail) {
-  ASSERT_TRUE(test_server()->Start());
   FormMap data;
   data["NAME_FIRST"] = "Bob";
   data["NAME_LAST"] = "Smith";
@@ -677,7 +672,6 @@
 // The data file contains two profiles with valid phone numbers and two
 // profiles with invalid phone numbers from their respective country.
 IN_PROC_BROWSER_TEST_F(AutofillTest, ProfileSavedWithValidCountryPhone) {
-  ASSERT_TRUE(test_server()->Start());
   std::vector<FormMap> profiles;
 
   FormMap data1;
@@ -747,7 +741,6 @@
 // Prepend country codes when formatting phone numbers, but only if the user
 // provided one in the first place.
 IN_PROC_BROWSER_TEST_F(AutofillTest, AppendCountryCodeForAggregatedPhones) {
-  ASSERT_TRUE(test_server()->Start());
   FormMap data;
   data["NAME_FIRST"] = "Bob";
   data["NAME_LAST"] = "Smith";
@@ -798,7 +791,6 @@
 #endif
 
 IN_PROC_BROWSER_TEST_F(AutofillTest, MAYBE_UsePlusSignForInternationalNumber) {
-  ASSERT_TRUE(test_server()->Start());
   std::vector<FormMap> profiles;
 
   FormMap data1;
@@ -881,7 +873,6 @@
     return;
 #endif
 
-  ASSERT_TRUE(test_server()->Start());
   FormMap data;
   data["CREDIT_CARD_NAME"] = "Bob Smith";
   data["CREDIT_CARD_NUMBER"] = "4408041234567893";
@@ -896,8 +887,6 @@
 
 // Test profile not aggregated if email found in non-email field.
 IN_PROC_BROWSER_TEST_F(AutofillTest, ProfileWithEmailInOtherFieldNotSaved) {
-  ASSERT_TRUE(test_server()->Start());
-
   FormMap data;
   data["NAME_FIRST"] = "Bob";
   data["NAME_LAST"] = "Smith";
diff --git a/chrome/browser/autofill/autofill_interactive_uitest.cc b/chrome/browser/autofill/autofill_interactive_uitest.cc
index f62b3ca..4debf7a 100644
--- a/chrome/browser/autofill/autofill_interactive_uitest.cc
+++ b/chrome/browser/autofill/autofill_interactive_uitest.cc
@@ -50,6 +50,7 @@
 #include "content/public/test/test_renderer_host.h"
 #include "content/public/test/test_utils.h"
 #include "net/base/net_errors.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "net/url_request/url_request_status.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -160,6 +161,9 @@
     gfx::Point reset_mouse(GetWebContents()->GetContainerBounds().origin());
     reset_mouse = gfx::Point(reset_mouse.x() + 5, reset_mouse.y() + 5);
     ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(reset_mouse));
+
+    ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+    InProcessBrowserTest::SetUpOnMainThread();
   }
 
   void TearDownOnMainThread() override {
@@ -344,10 +348,12 @@
     test_delegate_.Reset();
     // Install the key press event sink to ensure that any events that are not
     // handled by the installed callbacks do not end up crashing the test.
-    GetRenderViewHost()->AddKeyPressEventCallback(key_press_event_sink_);
-    GetRenderViewHost()->ForwardKeyboardEvent(event);
+    GetRenderViewHost()->GetWidget()->AddKeyPressEventCallback(
+        key_press_event_sink_);
+    GetRenderViewHost()->GetWidget()->ForwardKeyboardEvent(event);
     test_delegate_.Wait();
-    GetRenderViewHost()->RemoveKeyPressEventCallback(key_press_event_sink_);
+    GetRenderViewHost()->GetWidget()->RemoveKeyPressEventCallback(
+        key_press_event_sink_);
   }
 
   // Datalist does not support autofill preview. There is no need to start
@@ -359,9 +365,11 @@
     event.type = blink::WebKeyboardEvent::RawKeyDown;
     // Install the key press event sink to ensure that any events that are not
     // handled by the installed callbacks do not end up crashing the test.
-    GetRenderViewHost()->AddKeyPressEventCallback(key_press_event_sink_);
-    GetRenderViewHost()->ForwardKeyboardEvent(event);
-    GetRenderViewHost()->RemoveKeyPressEventCallback(key_press_event_sink_);
+    GetRenderViewHost()->GetWidget()->AddKeyPressEventCallback(
+        key_press_event_sink_);
+    GetRenderViewHost()->GetWidget()->ForwardKeyboardEvent(event);
+    GetRenderViewHost()->GetWidget()->RemoveKeyPressEventCallback(
+        key_press_event_sink_);
   }
 
   void TryBasicFormFill() {
@@ -1168,8 +1176,6 @@
 #define MAYBE_ComparePhoneNumbers ComparePhoneNumbers
 #endif  // defined(OS_WIN) || defined(OFFICIAL_BUILD)
 IN_PROC_BROWSER_TEST_F(AutofillInteractiveTest, MAYBE_ComparePhoneNumbers) {
-  ASSERT_TRUE(test_server()->Start());
-
   AutofillProfile profile;
   profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Bob"));
   profile.SetRawInfo(NAME_LAST, ASCIIToUTF16("Smith"));
@@ -1180,7 +1186,7 @@
   profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("1-408-555-4567"));
   SetTestProfile(browser(), profile);
 
-  GURL url = test_server()->GetURL("files/autofill/form_phones.html");
+  GURL url = embedded_test_server()->GetURL("/autofill/form_phones.html");
   ui_test_utils::NavigateToURL(browser(), url);
   PopulateForm("NAME_FIRST");
 
@@ -1212,8 +1218,6 @@
 #endif  // defined(OFFICIAL_BUILD)
 IN_PROC_BROWSER_TEST_F(AutofillInteractiveTest,
                        MAYBE_NoAutofillForReadOnlyFields) {
-  ASSERT_TRUE(test_server()->Start());
-
   std::string addr_line1("1234 H St.");
 
   AutofillProfile profile;
@@ -1228,7 +1232,8 @@
   profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("408-871-4567"));
   SetTestProfile(browser(), profile);
 
-  GURL url = test_server()->GetURL("files/autofill/read_only_field_test.html");
+  GURL url =
+      embedded_test_server()->GetURL("/autofill/read_only_field_test.html");
   ui_test_utils::NavigateToURL(browser(), url);
   PopulateForm("firstname");
 
@@ -1243,11 +1248,10 @@
 //   3. Fill form using a saved profile.
 // Flakily times out: http://crbug.com/270341
 IN_PROC_BROWSER_TEST_F(AutofillInteractiveTest, DISABLED_FormFillableOnReset) {
-  ASSERT_TRUE(test_server()->Start());
-
   CreateTestProfile();
 
-  GURL url = test_server()->GetURL("files/autofill/autofill_test_form.html");
+  GURL url =
+      embedded_test_server()->GetURL("/autofill/autofill_test_form.html");
   ui_test_utils::NavigateToURL(browser(), url);
   PopulateForm("NAME_FIRST");
 
@@ -1271,12 +1275,10 @@
 // Flakily times out: http://crbug.com/270341
 IN_PROC_BROWSER_TEST_F(AutofillInteractiveTest,
                        DISABLED_DistinguishMiddleInitialWithinName) {
-  ASSERT_TRUE(test_server()->Start());
-
   CreateTestProfile();
 
-  GURL url = test_server()->GetURL(
-      "files/autofill/autofill_middleinit_form.html");
+  GURL url =
+      embedded_test_server()->GetURL("/autofill/autofill_middleinit_form.html");
   ui_test_utils::NavigateToURL(browser(), url);
   PopulateForm("NAME_FIRST");
 
@@ -1288,8 +1290,6 @@
 // Flakily times out: http://crbug.com/270341
 IN_PROC_BROWSER_TEST_F(AutofillInteractiveTest,
                        DISABLED_MultipleEmailFilledByOneUserGesture) {
-  ASSERT_TRUE(test_server()->Start());
-
   std::string email("bsmith@gmail.com");
 
   AutofillProfile profile;
@@ -1299,8 +1299,8 @@
   profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("4088714567"));
   SetTestProfile(browser(), profile);
 
-  GURL url = test_server()->GetURL(
-      "files/autofill/autofill_confirmemail_form.html");
+  GURL url = embedded_test_server()->GetURL(
+      "/autofill/autofill_confirmemail_form.html");
   ui_test_utils::NavigateToURL(browser(), url);
   PopulateForm("NAME_FIRST");
 
@@ -1315,8 +1315,6 @@
 // Flakily times out: http://crbug.com/281527
 IN_PROC_BROWSER_TEST_F(AutofillInteractiveTest,
                        DISABLED_FormFillLatencyAfterSubmit) {
-  ASSERT_TRUE(test_server()->Start());
-
   std::vector<std::string> cities;
   cities.push_back("San Jose");
   cities.push_back("San Francisco");
@@ -1357,8 +1355,8 @@
   LOG(INFO) << "Created " << kNumProfiles << " profiles in " <<
                (base::Time::Now() - start_time).InSeconds() << " seconds.";
 
-  GURL url = test_server()->GetURL(
-      "files/autofill/latency_after_submit_test.html");
+  GURL url = embedded_test_server()->GetURL(
+      "/autofill/latency_after_submit_test.html");
   ui_test_utils::NavigateToURL(browser(), url);
   PopulateForm("NAME_FIRST");
 
diff --git a/chrome/browser/background/background_mode_manager_unittest.cc b/chrome/browser/background/background_mode_manager_unittest.cc
index 2344a25b..633680b 100644
--- a/chrome/browser/background/background_mode_manager_unittest.cc
+++ b/chrome/browser/background/background_mode_manager_unittest.cc
@@ -31,6 +31,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/image/image.h"
 #include "ui/message_center/message_center.h"
+#include "ui/message_center/notifier_settings.h"
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h"
@@ -122,7 +123,8 @@
   void SetToolTip(const base::string16& tool_tip) override {}
   void DisplayBalloon(const gfx::ImageSkia& icon,
                       const base::string16& title,
-                      const base::string16& contents) override {}
+                      const base::string16& contents,
+                      const message_center::NotifierId& notifier_id) override {}
   void UpdatePlatformContextMenu(StatusIconMenuModel* menu) override {}
 
  private:
diff --git a/chrome/browser/background/background_mode_manager_win.cc b/chrome/browser/background/background_mode_manager_win.cc
index fa85eb71..0b04ed7 100644
--- a/chrome/browser/background/background_mode_manager_win.cc
+++ b/chrome/browser/background/background_mode_manager_win.cc
@@ -17,9 +17,12 @@
 #include "content/public/browser/browser_thread.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/image/image_skia.h"
+#include "ui/message_center/notifier_settings.h"
 
 using content::BrowserThread;
 
+const char kAppInstalledNotifierId[] = "background-mode.app-installed";
+
 void BackgroundModeManager::EnableLaunchOnStartup(bool should_launch) {
   // This functionality is only defined for default profile, currently.
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kUserDataDir))
@@ -41,7 +44,9 @@
       l10n_util::GetStringUTF16(IDS_BACKGROUND_APP_INSTALLED_BALLOON_TITLE),
       l10n_util::GetStringFUTF16(IDS_BACKGROUND_APP_INSTALLED_BALLOON_BODY,
                                  name,
-                                 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
+                                 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)),
+      message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT,
+                                 kAppInstalledNotifierId));
 }
 
 base::string16 BackgroundModeManager::GetPreferencesMenuLabel() {
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index a43d66b1..69ff32bd 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -112,6 +112,7 @@
 #include "components/language_usage_metrics/language_usage_metrics.h"
 #include "components/metrics/call_stack_profile_metrics_provider.h"
 #include "components/metrics/metrics_service.h"
+#include "components/metrics/profiler/content/content_tracking_synchronizer_delegate.h"
 #include "components/metrics/profiler/tracking_synchronizer.h"
 #include "components/nacl/browser/nacl_browser.h"
 #include "components/rappor/rappor_service.h"
@@ -1038,7 +1039,8 @@
 
   // Initialize tracking synchronizer system.
   tracking_synchronizer_ = new metrics::TrackingSynchronizer(
-      make_scoped_ptr(new base::DefaultTickClock()));
+      make_scoped_ptr(new base::DefaultTickClock()),
+      base::Bind(&metrics::ContentTrackingSynchronizerDelegate::Create));
 
 #if defined(OS_MACOSX)
   // Get the Keychain API to register for distributed notifications on the main
diff --git a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc
index 3b9637b4..79cee1ac 100644
--- a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc
+++ b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc
@@ -27,6 +27,7 @@
     "mfaihdlpglflfgpfjcifdjdjcckigekc",  // ARC Runtime
     "ngjnkanfphagcaokhjecbgkboelgfcnf",  // Print button
     "gbchcmhmhahfdphkhkmpfmihenigjmpp",  // Chrome Remote Desktop
+    "cjanmonomjogheabiocdamfpknlpdehm",  // HP printer driver
 
     // Libraries:
     "aclofikceldphonlfmghmimkodjdmhck",  // Ancoris login component
diff --git a/chrome/browser/chromeos/extensions/virtual_keyboard_browsertest.cc b/chrome/browser/chromeos/extensions/virtual_keyboard_browsertest.cc
index b8c3877e..082e54b 100644
--- a/chrome/browser/chromeos/extensions/virtual_keyboard_browsertest.cc
+++ b/chrome/browser/chromeos/extensions/virtual_keyboard_browsertest.cc
@@ -14,6 +14,7 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_iterator.h"
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/web_contents.h"
@@ -53,7 +54,7 @@
       url_(kVirtualKeyboardURL) {
 }
 
-VirtualKeyboardBrowserTestConfig::~VirtualKeyboardBrowserTestConfig() {};
+VirtualKeyboardBrowserTestConfig::~VirtualKeyboardBrowserTestConfig() {}
 
 void VirtualKeyboardBrowserTest::SetUpCommandLine(
     base::CommandLine* command_line) {
diff --git a/chrome/browser/chromeos/first_run/first_run_view.cc b/chrome/browser/chromeos/first_run/first_run_view.cc
index 0a586de..9e372778 100644
--- a/chrome/browser/chromeos/first_run/first_run_view.cc
+++ b/chrome/browser/chromeos/first_run/first_run_view.cc
@@ -8,6 +8,7 @@
 #include "chrome/browser/ui/webui/chromeos/first_run/first_run_ui.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
@@ -31,7 +32,7 @@
   extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
       web_contents);
 
-  web_contents->GetRenderViewHost()->GetView()->SetBackgroundColor(
+  web_contents->GetRenderViewHost()->GetWidget()->GetView()->SetBackgroundColor(
       SK_ColorTRANSPARENT);
 }
 
diff --git a/chrome/browser/chromeos/input_method/textinput_test_helper.cc b/chrome/browser/chromeos/input_method/textinput_test_helper.cc
index 7a7d3a67..e393b0a 100644
--- a/chrome/browser/chromeos/input_method/textinput_test_helper.cc
+++ b/chrome/browser/chromeos/input_method/textinput_test_helper.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/test/base/interactive_test_utils.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
 #include "ui/aura/window_event_dispatcher.h"
@@ -201,10 +202,10 @@
   mouse_event.x = rect.CenterPoint().x();
   mouse_event.y = rect.CenterPoint().y();
   mouse_event.clickCount = 1;
-  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+  tab->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(mouse_event);
 
   mouse_event.type = blink::WebInputEvent::MouseUp;
-  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+  tab->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(mouse_event);
   return true;
 }
 
diff --git a/chrome/browser/chromeos/login/ui/webui_login_view.cc b/chrome/browser/chromeos/login/ui/webui_login_view.cc
index 172a495f..b53b856 100644
--- a/chrome/browser/chromeos/login/ui/webui_login_view.cc
+++ b/chrome/browser/chromeos/login/ui/webui_login_view.cc
@@ -35,6 +35,7 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
@@ -270,8 +271,11 @@
 
   // TODO(nkostylev): Use WebContentsObserver::RenderViewCreated to track
   // when RenderView is created.
-  GetWebContents()->GetRenderViewHost()->GetView()->SetBackgroundColor(
-      SK_ColorTRANSPARENT);
+  GetWebContents()
+      ->GetRenderViewHost()
+      ->GetWidget()
+      ->GetView()
+      ->SetBackgroundColor(SK_ColorTRANSPARENT);
 }
 
 content::WebUI* WebUILoginView::GetWebUI() {
@@ -495,10 +499,4 @@
   webui_visible_ = true;
 }
 
-void WebUILoginView::ReturnFocus(bool reverse) {
-  // Return the focus to the web contents.
-  webui_login_->web_contents()->FocusThroughTabTraversal(reverse);
-  GetWidget()->Activate();
-}
-
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/ui/webui_login_view.h b/chrome/browser/chromeos/login/ui/webui_login_view.h
index 9e911959..caa6ca5 100644
--- a/chrome/browser/chromeos/login/ui/webui_login_view.h
+++ b/chrome/browser/chromeos/login/ui/webui_login_view.h
@@ -158,10 +158,6 @@
   // 2. Notifies OOBE/sign classes.
   void OnLoginPromptVisible();
 
-  // Called when focus is returned from status area.
-  // |reverse| is true when focus is traversed backwards (using Shift-Tab).
-  void ReturnFocus(bool reverse);
-
   content::NotificationRegistrar registrar_;
 
   // Converts keyboard events on the WebContents to accelerators.
diff --git a/chrome/browser/devtools/devtools_ui_bindings.cc b/chrome/browser/devtools/devtools_ui_bindings.cc
index c9a31ee..6352a23 100644
--- a/chrome/browser/devtools/devtools_ui_bindings.cc
+++ b/chrome/browser/devtools/devtools_ui_bindings.cc
@@ -47,6 +47,7 @@
 #include "content/public/common/url_constants.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/common/permissions/permissions_data.h"
+#include "ipc/ipc_channel.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
 #include "net/http/http_response_headers.h"
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc
index 5ab3e44..7470923 100644
--- a/chrome/browser/download/download_browsertest.cc
+++ b/chrome/browser/download/download_browsertest.cc
@@ -79,6 +79,7 @@
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/resource_context.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
@@ -2669,9 +2670,9 @@
   mouse_event.y = 15;
   mouse_event.clickCount = 1;
   mouse_event.modifiers = blink::WebInputEvent::AltKey;
-  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+  tab->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(mouse_event);
   mouse_event.type = blink::WebInputEvent::MouseUp;
-  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+  tab->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(mouse_event);
 
   waiter->WaitForFinished();
   EXPECT_EQ(1u, waiter->NumDownloadsSeenInState(DownloadItem::COMPLETE));
@@ -2725,9 +2726,9 @@
   mouse_event.x = 15;
   mouse_event.y = 15;
   mouse_event.clickCount = 1;
-  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+  tab->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(mouse_event);
   mouse_event.type = blink::WebInputEvent::MouseUp;
-  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+  tab->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(mouse_event);
 
   waiter->WaitForFinished();
   EXPECT_EQ(1u, waiter->NumDownloadsSeenInState(DownloadItem::COMPLETE));
diff --git a/chrome/browser/engagement/site_engagement_helper.cc b/chrome/browser/engagement/site_engagement_helper.cc
index 96c6db05..f445edd4 100644
--- a/chrome/browser/engagement/site_engagement_helper.cc
+++ b/chrome/browser/engagement/site_engagement_helper.cc
@@ -125,15 +125,15 @@
   if (!contents)
     return;
 
-  host_->AddKeyPressEventCallback(key_press_event_callback_);
-  host_->AddMouseEventCallback(mouse_event_callback_);
+  host_->GetWidget()->AddKeyPressEventCallback(key_press_event_callback_);
+  host_->GetWidget()->AddMouseEventCallback(mouse_event_callback_);
   is_tracking_ = true;
 }
 
 void SiteEngagementHelper::InputTracker::RemoveCallbacks() {
   if (is_tracking_) {
-    host_->RemoveKeyPressEventCallback(key_press_event_callback_);
-    host_->RemoveMouseEventCallback(mouse_event_callback_);
+    host_->GetWidget()->RemoveKeyPressEventCallback(key_press_event_callback_);
+    host_->GetWidget()->RemoveMouseEventCallback(mouse_event_callback_);
     is_tracking_ = false;
   }
 }
diff --git a/chrome/browser/engagement/site_engagement_helper.h b/chrome/browser/engagement/site_engagement_helper.h
index 3077afb5..68d4f32 100644
--- a/chrome/browser/engagement/site_engagement_helper.h
+++ b/chrome/browser/engagement/site_engagement_helper.h
@@ -9,6 +9,7 @@
 #include "base/timer/timer.h"
 #include "chrome/browser/engagement/site_engagement_metrics.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
 
diff --git a/chrome/browser/extensions/active_script_controller.cc b/chrome/browser/extensions/active_script_controller.cc
index e2e3ab6..1eb1ae2 100644
--- a/chrome/browser/extensions/active_script_controller.cc
+++ b/chrome/browser/extensions/active_script_controller.cc
@@ -65,37 +65,6 @@
   RunPendingForExtension(extension);
 }
 
-void ActiveScriptController::AlwaysRunOnVisibleOrigin(
-    const Extension* extension) {
-  const GURL& url = web_contents()->GetVisibleURL();
-  URLPatternSet new_explicit_hosts;
-  URLPatternSet new_scriptable_hosts;
-
-  const PermissionSet& withheld_permissions =
-      extension->permissions_data()->withheld_permissions();
-  if (withheld_permissions.explicit_hosts().MatchesURL(url)) {
-    new_explicit_hosts.AddOrigin(UserScript::ValidUserScriptSchemes(),
-                                 url.GetOrigin());
-  }
-  if (withheld_permissions.scriptable_hosts().MatchesURL(url)) {
-    new_scriptable_hosts.AddOrigin(UserScript::ValidUserScriptSchemes(),
-                                   url.GetOrigin());
-  }
-
-
-  // Update permissions for the session. This adds |new_permissions| to active
-  // permissions and granted permissions.
-  // TODO(devlin): Make sure that the permission is removed from
-  // withheld_permissions if appropriate.
-  PermissionsUpdater(browser_context_)
-      .AddPermissions(extension,
-                      PermissionSet(APIPermissionSet(), ManifestPermissionSet(),
-                                    new_explicit_hosts, new_scriptable_hosts));
-
-  // Allow current tab to run injection.
-  OnClicked(extension);
-}
-
 void ActiveScriptController::OnClicked(const Extension* extension) {
   DCHECK(ContainsKey(pending_requests_, extension->id()));
   RunPendingForExtension(extension);
diff --git a/chrome/browser/extensions/active_script_controller.h b/chrome/browser/extensions/active_script_controller.h
index d05e9a3..1db2f74b 100644
--- a/chrome/browser/extensions/active_script_controller.h
+++ b/chrome/browser/extensions/active_script_controller.h
@@ -53,10 +53,6 @@
   // extension.
   void OnActiveTabPermissionGranted(const Extension* extension);
 
-  // Adds the visible origin to |extension|'s active permissions, granting
-  // |extension| permission to always run script injections on the origin.
-  void AlwaysRunOnVisibleOrigin(const Extension* extension);
-
   // Notifies the ActiveScriptController that the action for |extension| has
   // been clicked, running any pending tasks that were previously shelved.
   void OnClicked(const Extension* extension);
diff --git a/chrome/browser/extensions/active_script_controller_unittest.cc b/chrome/browser/extensions/active_script_controller_unittest.cc
index 497077d..3d21d5c 100644
--- a/chrome/browser/extensions/active_script_controller_unittest.cc
+++ b/chrome/browser/extensions/active_script_controller_unittest.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/extensions/extension_sync_service_factory.h"
 #include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/extensions/permissions_updater.h"
+#include "chrome/browser/extensions/scripting_permissions_modifier.h"
 #include "chrome/browser/extensions/tab_helper.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
@@ -384,7 +385,9 @@
   EXPECT_EQ(0u, GetExecutionCountForExtension(extension->id()));
 
   // Allow the extension to always run on this origin.
-  controller()->AlwaysRunOnVisibleOrigin(extension);
+  ScriptingPermissionsModifier modifier(profile(), extension);
+  modifier.GrantHostPermission(web_contents()->GetLastCommittedURL());
+  controller()->OnClicked(extension);
 
   // The extension should execute, and the extension shouldn't want to run.
   EXPECT_EQ(1u, GetExecutionCountForExtension(extension->id()));
diff --git a/chrome/browser/extensions/api/developer_private/extension_info_generator.cc b/chrome/browser/extensions/api/developer_private/extension_info_generator.cc
index a7efa10..dd2d583c 100644
--- a/chrome/browser/extensions/api/developer_private/extension_info_generator.cc
+++ b/chrome/browser/extensions/api/developer_private/extension_info_generator.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/extensions/extension_ui_util.h"
 #include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/extensions/path_util.h"
+#include "chrome/browser/extensions/scripting_permissions_modifier.h"
 #include "chrome/browser/extensions/shared_module_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
@@ -498,12 +499,13 @@
   }
 
   // Runs on all urls.
+  ScriptingPermissionsModifier permissions_modifier(
+      browser_context_, make_scoped_refptr(&extension));
   info->run_on_all_urls.is_enabled =
       (FeatureSwitch::scripts_require_action()->IsEnabled() &&
-       PermissionsData::ScriptsMayRequireActionForExtension(
-           &extension, extension.permissions_data()->active_permissions())) ||
-      extension.permissions_data()->HasWithheldImpliedAllHosts() ||
-      util::HasSetAllowedScriptingOnAllUrls(extension.id(), browser_context_);
+       permissions_modifier.CanAffectExtension(
+           extension.permissions_data()->active_permissions())) ||
+      permissions_modifier.HasAffectedExtension();
   info->run_on_all_urls.is_active =
       util::AllowedScriptingOnAllUrls(extension.id(), browser_context_);
 
diff --git a/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc b/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
index dc2ac63..3934405 100644
--- a/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
+++ b/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
@@ -33,6 +33,7 @@
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/resource_controller.h"
 #include "content/public/browser/resource_dispatcher_host.h"
 #include "content/public/browser/resource_throttle.h"
@@ -542,9 +543,9 @@
   mouse_event.x = 7;
   mouse_event.y = 7;
   mouse_event.clickCount = 1;
-  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+  tab->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(mouse_event);
   mouse_event.type = blink::WebInputEvent::MouseUp;
-  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+  tab->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(mouse_event);
 
   ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
 }
@@ -574,9 +575,9 @@
   mouse_event.x = 7;
   mouse_event.y = 7;
   mouse_event.clickCount = 1;
-  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+  tab->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(mouse_event);
   mouse_event.type = blink::WebInputEvent::MouseUp;
-  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+  tab->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(mouse_event);
 
   ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
 }
@@ -604,9 +605,9 @@
   mouse_event.x = 7;
   mouse_event.y = 7;
   mouse_event.clickCount = 1;
-  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+  tab->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(mouse_event);
   mouse_event.type = blink::WebInputEvent::MouseUp;
-  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+  tab->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(mouse_event);
 
   ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
 }
diff --git a/chrome/browser/extensions/api/web_request/web_request_apitest.cc b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
index 410c54ef..45524672 100644
--- a/chrome/browser/extensions/api/web_request/web_request_apitest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
@@ -14,6 +14,7 @@
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
 #include "extensions/browser/api/web_request/web_request_api.h"
@@ -151,9 +152,9 @@
   mouse_event.x = 7;
   mouse_event.y = 7;
   mouse_event.clickCount = 1;
-  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+  tab->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(mouse_event);
   mouse_event.type = blink::WebInputEvent::MouseUp;
-  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+  tab->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(mouse_event);
 
   ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
 }
diff --git a/chrome/browser/extensions/extension_context_menu_model.cc b/chrome/browser/extensions/extension_context_menu_model.cc
index 7b33a7e2..d97ee3ab 100644
--- a/chrome/browser/extensions/extension_context_menu_model.cc
+++ b/chrome/browser/extensions/extension_context_menu_model.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/extensions/extension_uninstall_dialog.h"
 #include "chrome/browser/extensions/menu_manager.h"
+#include "chrome/browser/extensions/scripting_permissions_modifier.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sessions/session_tab_helper.h"
 #include "chrome/browser/ui/browser.h"
@@ -242,8 +243,10 @@
     case ALWAYS_RUN: {
       content::WebContents* web_contents = GetActiveWebContents();
       if (web_contents) {
+        ScriptingPermissionsModifier(profile_, extension)
+            .GrantHostPermission(web_contents->GetLastCommittedURL());
         ActiveScriptController::GetForWebContents(web_contents)
-            ->AlwaysRunOnVisibleOrigin(extension);
+            ->OnClicked(extension);
       }
       break;
     }
diff --git a/chrome/browser/extensions/extension_util.cc b/chrome/browser/extensions/extension_util.cc
index 97a0177..9696561 100644
--- a/chrome/browser/extensions/extension_util.cc
+++ b/chrome/browser/extensions/extension_util.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_sync_service.h"
 #include "chrome/browser/extensions/permissions_updater.h"
+#include "chrome/browser/extensions/scripting_permissions_modifier.h"
 #include "chrome/browser/extensions/shared_module_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
@@ -98,11 +99,11 @@
         ExtensionRegistry::Get(context)->enabled_extensions().GetByID(
             extension_id);
     if (extension) {
-      PermissionsUpdater updater(context);
+      ScriptingPermissionsModifier modifier(context, extension);
       if (allowed)
-        updater.GrantWithheldImpliedAllHosts(extension);
+        modifier.GrantWithheldImpliedAllHosts();
       else
-        updater.WithholdImpliedAllHosts(extension);
+        modifier.WithholdImpliedAllHosts();
 
       // If this was an update to permissions, we also need to sync the change.
       ExtensionSyncService* sync_service = ExtensionSyncService::Get(context);
diff --git a/chrome/browser/extensions/extension_view_host.cc b/chrome/browser/extensions/extension_view_host.cc
index df711fa..eca369a6 100644
--- a/chrome/browser/extensions/extension_view_host.cc
+++ b/chrome/browser/extensions/extension_view_host.cc
@@ -19,6 +19,7 @@
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/browser/runtime_data.h"
diff --git a/chrome/browser/extensions/favicon_downloader_unittest.cc b/chrome/browser/extensions/favicon_downloader_unittest.cc
index 7bacba1..78026231 100644
--- a/chrome/browser/extensions/favicon_downloader_unittest.cc
+++ b/chrome/browser/extensions/favicon_downloader_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/extensions/favicon_downloader.h"
 
+#include "base/bind.h"
 #include "base/files/scoped_temp_dir.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "content/public/common/favicon_url.h"
diff --git a/chrome/browser/extensions/permissions_updater.cc b/chrome/browser/extensions/permissions_updater.cc
index 7ad22f6..5957a3f 100644
--- a/chrome/browser/extensions/permissions_updater.cc
+++ b/chrome/browser/extensions/permissions_updater.cc
@@ -9,7 +9,7 @@
 #include "base/values.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/api/permissions/permissions_api_helpers.h"
-#include "chrome/browser/extensions/extension_util.h"
+#include "chrome/browser/extensions/scripting_permissions_modifier.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/extensions/api/permissions.h"
 #include "content/public/browser/notification_observer.h"
@@ -36,27 +36,6 @@
 
 namespace {
 
-// Returns a set of single origin permissions from |permissions| that match
-// |bounds|. This is necessary for two reasons:
-//   a) single origin active permissions can get filtered out in
-//      GetBoundedActivePermissions because they are not recognized as a subset
-//      of all-host permissions
-//   b) active permissions that do not match any manifest permissions can
-//      exist if a manifest permission is dropped
-URLPatternSet FilterSingleOriginPermissions(const URLPatternSet& permissions,
-                                            const URLPatternSet& bounds) {
-  URLPatternSet single_origin_permissions;
-  for (URLPatternSet::const_iterator iter = permissions.begin();
-       iter != permissions.end();
-       ++iter) {
-    if (iter->MatchesSingleOrigin() &&
-        bounds.MatchesURL(GURL(iter->GetAsString()))) {
-      single_origin_permissions.AddPattern(*iter);
-    }
-  }
-  return single_origin_permissions;
-}
-
 // Returns a PermissionSet that has the active permissions of the extension,
 // bounded to its current manifest.
 scoped_ptr<const PermissionSet> GetBoundedActivePermissions(
@@ -92,23 +71,6 @@
   return adjusted_active;
 }
 
-// Divvy up the |url patterns| between those we grant and those we do not. If
-// |withhold_permissions| is false (because the requisite feature is not
-// enabled), no permissions are withheld.
-void SegregateUrlPermissions(const URLPatternSet& url_patterns,
-                             bool withhold_permissions,
-                             URLPatternSet* granted,
-                             URLPatternSet* withheld) {
-  for (URLPatternSet::const_iterator iter = url_patterns.begin();
-       iter != url_patterns.end();
-       ++iter) {
-    if (withhold_permissions && iter->ImpliesAllHosts())
-      withheld->AddPattern(*iter);
-    else
-      granted->AddPattern(*iter);
-  }
-}
-
 }  // namespace
 
 PermissionsUpdater::PermissionsUpdater(content::BrowserContext* browser_context)
@@ -131,7 +93,10 @@
   scoped_ptr<const PermissionSet> added =
       PermissionSet::CreateDifference(*total, active);
 
-  SetPermissions(extension, total.Pass(), nullptr);
+  scoped_ptr<const PermissionSet> new_withheld =
+      PermissionSet::CreateDifference(
+          extension->permissions_data()->withheld_permissions(), permissions);
+  SetPermissions(extension, total.Pass(), new_withheld.Pass());
 
   // Update the granted permissions so we don't auto-disable the extension.
   GrantActivePermissions(extension);
@@ -191,44 +156,16 @@
 
 scoped_ptr<const PermissionSet> PermissionsUpdater::GetRevokablePermissions(
     const Extension* extension) const {
-  // Optional permissions are revokable.
-  scoped_ptr<const PermissionSet> wrapper;
-  const PermissionSet* revokable_permissions =
-      &PermissionsParser::GetOptionalPermissions(extension);
-  const PermissionSet& active_permissions =
-      extension->permissions_data()->active_permissions();
-  // If click-to-script is enabled, then any hosts that are granted, but not
-  // listed explicitly as a required permission, are also revokable.
-  if (FeatureSwitch::scripts_require_action()->IsEnabled()) {
-    const PermissionSet& required_permissions =
-        PermissionsParser::GetRequiredPermissions(extension);
-    auto find_revokable_hosts = [](const URLPatternSet& active_hosts,
-                                   const URLPatternSet& required_hosts) {
-      URLPatternSet revokable_hosts;
-      for (const URLPattern& pattern : active_hosts) {
-        if (std::find(required_hosts.begin(), required_hosts.end(), pattern) ==
-            required_hosts.end()) {
-          revokable_hosts.AddPattern(pattern);
-        }
-      }
-      return revokable_hosts;
-    };
-    URLPatternSet revokable_explicit_hosts =
-        find_revokable_hosts(active_permissions.explicit_hosts(),
-                             required_permissions.explicit_hosts());
-    URLPatternSet revokable_scriptable_hosts =
-        find_revokable_hosts(active_permissions.scriptable_hosts(),
-                             required_permissions.scriptable_hosts());
-    scoped_ptr<const PermissionSet> revokable_host_permissions(
-        new PermissionSet(APIPermissionSet(), ManifestPermissionSet(),
-                          revokable_explicit_hosts,
-                          revokable_scriptable_hosts));
-    wrapper = PermissionSet::CreateUnion(*revokable_permissions,
-                                         *revokable_host_permissions);
-    revokable_permissions = wrapper.get();
-  }
-  return PermissionSet::CreateIntersection(active_permissions,
-                                           *revokable_permissions);
+  // The user can revoke any permissions they granted. In other words, any
+  // permissions the extension didn't start with can be revoked.
+  const PermissionSet& required =
+      PermissionsParser::GetRequiredPermissions(extension);
+  scoped_ptr<const PermissionSet> granted;
+  scoped_ptr<const PermissionSet> withheld;
+  ScriptingPermissionsModifier(browser_context_, make_scoped_refptr(extension))
+      .WithholdPermissions(required, &granted, &withheld, false);
+  return PermissionSet::CreateDifference(
+      extension->permissions_data()->active_permissions(), *granted);
 }
 
 void PermissionsUpdater::GrantActivePermissions(const Extension* extension) {
@@ -240,142 +177,30 @@
 }
 
 void PermissionsUpdater::InitializePermissions(const Extension* extension) {
-  scoped_ptr<const PermissionSet> active_wrapper;
   scoped_ptr<const PermissionSet> bounded_wrapper;
-  const PermissionSet* active_permissions = nullptr;
   const PermissionSet* bounded_active = nullptr;
   // If |extension| is a transient dummy extension, we do not want to look for
   // it in preferences.
   if (init_flag_ & INIT_FLAG_TRANSIENT) {
-    active_permissions = bounded_active =
-        &extension->permissions_data()->active_permissions();
+    bounded_active = &extension->permissions_data()->active_permissions();
   } else {
-    // As part of initializing permissions, we restrict access to the main
-    // thread.
-    active_wrapper = ExtensionPrefs::Get(browser_context_)
-                         ->GetActivePermissions(extension->id());
-    active_permissions = active_wrapper.get();
+    scoped_ptr<const PermissionSet> active_permissions =
+        ExtensionPrefs::Get(browser_context_)
+            ->GetActivePermissions(extension->id());
     bounded_wrapper =
-        GetBoundedActivePermissions(extension, active_permissions);
+        GetBoundedActivePermissions(extension, active_permissions.get());
     bounded_active = bounded_wrapper.get();
   }
 
-  // Determine whether or not to withhold host permissions.
-  bool should_withhold_permissions = false;
-  if (PermissionsData::ScriptsMayRequireActionForExtension(extension,
-                                                           *bounded_active)) {
-    should_withhold_permissions =
-        init_flag_ & INIT_FLAG_TRANSIENT ?
-            !util::DefaultAllowedScriptingOnAllUrls() :
-            !util::AllowedScriptingOnAllUrls(extension->id(), browser_context_);
-  }
+  scoped_ptr<const PermissionSet> granted_permissions;
+  scoped_ptr<const PermissionSet> withheld_permissions;
+  ScriptingPermissionsModifier(browser_context_, make_scoped_refptr(extension))
+      .WithholdPermissions(*bounded_active, &granted_permissions,
+                           &withheld_permissions,
+                           (init_flag_ & INIT_FLAG_TRANSIENT) == 0);
 
-  URLPatternSet granted_explicit_hosts;
-  URLPatternSet withheld_explicit_hosts;
-  SegregateUrlPermissions(bounded_active->explicit_hosts(),
-                          should_withhold_permissions,
-                          &granted_explicit_hosts,
-                          &withheld_explicit_hosts);
-
-  URLPatternSet granted_scriptable_hosts;
-  URLPatternSet withheld_scriptable_hosts;
-  SegregateUrlPermissions(bounded_active->scriptable_hosts(),
-                          should_withhold_permissions,
-                          &granted_scriptable_hosts,
-                          &withheld_scriptable_hosts);
-
-  // After withholding permissions, add back any origins to the active set that
-  // may have been lost during the set operations that would have dropped them.
-  // For example, the union of <all_urls> and "example.com" is <all_urls>, so
-  // we may lose "example.com". However, "example.com" is important once
-  // <all_urls> is stripped during withholding.
-  if (active_permissions) {
-    granted_explicit_hosts.AddPatterns(
-        FilterSingleOriginPermissions(active_permissions->explicit_hosts(),
-                                      bounded_active->explicit_hosts()));
-    granted_scriptable_hosts.AddPatterns(
-        FilterSingleOriginPermissions(active_permissions->scriptable_hosts(),
-                                      bounded_active->scriptable_hosts()));
-  }
-
-  scoped_ptr<const PermissionSet> new_permissions(new PermissionSet(
-      bounded_active->apis(), bounded_active->manifest_permissions(),
-      granted_explicit_hosts, granted_scriptable_hosts));
-
-  scoped_ptr<const PermissionSet> withheld(
-      new PermissionSet(APIPermissionSet(), ManifestPermissionSet(),
-                        withheld_explicit_hosts, withheld_scriptable_hosts));
-  SetPermissions(extension, new_permissions.Pass(), withheld.Pass());
-}
-
-void PermissionsUpdater::WithholdImpliedAllHosts(const Extension* extension) {
-  const PermissionSet& active =
-      extension->permissions_data()->active_permissions();
-  const PermissionSet& withheld =
-      extension->permissions_data()->withheld_permissions();
-
-  URLPatternSet withheld_scriptable = withheld.scriptable_hosts();
-  URLPatternSet active_scriptable;
-  SegregateUrlPermissions(active.scriptable_hosts(),
-                          true,  // withhold permissions
-                          &active_scriptable, &withheld_scriptable);
-
-  URLPatternSet withheld_explicit = withheld.explicit_hosts();
-  URLPatternSet active_explicit;
-  SegregateUrlPermissions(active.explicit_hosts(),
-                          true,  // withhold permissions
-                          &active_explicit, &withheld_explicit);
-
-  URLPatternSet delta_explicit =
-      URLPatternSet::CreateDifference(active.explicit_hosts(), active_explicit);
-  URLPatternSet delta_scriptable = URLPatternSet::CreateDifference(
-      active.scriptable_hosts(), active_scriptable);
-
-  SetPermissions(extension, make_scoped_ptr(new PermissionSet(
-                                active.apis(), active.manifest_permissions(),
-                                active_explicit, active_scriptable)),
-                 make_scoped_ptr(new PermissionSet(
-                     withheld.apis(), withheld.manifest_permissions(),
-                     withheld_explicit, withheld_scriptable)));
-
-  NotifyPermissionsUpdated(
-      REMOVED, extension,
-      PermissionSet(APIPermissionSet(), ManifestPermissionSet(), delta_explicit,
-                    delta_scriptable));
-}
-
-void PermissionsUpdater::GrantWithheldImpliedAllHosts(
-    const Extension* extension) {
-  const PermissionSet& active =
-      extension->permissions_data()->active_permissions();
-  const PermissionSet& withheld =
-      extension->permissions_data()->withheld_permissions();
-
-  // Move the all-hosts permission from withheld to active.
-  // We can cheat a bit here since we know that the only host permission we
-  // withhold is allhosts (or something similar enough to it), so we can just
-  // grant all withheld host permissions.
-  URLPatternSet explicit_hosts = URLPatternSet::CreateUnion(
-      active.explicit_hosts(), withheld.explicit_hosts());
-  URLPatternSet scriptable_hosts = URLPatternSet::CreateUnion(
-      active.scriptable_hosts(), withheld.scriptable_hosts());
-
-  URLPatternSet delta_explicit =
-      URLPatternSet::CreateDifference(explicit_hosts, active.explicit_hosts());
-  URLPatternSet delta_scriptable = URLPatternSet::CreateDifference(
-      scriptable_hosts, active.scriptable_hosts());
-
-  // Since we only withhold host permissions (so far), we know that withheld
-  // permissions will be empty.
-  SetPermissions(extension, make_scoped_ptr(new PermissionSet(
-                                active.apis(), active.manifest_permissions(),
-                                explicit_hosts, scriptable_hosts)),
-                 make_scoped_ptr(new PermissionSet()));
-
-  NotifyPermissionsUpdated(
-      ADDED, extension,
-      PermissionSet(APIPermissionSet(), ManifestPermissionSet(), delta_explicit,
-                    delta_scriptable));
+  SetPermissions(extension, granted_permissions.Pass(),
+                 withheld_permissions.Pass());
 }
 
 void PermissionsUpdater::SetPermissions(
diff --git a/chrome/browser/extensions/permissions_updater.h b/chrome/browser/extensions/permissions_updater.h
index 47d63c4..c92ada8 100644
--- a/chrome/browser/extensions/permissions_updater.h
+++ b/chrome/browser/extensions/permissions_updater.h
@@ -81,12 +81,6 @@
   // required by the extension.
   void InitializePermissions(const Extension* extension);
 
-  // Grants any withheld all-hosts (or all-hosts-like) permissions.
-  void GrantWithheldImpliedAllHosts(const Extension* extension);
-
-  // Revokes any requests all-hosts (or all-hosts-like) permissions.
-  void WithholdImpliedAllHosts(const Extension* extension);
-
  private:
   enum EventType {
     ADDED,
diff --git a/chrome/browser/extensions/permissions_updater_unittest.cc b/chrome/browser/extensions/permissions_updater_unittest.cc
index 2f4470f..1de34014 100644
--- a/chrome/browser/extensions/permissions_updater_unittest.cc
+++ b/chrome/browser/extensions/permissions_updater_unittest.cc
@@ -53,69 +53,6 @@
       .Build();
 }
 
-scoped_refptr<const Extension> CreateExtensionWithPermissions(
-    const std::set<URLPattern>& scriptable_hosts,
-    const std::set<URLPattern>& explicit_hosts,
-    Manifest::Location location,
-    const std::string& name) {
-  ListBuilder scriptable_host_list;
-  for (std::set<URLPattern>::const_iterator pattern = scriptable_hosts.begin();
-       pattern != scriptable_hosts.end();
-       ++pattern) {
-    scriptable_host_list.Append(pattern->GetAsString());
-  }
-
-  ListBuilder explicit_host_list;
-  for (std::set<URLPattern>::const_iterator pattern = explicit_hosts.begin();
-       pattern != explicit_hosts.end();
-       ++pattern) {
-    explicit_host_list.Append(pattern->GetAsString());
-  }
-
-  DictionaryBuilder script;
-  script.Set("matches", scriptable_host_list.Pass())
-      .Set("js", ListBuilder().Append("foo.js"));
-
-  return ExtensionBuilder()
-      .SetLocation(location)
-      .SetManifest(
-           DictionaryBuilder()
-               .Set("name", name)
-               .Set("description", "foo")
-               .Set("manifest_version", 2)
-               .Set("version", "0.1.2.3")
-               .Set("content_scripts", ListBuilder().Append(script.Pass()))
-               .Set("permissions", explicit_host_list.Pass()))
-      .SetID(crx_file::id_util::GenerateId(name))
-      .Build();
-}
-
-testing::AssertionResult SetsAreEqual(const std::set<URLPattern>& set1,
-                                      const std::set<URLPattern>& set2) {
-  // Take the (set1 - set2) U (set2 - set1). This is then the set of all
-  // elements which are in either set1 or set2, but not both.
-  // If the sets are equal, this is none.
-  std::set<URLPattern> difference = base::STLSetUnion<std::set<URLPattern> >(
-      base::STLSetDifference<std::set<URLPattern> >(set1, set2),
-      base::STLSetDifference<std::set<URLPattern> >(set2, set1));
-
-  std::string error;
-  for (std::set<URLPattern>::const_iterator iter = difference.begin();
-       iter != difference.end();
-       ++iter) {
-    if (iter->GetAsString() == "chrome://favicon/*")
-      continue;  // Grr... This is auto-added for extensions with <all_urls>
-    error = base::StringPrintf("%s\n%s contains %s and the other does not.",
-                               error.c_str(),
-                               (set1.count(*iter) ? "Set1" : "Set2"),
-                               iter->GetAsString().c_str());
-  }
-
-  if (!error.empty())
-    return testing::AssertionFailure() << error;
-  return testing::AssertionSuccess();
-}
-
 // A helper class that listens for NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED.
 class PermissionsUpdaterListener : public content::NotificationObserver {
  public:
@@ -290,202 +227,6 @@
   }
 }
 
-TEST_F(PermissionsUpdaterTest, WithholdAllHosts) {
-  InitializeEmptyExtensionService();
-
-  // Permissions are only withheld with the appropriate switch turned on.
-  scoped_ptr<FeatureSwitch::ScopedOverride> switch_override(
-      new FeatureSwitch::ScopedOverride(FeatureSwitch::scripts_require_action(),
-                                        FeatureSwitch::OVERRIDE_ENABLED));
-
-  URLPattern google(URLPattern::SCHEME_ALL, "http://www.google.com/*");
-  URLPattern sub_google(URLPattern::SCHEME_ALL, "http://*.google.com/*");
-  URLPattern all_http(URLPattern::SCHEME_ALL, "http://*/*");
-  URLPattern all_hosts(URLPattern::SCHEME_ALL, "<all_urls>");
-  URLPattern all_com(URLPattern::SCHEME_ALL, "http://*.com/*");
-
-  std::set<URLPattern> all_host_patterns;
-  std::set<URLPattern> safe_patterns;
-
-  all_host_patterns.insert(all_http);
-  all_host_patterns.insert(all_hosts);
-  all_host_patterns.insert(all_com);
-
-  safe_patterns.insert(google);
-  safe_patterns.insert(sub_google);
-
-  std::set<URLPattern> all_patterns = base::STLSetUnion<std::set<URLPattern> >(
-      all_host_patterns, safe_patterns);
-
-  scoped_refptr<const Extension> extension = CreateExtensionWithPermissions(
-      all_patterns, all_patterns, Manifest::INTERNAL, "a");
-  const PermissionsData* permissions_data = extension->permissions_data();
-  PermissionsUpdater updater(profile_.get());
-  updater.InitializePermissions(extension.get());
-
-  // At first, the active permissions should have only the safe patterns and
-  // the withheld permissions should have only the all host patterns.
-  EXPECT_TRUE(SetsAreEqual(
-      permissions_data->active_permissions().scriptable_hosts().patterns(),
-      safe_patterns));
-  EXPECT_TRUE(SetsAreEqual(
-      permissions_data->active_permissions().explicit_hosts().patterns(),
-      safe_patterns));
-  EXPECT_TRUE(SetsAreEqual(
-      permissions_data->withheld_permissions().scriptable_hosts().patterns(),
-      all_host_patterns));
-  EXPECT_TRUE(SetsAreEqual(
-      permissions_data->withheld_permissions().explicit_hosts().patterns(),
-      all_host_patterns));
-
-  // Then, we grant the withheld all-hosts permissions.
-  updater.GrantWithheldImpliedAllHosts(extension.get());
-  // Now, active permissions should have all patterns, and withheld permissions
-  // should have none.
-  EXPECT_TRUE(SetsAreEqual(
-      permissions_data->active_permissions().scriptable_hosts().patterns(),
-      all_patterns));
-  EXPECT_TRUE(permissions_data->withheld_permissions()
-                  .scriptable_hosts()
-                  .patterns()
-                  .empty());
-  EXPECT_TRUE(SetsAreEqual(
-      permissions_data->active_permissions().explicit_hosts().patterns(),
-      all_patterns));
-  EXPECT_TRUE(permissions_data->withheld_permissions()
-                  .explicit_hosts()
-                  .patterns()
-                  .empty());
-
-  // Finally, we revoke the all hosts permissions.
-  updater.WithholdImpliedAllHosts(extension.get());
-
-  // We should be back to our initial state - all_hosts should be withheld, and
-  // the safe patterns should be granted.
-  EXPECT_TRUE(SetsAreEqual(
-      permissions_data->active_permissions().scriptable_hosts().patterns(),
-      safe_patterns));
-  EXPECT_TRUE(SetsAreEqual(
-      permissions_data->active_permissions().explicit_hosts().patterns(),
-      safe_patterns));
-  EXPECT_TRUE(SetsAreEqual(
-      permissions_data->withheld_permissions().scriptable_hosts().patterns(),
-      all_host_patterns));
-  EXPECT_TRUE(SetsAreEqual(
-      permissions_data->withheld_permissions().explicit_hosts().patterns(),
-      all_host_patterns));
-
-  // Creating a component extension should result in no withheld permissions.
-  extension = CreateExtensionWithPermissions(
-      all_patterns, all_patterns, Manifest::COMPONENT, "b");
-  permissions_data = extension->permissions_data();
-  updater.InitializePermissions(extension.get());
-  EXPECT_TRUE(SetsAreEqual(
-      permissions_data->active_permissions().scriptable_hosts().patterns(),
-      all_patterns));
-  EXPECT_TRUE(permissions_data->withheld_permissions()
-                  .scriptable_hosts()
-                  .patterns()
-                  .empty());
-  EXPECT_TRUE(SetsAreEqual(
-      permissions_data->active_permissions().explicit_hosts().patterns(),
-      all_patterns));
-  EXPECT_TRUE(permissions_data->withheld_permissions()
-                  .explicit_hosts()
-                  .patterns()
-                  .empty());
-
-  // Without the switch, we shouldn't withhold anything.
-  switch_override.reset();
-  extension = CreateExtensionWithPermissions(
-      all_patterns, all_patterns, Manifest::INTERNAL, "c");
-  permissions_data = extension->permissions_data();
-  updater.InitializePermissions(extension.get());
-  EXPECT_TRUE(SetsAreEqual(
-      permissions_data->active_permissions().scriptable_hosts().patterns(),
-      all_patterns));
-  EXPECT_TRUE(permissions_data->withheld_permissions()
-                  .scriptable_hosts()
-                  .patterns()
-                  .empty());
-  EXPECT_TRUE(SetsAreEqual(
-      permissions_data->active_permissions().explicit_hosts().patterns(),
-      all_patterns));
-  EXPECT_TRUE(permissions_data->withheld_permissions()
-                  .explicit_hosts()
-                  .patterns()
-                  .empty());
-}
-
-// Tests that withholding all hosts behaves properly with extensions installed
-// when the switch is turned on and off.
-TEST_F(PermissionsUpdaterTest, WithholdAllHostsWithTransientSwitch) {
-  InitializeEmptyExtensionService();
-
-  URLPattern all_hosts(URLPattern::SCHEME_ALL, "<all_urls>");
-  std::set<URLPattern> all_host_patterns;
-  all_host_patterns.insert(all_hosts);
-
-  scoped_refptr<const Extension> extension_a = CreateExtensionWithPermissions(
-      all_host_patterns, all_host_patterns, Manifest::INTERNAL, "a");
-  PermissionsUpdater updater(profile());
-  updater.InitializePermissions(extension_a.get());
-  const PermissionsData* permissions_data = extension_a->permissions_data();
-
-  // Since the extension was created without the switch on, it should default
-  // to having all urls access.
-  EXPECT_TRUE(SetsAreEqual(
-      permissions_data->active_permissions().scriptable_hosts().patterns(),
-      all_host_patterns));
-  EXPECT_TRUE(
-      permissions_data->withheld_permissions().scriptable_hosts().is_empty());
-  EXPECT_TRUE(util::AllowedScriptingOnAllUrls(extension_a->id(), profile()));
-
-  // Enable the switch, and re-init permission for the extension.
-  scoped_ptr<FeatureSwitch::ScopedOverride> switch_override(
-      new FeatureSwitch::ScopedOverride(FeatureSwitch::scripts_require_action(),
-                                        FeatureSwitch::OVERRIDE_ENABLED));
-  updater.InitializePermissions(extension_a.get());
-
-  // Since the extension was installed when the switch was off, it should still
-  // have the all urls pref.
-  permissions_data = extension_a->permissions_data();
-  EXPECT_TRUE(SetsAreEqual(
-      permissions_data->active_permissions().scriptable_hosts().patterns(),
-      all_host_patterns));
-  EXPECT_TRUE(
-      permissions_data->withheld_permissions().scriptable_hosts().is_empty());
-  EXPECT_TRUE(util::AllowedScriptingOnAllUrls(extension_a->id(), profile()));
-
-  // Load a new extension, which also has all urls. Since the switch is now on,
-  // the permissions should be withheld.
-  scoped_refptr<const Extension> extension_b = CreateExtensionWithPermissions(
-      all_host_patterns, all_host_patterns, Manifest::INTERNAL, "b");
-  updater.InitializePermissions(extension_b.get());
-  permissions_data = extension_b->permissions_data();
-
-  EXPECT_TRUE(
-      permissions_data->active_permissions().scriptable_hosts().is_empty());
-  EXPECT_TRUE(SetsAreEqual(
-      permissions_data->withheld_permissions().scriptable_hosts().patterns(),
-      all_host_patterns));
-  EXPECT_FALSE(util::AllowedScriptingOnAllUrls(extension_b->id(), profile()));
-
-  // Disable the switch, and reload the extension.
-  switch_override.reset();
-  updater.InitializePermissions(extension_b.get());
-
-  // Since the extension was installed with the switch on, it should still be
-  // restricted with the switch off.
-  permissions_data = extension_b->permissions_data();
-  EXPECT_TRUE(
-      permissions_data->active_permissions().scriptable_hosts().is_empty());
-  EXPECT_TRUE(SetsAreEqual(
-      permissions_data->withheld_permissions().scriptable_hosts().patterns(),
-      all_host_patterns));
-  EXPECT_FALSE(util::AllowedScriptingOnAllUrls(extension_b->id(), profile()));
-}
-
 TEST_F(PermissionsUpdaterTest, RevokingPermissions) {
   InitializeEmptyExtensionService();
 
diff --git a/chrome/browser/extensions/scripting_permissions_modifier.cc b/chrome/browser/extensions/scripting_permissions_modifier.cc
new file mode 100644
index 0000000..eaaa9b68
--- /dev/null
+++ b/chrome/browser/extensions/scripting_permissions_modifier.cc
@@ -0,0 +1,194 @@
+// Copyright 2015 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 "chrome/browser/extensions/scripting_permissions_modifier.h"
+
+#include "chrome/browser/extensions/extension_util.h"
+#include "chrome/browser/extensions/permissions_updater.h"
+#include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/feature_switch.h"
+#include "extensions/common/manifest_handlers/permissions_parser.h"
+#include "extensions/common/permissions/permission_set.h"
+#include "extensions/common/permissions/permissions_data.h"
+#include "extensions/common/user_script.h"
+
+namespace extensions {
+
+namespace {
+
+URLPatternSet FilterImpliedAllHostsPatterns(const URLPatternSet& patterns) {
+  URLPatternSet result;
+  for (const URLPattern& pattern : patterns) {
+    if (pattern.ImpliesAllHosts())
+      result.AddPattern(pattern);
+  }
+  return result;
+}
+
+}  // namespace
+
+ScriptingPermissionsModifier::ScriptingPermissionsModifier(
+    content::BrowserContext* browser_context,
+    const scoped_refptr<const Extension>& extension)
+    : browser_context_(browser_context), extension_(extension) {}
+
+ScriptingPermissionsModifier::~ScriptingPermissionsModifier() {}
+
+bool ScriptingPermissionsModifier::CanAffectExtension(
+    const PermissionSet& permissions) const {
+  // An extension may require user action to execute scripts iff the extension
+  // shows up in chrome:extensions (so the user can grant withheld permissions),
+  // is not part of chrome or corporate policy, not on the scripting whitelist,
+  // and requires enough permissions that we should withhold them.
+  return extension_->ShouldDisplayInExtensionSettings() &&
+         !Manifest::IsPolicyLocation(extension_->location()) &&
+         !Manifest::IsComponentLocation(extension_->location()) &&
+         !PermissionsData::CanExecuteScriptEverywhere(extension_.get()) &&
+         permissions.ShouldWarnAllHosts();
+}
+
+bool ScriptingPermissionsModifier::HasAffectedExtension() const {
+  return extension_->permissions_data()->HasWithheldImpliedAllHosts() ||
+         util::HasSetAllowedScriptingOnAllUrls(extension_->id(),
+                                               browser_context_);
+}
+
+void ScriptingPermissionsModifier::GrantHostPermission(const GURL& url) const {
+  GURL origin = url.GetOrigin();
+  URLPatternSet new_explicit_hosts;
+  URLPatternSet new_scriptable_hosts;
+
+  const PermissionSet& withheld_permissions =
+      extension_->permissions_data()->withheld_permissions();
+  if (withheld_permissions.explicit_hosts().MatchesURL(url)) {
+    new_explicit_hosts.AddOrigin(UserScript::ValidUserScriptSchemes(), origin);
+  }
+  if (withheld_permissions.scriptable_hosts().MatchesURL(url)) {
+    new_scriptable_hosts.AddOrigin(UserScript::ValidUserScriptSchemes(),
+                                   origin);
+  }
+
+  PermissionsUpdater(browser_context_)
+      .AddPermissions(extension_.get(),
+                      PermissionSet(APIPermissionSet(), ManifestPermissionSet(),
+                                    new_explicit_hosts, new_scriptable_hosts));
+}
+
+bool ScriptingPermissionsModifier::HasGrantedHostPermission(
+    const GURL& url) const {
+  GURL origin = url.GetOrigin();
+  const PermissionSet& required_permissions =
+      PermissionsParser::GetRequiredPermissions(extension_.get());
+  if (!extension_->permissions_data()
+           ->active_permissions()
+           .effective_hosts()
+           .MatchesURL(origin))
+    return false;
+  scoped_ptr<const PermissionSet> granted_permissions;
+  scoped_ptr<const PermissionSet> withheld_permissions;
+  WithholdPermissions(required_permissions, &granted_permissions,
+                      &withheld_permissions, false);
+  if (!granted_permissions->effective_hosts().MatchesURL(origin) &&
+      withheld_permissions->effective_hosts().MatchesURL(origin))
+    return true;
+
+  return false;
+}
+
+void ScriptingPermissionsModifier::RemoveGrantedHostPermission(
+    const GURL& url) const {
+  DCHECK(HasGrantedHostPermission(url));
+
+  GURL origin = url.GetOrigin();
+  URLPatternSet explicit_hosts;
+  URLPatternSet scriptable_hosts;
+  const PermissionSet& active_permissions =
+      extension_->permissions_data()->active_permissions();
+  if (active_permissions.explicit_hosts().MatchesURL(url))
+    explicit_hosts.AddOrigin(UserScript::ValidUserScriptSchemes(), origin);
+  if (active_permissions.scriptable_hosts().MatchesURL(url))
+    scriptable_hosts.AddOrigin(UserScript::ValidUserScriptSchemes(), origin);
+
+  PermissionsUpdater(browser_context_)
+      .RemovePermissions(
+          extension_.get(),
+          PermissionSet(APIPermissionSet(), ManifestPermissionSet(),
+                        explicit_hosts, scriptable_hosts),
+          PermissionsUpdater::REMOVE_HARD);
+}
+
+void ScriptingPermissionsModifier::WithholdPermissions(
+    const PermissionSet& permissions,
+    scoped_ptr<const PermissionSet>* granted_permissions_out,
+    scoped_ptr<const PermissionSet>* withheld_permissions_out,
+    bool check_prefs) const {
+  bool should_withhold = false;
+  if (CanAffectExtension(permissions))
+    should_withhold = check_prefs
+                          ? !util::AllowedScriptingOnAllUrls(extension_->id(),
+                                                             browser_context_)
+                          : !util::DefaultAllowedScriptingOnAllUrls();
+
+  if (!should_withhold) {
+    *granted_permissions_out = permissions.Clone();
+    withheld_permissions_out->reset(new PermissionSet());
+    return;
+  }
+
+  auto segregate_url_permissions = [](const URLPatternSet& patterns,
+                                      URLPatternSet* granted,
+                                      URLPatternSet* withheld) {
+    for (const URLPattern& pattern : patterns) {
+      if (pattern.ImpliesAllHosts())
+        withheld->AddPattern(pattern);
+      else
+        granted->AddPattern(pattern);
+    }
+  };
+
+  URLPatternSet granted_explicit_hosts;
+  URLPatternSet withheld_explicit_hosts;
+  URLPatternSet granted_scriptable_hosts;
+  URLPatternSet withheld_scriptable_hosts;
+  segregate_url_permissions(permissions.explicit_hosts(),
+                            &granted_explicit_hosts, &withheld_explicit_hosts);
+  segregate_url_permissions(permissions.scriptable_hosts(),
+                            &granted_scriptable_hosts,
+                            &withheld_scriptable_hosts);
+
+  granted_permissions_out->reset(
+      new PermissionSet(permissions.apis(), permissions.manifest_permissions(),
+                        granted_explicit_hosts, granted_scriptable_hosts));
+  withheld_permissions_out->reset(
+      new PermissionSet(APIPermissionSet(), ManifestPermissionSet(),
+                        withheld_explicit_hosts, withheld_scriptable_hosts));
+}
+
+void ScriptingPermissionsModifier::GrantWithheldImpliedAllHosts() const {
+  const PermissionSet& withheld =
+      extension_->permissions_data()->withheld_permissions();
+
+  PermissionSet permissions(
+      APIPermissionSet(), ManifestPermissionSet(),
+      FilterImpliedAllHostsPatterns(withheld.explicit_hosts()),
+      FilterImpliedAllHostsPatterns(withheld.scriptable_hosts()));
+  PermissionsUpdater(browser_context_)
+      .AddPermissions(extension_.get(), permissions);
+}
+
+void ScriptingPermissionsModifier::WithholdImpliedAllHosts() const {
+  const PermissionSet& active =
+      extension_->permissions_data()->active_permissions();
+  PermissionSet permissions(
+      APIPermissionSet(), ManifestPermissionSet(),
+      FilterImpliedAllHostsPatterns(active.explicit_hosts()),
+      FilterImpliedAllHostsPatterns(active.scriptable_hosts()));
+  PermissionsUpdater(browser_context_)
+      .RemovePermissions(extension_.get(), permissions,
+                         PermissionsUpdater::REMOVE_HARD);
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/scripting_permissions_modifier.h b/chrome/browser/extensions/scripting_permissions_modifier.h
new file mode 100644
index 0000000..82758cc
--- /dev/null
+++ b/chrome/browser/extensions/scripting_permissions_modifier.h
@@ -0,0 +1,80 @@
+// Copyright 2015 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 CHROME_BROWSER_EXTENSIONS_SCRIPTING_PERMISSIONS_MODIFIER_H_
+#define CHROME_BROWSER_EXTENSIONS_SCRIPTING_PERMISSIONS_MODIFIER_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+
+class GURL;
+
+namespace content {
+class BrowserContext;
+}
+
+namespace extensions {
+class Extension;
+class PermissionSet;
+
+// Responsible for managing the majority of click-to-script features, including
+// granting, withholding, and querying host permissions, and determining if an
+// extension has been affected by the click-to-script project.
+class ScriptingPermissionsModifier {
+ public:
+  ScriptingPermissionsModifier(content::BrowserContext* browser_context,
+                               const scoped_refptr<const Extension>& extension);
+  ~ScriptingPermissionsModifier();
+
+  // Returns true if the --scripts-require-action flag would possibly affect
+  // the given extension and |permissions|. We pass in the |permissions|
+  // explicitly, as we may need to check with permissions other than the ones
+  // that are currently on the extension's PermissionsData.
+  bool CanAffectExtension(const PermissionSet& permissions) const;
+
+  // Returns true if the extension has been affected by the scripts-require-
+  // action flag.
+  bool HasAffectedExtension() const;
+
+  // Grants the extension permission to run on the origin of |url|.
+  void GrantHostPermission(const GURL& url) const;
+
+  // Returns true if the extension has been explicitly granted permission to run
+  // on the origin of |url|.
+  bool HasGrantedHostPermission(const GURL& url) const;
+
+  // Revokes permission to run on the origin of |url|. DCHECKs if |url| has not
+  // been granted.
+  void RemoveGrantedHostPermission(const GURL& url) const;
+
+  // Takes in a set of permissions and withholds any permissions that should not
+  // be granted, populating |granted_permissions_out| with the set of all
+  // permissions that can be granted, and |withheld_permissions_out| with the
+  // set of all withheld permissions.
+  // If |check_prefs| is false, this won't take into account preferences like
+  // AllowedScriptingOnAllUrls().
+  void WithholdPermissions(
+      const PermissionSet& permissions,
+      scoped_ptr<const PermissionSet>* granted_permissions_out,
+      scoped_ptr<const PermissionSet>* withheld_permissions_out,
+      bool check_prefs) const;
+
+  // Grants any withheld all-hosts (or all-hosts-like) permissions.
+  void GrantWithheldImpliedAllHosts() const;
+
+  // Revokes any granted all-hosts (or all-hosts-like) permissions.
+  void WithholdImpliedAllHosts() const;
+
+ private:
+  content::BrowserContext* browser_context_;
+
+  scoped_refptr<const Extension> extension_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScriptingPermissionsModifier);
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_SCRIPTING_PERMISSIONS_MODIFIER_H_
diff --git a/chrome/browser/extensions/scripting_permissions_modifier_unittest.cc b/chrome/browser/extensions/scripting_permissions_modifier_unittest.cc
new file mode 100644
index 0000000..1b1a71da
--- /dev/null
+++ b/chrome/browser/extensions/scripting_permissions_modifier_unittest.cc
@@ -0,0 +1,330 @@
+// Copyright 2015 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 "base/strings/stringprintf.h"
+#include "chrome/browser/extensions/extension_service_test_base.h"
+#include "chrome/browser/extensions/extension_util.h"
+#include "chrome/browser/extensions/permissions_updater.h"
+#include "chrome/browser/extensions/scripting_permissions_modifier.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/crx_file/id_util.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/extension_builder.h"
+#include "extensions/common/feature_switch.h"
+#include "extensions/common/permissions/permission_set.h"
+#include "extensions/common/permissions/permissions_data.h"
+#include "extensions/common/url_pattern.h"
+#include "extensions/common/url_pattern_set.h"
+#include "extensions/common/value_builder.h"
+
+namespace extensions {
+
+namespace {
+
+scoped_refptr<const Extension> CreateExtensionWithPermissions(
+    const std::set<URLPattern>& scriptable_hosts,
+    const std::set<URLPattern>& explicit_hosts,
+    Manifest::Location location,
+    const std::string& name) {
+  ListBuilder scriptable_host_list;
+  for (std::set<URLPattern>::const_iterator pattern = scriptable_hosts.begin();
+       pattern != scriptable_hosts.end(); ++pattern) {
+    scriptable_host_list.Append(pattern->GetAsString());
+  }
+
+  ListBuilder explicit_host_list;
+  for (std::set<URLPattern>::const_iterator pattern = explicit_hosts.begin();
+       pattern != explicit_hosts.end(); ++pattern) {
+    explicit_host_list.Append(pattern->GetAsString());
+  }
+
+  DictionaryBuilder script;
+  script.Set("matches", scriptable_host_list.Pass())
+      .Set("js", ListBuilder().Append("foo.js"));
+
+  return ExtensionBuilder()
+      .SetLocation(location)
+      .SetManifest(
+          DictionaryBuilder()
+              .Set("name", name)
+              .Set("description", "foo")
+              .Set("manifest_version", 2)
+              .Set("version", "0.1.2.3")
+              .Set("content_scripts", ListBuilder().Append(script.Pass()))
+              .Set("permissions", explicit_host_list.Pass()))
+      .SetID(crx_file::id_util::GenerateId(name))
+      .Build();
+}
+
+testing::AssertionResult SetsAreEqual(const std::set<URLPattern>& set1,
+                                      const std::set<URLPattern>& set2) {
+  // Take the (set1 - set2) U (set2 - set1). This is then the set of all
+  // elements which are in either set1 or set2, but not both.
+  // If the sets are equal, this is none.
+  std::set<URLPattern> difference = base::STLSetUnion<std::set<URLPattern>>(
+      base::STLSetDifference<std::set<URLPattern>>(set1, set2),
+      base::STLSetDifference<std::set<URLPattern>>(set2, set1));
+
+  std::string error;
+  for (std::set<URLPattern>::const_iterator iter = difference.begin();
+       iter != difference.end(); ++iter) {
+    if (iter->GetAsString() == "chrome://favicon/*")
+      continue;  // Grr... This is auto-added for extensions with <all_urls>
+    error = base::StringPrintf(
+        "%s\n%s contains %s and the other does not.", error.c_str(),
+        (set1.count(*iter) ? "Set1" : "Set2"), iter->GetAsString().c_str());
+  }
+
+  if (!error.empty())
+    return testing::AssertionFailure() << error;
+  return testing::AssertionSuccess();
+}
+
+using ScriptingPermissionsModifierUnitTest = ExtensionServiceTestBase;
+
+}  // namespace
+
+TEST_F(ScriptingPermissionsModifierUnitTest, WithholdAllHosts) {
+  InitializeEmptyExtensionService();
+
+  // Permissions are only withheld with the appropriate switch turned on.
+  scoped_ptr<FeatureSwitch::ScopedOverride> switch_override(
+      new FeatureSwitch::ScopedOverride(FeatureSwitch::scripts_require_action(),
+                                        FeatureSwitch::OVERRIDE_ENABLED));
+
+  URLPattern google(URLPattern::SCHEME_ALL, "http://www.google.com/*");
+  URLPattern sub_google(URLPattern::SCHEME_ALL, "http://*.google.com/*");
+  URLPattern all_http(URLPattern::SCHEME_ALL, "http://*/*");
+  URLPattern all_hosts(URLPattern::SCHEME_ALL, "<all_urls>");
+  URLPattern all_com(URLPattern::SCHEME_ALL, "http://*.com/*");
+
+  std::set<URLPattern> all_host_patterns;
+  std::set<URLPattern> safe_patterns;
+
+  all_host_patterns.insert(all_http);
+  all_host_patterns.insert(all_hosts);
+  all_host_patterns.insert(all_com);
+
+  safe_patterns.insert(google);
+  safe_patterns.insert(sub_google);
+
+  std::set<URLPattern> all_patterns =
+      base::STLSetUnion<std::set<URLPattern>>(all_host_patterns, safe_patterns);
+
+  scoped_refptr<const Extension> extension = CreateExtensionWithPermissions(
+      all_patterns, all_patterns, Manifest::INTERNAL, "a");
+  const PermissionsData* permissions_data = extension->permissions_data();
+  PermissionsUpdater updater(profile());
+  updater.InitializePermissions(extension.get());
+
+  // At first, the active permissions should have only the safe patterns and
+  // the withheld permissions should have only the all host patterns.
+  EXPECT_TRUE(SetsAreEqual(
+      permissions_data->active_permissions().scriptable_hosts().patterns(),
+      safe_patterns));
+  EXPECT_TRUE(SetsAreEqual(
+      permissions_data->active_permissions().explicit_hosts().patterns(),
+      safe_patterns));
+  EXPECT_TRUE(SetsAreEqual(
+      permissions_data->withheld_permissions().scriptable_hosts().patterns(),
+      all_host_patterns));
+  EXPECT_TRUE(SetsAreEqual(
+      permissions_data->withheld_permissions().explicit_hosts().patterns(),
+      all_host_patterns));
+
+  ScriptingPermissionsModifier modifier(profile(), extension);
+  // Then, we grant the withheld all-hosts permissions.
+  modifier.GrantWithheldImpliedAllHosts();
+  // Now, active permissions should have all patterns, and withheld permissions
+  // should have none.
+  EXPECT_TRUE(SetsAreEqual(
+      permissions_data->active_permissions().scriptable_hosts().patterns(),
+      all_patterns));
+  EXPECT_TRUE(permissions_data->withheld_permissions()
+                  .scriptable_hosts()
+                  .patterns()
+                  .empty());
+  EXPECT_TRUE(SetsAreEqual(
+      permissions_data->active_permissions().explicit_hosts().patterns(),
+      all_patterns));
+  EXPECT_TRUE(permissions_data->withheld_permissions()
+                  .explicit_hosts()
+                  .patterns()
+                  .empty());
+
+  // Finally, we revoke the all hosts permissions.
+  modifier.WithholdImpliedAllHosts();
+
+  // We should be back to our initial state - all_hosts should be withheld, and
+  // the safe patterns should be granted.
+  EXPECT_TRUE(SetsAreEqual(
+      permissions_data->active_permissions().scriptable_hosts().patterns(),
+      safe_patterns));
+  EXPECT_TRUE(SetsAreEqual(
+      permissions_data->active_permissions().explicit_hosts().patterns(),
+      safe_patterns));
+  EXPECT_TRUE(SetsAreEqual(
+      permissions_data->withheld_permissions().scriptable_hosts().patterns(),
+      all_host_patterns));
+  EXPECT_TRUE(SetsAreEqual(
+      permissions_data->withheld_permissions().explicit_hosts().patterns(),
+      all_host_patterns));
+
+  // Creating a component extension should result in no withheld permissions.
+  extension = CreateExtensionWithPermissions(all_patterns, all_patterns,
+                                             Manifest::COMPONENT, "b");
+  permissions_data = extension->permissions_data();
+  updater.InitializePermissions(extension.get());
+  EXPECT_TRUE(SetsAreEqual(
+      permissions_data->active_permissions().scriptable_hosts().patterns(),
+      all_patterns));
+  EXPECT_TRUE(permissions_data->withheld_permissions()
+                  .scriptable_hosts()
+                  .patterns()
+                  .empty());
+  EXPECT_TRUE(SetsAreEqual(
+      permissions_data->active_permissions().explicit_hosts().patterns(),
+      all_patterns));
+  EXPECT_TRUE(permissions_data->withheld_permissions()
+                  .explicit_hosts()
+                  .patterns()
+                  .empty());
+
+  // Without the switch, we shouldn't withhold anything.
+  switch_override.reset();
+  extension = CreateExtensionWithPermissions(all_patterns, all_patterns,
+                                             Manifest::INTERNAL, "c");
+  permissions_data = extension->permissions_data();
+  updater.InitializePermissions(extension.get());
+  EXPECT_TRUE(SetsAreEqual(
+      permissions_data->active_permissions().scriptable_hosts().patterns(),
+      all_patterns));
+  EXPECT_TRUE(permissions_data->withheld_permissions()
+                  .scriptable_hosts()
+                  .patterns()
+                  .empty());
+  EXPECT_TRUE(SetsAreEqual(
+      permissions_data->active_permissions().explicit_hosts().patterns(),
+      all_patterns));
+  EXPECT_TRUE(permissions_data->withheld_permissions()
+                  .explicit_hosts()
+                  .patterns()
+                  .empty());
+}
+
+// Tests that withholding all hosts behaves properly with extensions installed
+// when the switch is turned on and off.
+TEST_F(ScriptingPermissionsModifierUnitTest,
+       WithholdAllHostsWithTransientSwitch) {
+  InitializeEmptyExtensionService();
+
+  URLPattern all_hosts(URLPattern::SCHEME_ALL, "<all_urls>");
+  std::set<URLPattern> all_host_patterns;
+  all_host_patterns.insert(all_hosts);
+
+  scoped_refptr<const Extension> extension_a = CreateExtensionWithPermissions(
+      all_host_patterns, all_host_patterns, Manifest::INTERNAL, "a");
+  PermissionsUpdater updater(profile());
+  updater.InitializePermissions(extension_a.get());
+  const PermissionsData* permissions_data = extension_a->permissions_data();
+
+  // Since the extension was created without the switch on, it should default
+  // to having all urls access.
+  EXPECT_TRUE(SetsAreEqual(
+      permissions_data->active_permissions().scriptable_hosts().patterns(),
+      all_host_patterns));
+  EXPECT_TRUE(
+      permissions_data->withheld_permissions().scriptable_hosts().is_empty());
+  EXPECT_TRUE(util::AllowedScriptingOnAllUrls(extension_a->id(), profile()));
+
+  // Enable the switch, and re-init permission for the extension.
+  scoped_ptr<FeatureSwitch::ScopedOverride> switch_override(
+      new FeatureSwitch::ScopedOverride(FeatureSwitch::scripts_require_action(),
+                                        FeatureSwitch::OVERRIDE_ENABLED));
+  updater.InitializePermissions(extension_a.get());
+
+  // Since the extension was installed when the switch was off, it should still
+  // have the all urls pref.
+  permissions_data = extension_a->permissions_data();
+  EXPECT_TRUE(SetsAreEqual(
+      permissions_data->active_permissions().scriptable_hosts().patterns(),
+      all_host_patterns));
+  EXPECT_TRUE(
+      permissions_data->withheld_permissions().scriptable_hosts().is_empty());
+  EXPECT_TRUE(util::AllowedScriptingOnAllUrls(extension_a->id(), profile()));
+
+  // Load a new extension, which also has all urls. Since the switch is now on,
+  // the permissions should be withheld.
+  scoped_refptr<const Extension> extension_b = CreateExtensionWithPermissions(
+      all_host_patterns, all_host_patterns, Manifest::INTERNAL, "b");
+  updater.InitializePermissions(extension_b.get());
+  permissions_data = extension_b->permissions_data();
+  EXPECT_TRUE(
+      permissions_data->active_permissions().scriptable_hosts().is_empty());
+  EXPECT_TRUE(SetsAreEqual(
+      permissions_data->withheld_permissions().scriptable_hosts().patterns(),
+      all_host_patterns));
+  EXPECT_FALSE(util::AllowedScriptingOnAllUrls(extension_b->id(), profile()));
+
+  // Disable the switch, and reload the extension.
+  switch_override.reset();
+  updater.InitializePermissions(extension_b.get());
+
+  // Since the extension was installed with the switch on, it should still be
+  // restricted with the switch off.
+  permissions_data = extension_b->permissions_data();
+  EXPECT_TRUE(
+      permissions_data->active_permissions().scriptable_hosts().is_empty());
+  EXPECT_TRUE(SetsAreEqual(
+      permissions_data->withheld_permissions().scriptable_hosts().patterns(),
+      all_host_patterns));
+  EXPECT_FALSE(util::AllowedScriptingOnAllUrls(extension_b->id(), profile()));
+}
+
+TEST_F(ScriptingPermissionsModifierUnitTest, GrantHostPermission) {
+  InitializeEmptyExtensionService();
+
+  // Permissions are only withheld with the appropriate switch turned on.
+  scoped_ptr<FeatureSwitch::ScopedOverride> switch_override(
+      new FeatureSwitch::ScopedOverride(FeatureSwitch::scripts_require_action(),
+                                        FeatureSwitch::OVERRIDE_ENABLED));
+
+  URLPattern all_hosts(URLPattern::SCHEME_ALL, "<all_urls>");
+  std::set<URLPattern> all_host_patterns;
+  all_host_patterns.insert(all_hosts);
+
+  scoped_refptr<const Extension> extension = CreateExtensionWithPermissions(
+      all_host_patterns, all_host_patterns, Manifest::INTERNAL, "extension");
+  PermissionsUpdater(profile()).InitializePermissions(extension.get());
+
+  ScriptingPermissionsModifier modifier(profile(), extension);
+
+  const GURL kUrl("https://www.google.com/");
+  const GURL kUrl2("https://www.chromium.org/");
+  EXPECT_FALSE(modifier.HasGrantedHostPermission(kUrl));
+  EXPECT_FALSE(modifier.HasGrantedHostPermission(kUrl2));
+
+  const PermissionsData* permissions = extension->permissions_data();
+  auto get_page_access = [&permissions, &extension](const GURL& url) {
+    return permissions->GetPageAccess(extension.get(), url, 0 /* tab id */,
+                                      0 /* process id */, nullptr /* error */);
+  };
+
+  EXPECT_EQ(PermissionsData::ACCESS_WITHHELD, get_page_access(kUrl));
+  EXPECT_EQ(PermissionsData::ACCESS_WITHHELD, get_page_access(kUrl2));
+
+  modifier.GrantHostPermission(kUrl);
+  EXPECT_TRUE(modifier.HasGrantedHostPermission(kUrl));
+  EXPECT_FALSE(modifier.HasGrantedHostPermission(kUrl2));
+  EXPECT_EQ(PermissionsData::ACCESS_ALLOWED, get_page_access(kUrl));
+  EXPECT_EQ(PermissionsData::ACCESS_WITHHELD, get_page_access(kUrl2));
+
+  modifier.RemoveGrantedHostPermission(kUrl);
+  EXPECT_FALSE(modifier.HasGrantedHostPermission(kUrl));
+  EXPECT_FALSE(modifier.HasGrantedHostPermission(kUrl2));
+  EXPECT_EQ(PermissionsData::ACCESS_WITHHELD, get_page_access(kUrl));
+  EXPECT_EQ(PermissionsData::ACCESS_WITHHELD, get_page_access(kUrl2));
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/file_select_helper.cc b/chrome/browser/file_select_helper.cc
index bbfae1b..034ec98 100644
--- a/chrome/browser/file_select_helper.cc
+++ b/chrome/browser/file_select_helper.cc
@@ -26,6 +26,7 @@
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
@@ -406,9 +407,8 @@
   notification_registrar_.RemoveAll();
   content::WebContentsObserver::Observe(web_contents_);
   notification_registrar_.Add(
-      this,
-      content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
-      content::Source<RenderWidgetHost>(render_view_host_));
+      this, content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
+      content::Source<RenderWidgetHost>(render_view_host_->GetWidget()));
 
   BrowserThread::PostTask(
       BrowserThread::FILE, FROM_HERE,
@@ -470,8 +470,8 @@
       params.default_file_name :
       profile_->last_selected_directory().Append(params.default_file_name);
 
-  gfx::NativeWindow owning_window =
-      platform_util::GetTopLevel(render_view_host_->GetView()->GetNativeView());
+  gfx::NativeWindow owning_window = platform_util::GetTopLevel(
+      render_view_host_->GetWidget()->GetView()->GetNativeView());
 
 #if defined(OS_ANDROID)
   // Android needs the original MIME types and an additional capture value.
@@ -539,7 +539,7 @@
   switch (type) {
     case content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED: {
       DCHECK(content::Source<RenderWidgetHost>(source).ptr() ==
-             render_view_host_);
+             render_view_host_->GetWidget());
       render_view_host_ = NULL;
       break;
     }
diff --git a/chrome/browser/media/android/remote/remote_media_player_bridge.cc b/chrome/browser/media/android/remote/remote_media_player_bridge.cc
index 3f9781e..4efd11b9 100644
--- a/chrome/browser/media/android/remote/remote_media_player_bridge.cc
+++ b/chrome/browser/media/android/remote/remote_media_player_bridge.cc
@@ -18,6 +18,7 @@
 #include "ui/gfx/android/java_bitmap.h"
 
 using base::android::ConvertUTF8ToJavaString;
+using base::android::ConvertJavaStringToUTF8;
 using base::android::ScopedJavaLocalRef;
 using base::android::AttachCurrentThread;
 
@@ -40,12 +41,8 @@
                          local_player->frame_url()),
       start_position_millis_(0),
       local_player_(local_player),
-      in_use_(false),
-      prepared_(false),
-      pending_play_(false),
       width_(0),
       height_(0),
-      should_seek_on_prepare_(false),
       hide_url_log_(hide_url_log),
       volume_(-1.0),
       url_(local_player->GetUrl()),
@@ -67,11 +64,10 @@
     j_frame_url_string = ConvertUTF8ToJavaString(
         env, local_player->frame_url().spec());
   }
-  java_bridge_.Reset(
-      Java_RemoteMediaPlayerBridge_create(env, reinterpret_cast<intptr_t>(this),
-                                          start_position_millis_,
-                                          j_url_string.obj(),
-                                          j_frame_url_string.obj()));
+  java_bridge_.Reset(Java_RemoteMediaPlayerBridge_create(
+      env, reinterpret_cast<intptr_t>(this), start_position_millis_,
+      j_url_string.obj(), j_frame_url_string.obj(),
+      ConvertUTF8ToJavaString(env, user_agent).obj()));
 }
 
 RemoteMediaPlayerBridge::~RemoteMediaPlayerBridge() {
@@ -102,30 +98,6 @@
 
 void RemoteMediaPlayerBridge::OnMediaInterrupted() {}
 
-void RemoteMediaPlayerBridge::OnMediaPrepared() {
-  if (!in_use_)
-    return;
-
-  prepared_ = true;
-  duration_ = GetDuration();
-
-  // If media player was recovered from a saved state, consume all the pending
-  // events.
-  if (should_seek_on_prepare_) {
-    PendingSeekInternal(pending_seek_);
-    pending_seek_ = base::TimeDelta::FromMilliseconds(0);
-    should_seek_on_prepare_ = false;
-  }
-
-  if (pending_play_) {
-    StartInternal();
-    pending_play_ = false;
-  }
-
-  manager()->OnMediaMetadataChanged(
-      player_id(), duration_, width_, height_, true);
-}
-
 void RemoteMediaPlayerBridge::StartInternal() {
   JNIEnv* env = AttachCurrentThread();
   Java_RemoteMediaPlayerBridge_start(env, java_bridge_.obj());
@@ -143,64 +115,37 @@
   time_update_timer_.Stop();
 }
 
-void RemoteMediaPlayerBridge::SeekInternal(base::TimeDelta time) {
-  if (time > duration_)
-    time = duration_;
-
-  // Seeking to an invalid position may cause media player to stuck in an
-  // error state.
-  if (time < base::TimeDelta()) {
-    DCHECK_EQ(-1.0, time.InMillisecondsF());
-    return;
-  }
-
-  JNIEnv* env = AttachCurrentThread();
-  CHECK(env);
-  int time_msec = static_cast<int>(time.InMilliseconds());
-  Java_RemoteMediaPlayerBridge_seekTo(
-      env, java_bridge_.obj(), time_msec);
-}
-
 void RemoteMediaPlayerBridge::OnTimeUpdateTimerFired() {
   manager()->OnTimeUpdate(
       player_id(), GetCurrentTime(), base::TimeTicks::Now());
 }
 
-void RemoteMediaPlayerBridge::PendingSeekInternal(const base::TimeDelta& time) {
-  SeekInternal(time);
+void RemoteMediaPlayerBridge::PauseLocal(JNIEnv* env, jobject obj) {
+  local_player_->Pause(true);
+  static_cast<RemoteMediaPlayerManager*>(manager())->OnPaused(player_id());
 }
 
-void RemoteMediaPlayerBridge::Prepare() {
-  DCHECK(!in_use_);
-  DCHECK(IsMediaPlayableRemotely());
-  in_use_ = true;
-  AttachListener(java_bridge_.obj());
-  JNIEnv* env = AttachCurrentThread();
-  CHECK(env);
+jint RemoteMediaPlayerBridge::GetLocalPosition(JNIEnv* env, jobject obj) {
+  base::TimeDelta time = local_player_->GetCurrentTime();
+  return static_cast<jint>(time.InMilliseconds());
+}
 
-  if (url_.is_valid()) {
-    // Create a Java String for the URL.
-    ScopedJavaLocalRef<jstring> j_url_string =
-        ConvertUTF8ToJavaString(env, url_.spec());
-
-    jobject j_context = base::android::GetApplicationContext();
-    DCHECK(j_context);
-
-    ScopedJavaLocalRef<jstring> j_cookies = ConvertUTF8ToJavaString(
-        env, cookies_);
-    ScopedJavaLocalRef<jstring> j_user_agent = ConvertUTF8ToJavaString(
-        env, user_agent_);
-
-    if (!Java_RemoteMediaPlayerBridge_setDataSource(
-        env, java_bridge_.obj(), j_context, j_url_string.obj(),
-        j_cookies.obj(), j_user_agent.obj(), hide_url_log_)) {
-      OnMediaError(MEDIA_ERROR_FORMAT);
-      return;
-    }
+void RemoteMediaPlayerBridge::OnCastStarting(JNIEnv* env,
+                                             jobject obj,
+                                             jstring casting_message) {
+  static_cast<RemoteMediaPlayerManager*>(manager())->SwitchToRemotePlayer(
+      player_id(), ConvertJavaStringToUTF8(env, casting_message));
+  if (!time_update_timer_.IsRunning()) {
+    time_update_timer_.Start(
+        FROM_HERE,
+        base::TimeDelta::FromMilliseconds(media::kTimeUpdateInterval), this,
+        &RemoteMediaPlayerBridge::OnTimeUpdateTimerFired);
   }
+}
 
-  if (!Java_RemoteMediaPlayerBridge_prepareAsync(env, java_bridge_.obj()))
-    OnMediaError(MEDIA_ERROR_FORMAT);
+void RemoteMediaPlayerBridge::OnCastStopping(JNIEnv* env, jobject obj) {
+  static_cast<RemoteMediaPlayerManager*>(manager())
+      ->SwitchToLocalPlayer(player_id());
 }
 
 void RemoteMediaPlayerBridge::Pause(bool is_media_related_action) {
@@ -209,14 +154,9 @@
   // reasons, such as freeing resources, etc. and during those times, the
   // remote video playback should not be paused.
   if (is_media_related_action) {
-    if (!in_use_) {
-      pending_play_ = false;
-    } else {
-      if (prepared_ && IsPlaying())
-        PauseInternal();
-      else
-        pending_play_ = false;
-    }
+    JNIEnv* env = AttachCurrentThread();
+    Java_RemoteMediaPlayerBridge_pause(env, java_bridge_.obj());
+    time_update_timer_.Stop();
   }
 }
 
@@ -241,15 +181,6 @@
   static_cast<RemoteMediaPlayerManager *>(manager())->OnPaused(player_id());
 }
 
-void RemoteMediaPlayerBridge::OnRouteSelected(JNIEnv* env, jobject obj,
-                                              jstring castingMessage) {
-  casting_message_.reset(
-      new std::string(
-          base::android::ConvertJavaStringToUTF8(env, castingMessage)));
-  static_cast<RemoteMediaPlayerManager *>(manager())->OnRemoteDeviceSelected(
-      player_id());
-}
-
 void RemoteMediaPlayerBridge::OnRouteUnselected(JNIEnv* env, jobject obj) {
   casting_message_.reset();
   static_cast<RemoteMediaPlayerManager *>(manager())->OnRemoteDeviceUnselected(
@@ -315,30 +246,6 @@
       env, java_bridge_.obj());
 }
 
-bool RemoteMediaPlayerBridge::IsRemotePlaybackAvailable() const {
-  JNIEnv* env = AttachCurrentThread();
-  CHECK(env);
-
-  jboolean result = Java_RemoteMediaPlayerBridge_isRemotePlaybackAvailable(
-      env, java_bridge_.obj());
-
-  return result;
-}
-
-bool RemoteMediaPlayerBridge::IsRemotePlaybackPreferredForFrame() const {
-  if (in_use_) {
-    // We have already decided to use remote playback
-    return true;
-  }
-  JNIEnv* env = AttachCurrentThread();
-  CHECK(env);
-
-  jboolean result =
-      Java_RemoteMediaPlayerBridge_isRemotePlaybackPreferredForFrame(
-          env, java_bridge_.obj());
-  return result;
-}
-
 std::string RemoteMediaPlayerBridge::GetCastingMessage() {
   return casting_message_ ?
       *casting_message_ : std::string();
@@ -361,51 +268,37 @@
 }
 
 void RemoteMediaPlayerBridge::Start() {
-  if (!in_use_) {
-    pending_play_ = true;
-    Prepare();
-  } else {
-    if (prepared_)
-      StartInternal();
-    else
-      pending_play_ = true;
-  }
+  StartInternal();
 }
 
-void RemoteMediaPlayerBridge::SeekTo(base::TimeDelta timestamp) {
-  // Record the time to seek when OnMediaPrepared() is called.
-  pending_seek_ = timestamp;
-  should_seek_on_prepare_ = true;
+void RemoteMediaPlayerBridge::SeekTo(base::TimeDelta time) {
+  // TODO(aberent) Move the checks to the Java side.
+  base::TimeDelta duration = GetDuration();
 
-  if (!in_use_)
-    Prepare();
-  else if (prepared_)
-    SeekInternal(timestamp);
+  if (time > duration)
+    time = duration;
+
+  // Seeking to an invalid position may cause media player to stuck in an
+  // error state.
+  if (time < base::TimeDelta()) {
+    DCHECK_EQ(-1.0, time.InMillisecondsF());
+    return;
+  }
+
+  JNIEnv* env = AttachCurrentThread();
+  CHECK(env);
+  int time_msec = static_cast<int>(time.InMilliseconds());
+  Java_RemoteMediaPlayerBridge_seekTo(env, java_bridge_.obj(), time_msec);
 }
 
 void RemoteMediaPlayerBridge::Release() {
-  if (!in_use_)
-    return;
   time_update_timer_.Stop();
-  if (prepared_) {
-    pending_seek_ = GetCurrentTime();
-    should_seek_on_prepare_ = true;
-  }
-
-  prepared_ = false;
-  pending_play_ = false;
   JNIEnv* env = AttachCurrentThread();
   Java_RemoteMediaPlayerBridge_release(env, java_bridge_.obj());
   DetachListener();
-  in_use_ = false;
 }
 
 void RemoteMediaPlayerBridge::SetVolume(double volume) {
-  if (!in_use_) {
-    volume_ = volume;
-    return;
-  }
-
   JNIEnv* env = AttachCurrentThread();
   CHECK(env);
   Java_RemoteMediaPlayerBridge_setVolume(
@@ -413,8 +306,6 @@
 }
 
 base::TimeDelta RemoteMediaPlayerBridge::GetCurrentTime() {
-  if (!prepared_)
-    return pending_seek_;
   JNIEnv* env = AttachCurrentThread();
   return base::TimeDelta::FromMilliseconds(
       Java_RemoteMediaPlayerBridge_getCurrentPosition(
@@ -422,8 +313,6 @@
 }
 
 base::TimeDelta RemoteMediaPlayerBridge::GetDuration() {
-  if (!prepared_)
-    return duration_;
   JNIEnv* env = AttachCurrentThread();
   const int duration_ms =
       Java_RemoteMediaPlayerBridge_getDuration(env, java_bridge_.obj());
@@ -439,9 +328,6 @@
 }
 
 bool RemoteMediaPlayerBridge::IsPlaying() {
-  if (!prepared_)
-    return pending_play_;
-
   JNIEnv* env = AttachCurrentThread();
   CHECK(env);
   jboolean result = Java_RemoteMediaPlayerBridge_isPlaying(
@@ -462,7 +348,7 @@
 }
 
 bool RemoteMediaPlayerBridge::IsPlayerReady() {
-  return prepared_;
+  return true;
 }
 
 GURL RemoteMediaPlayerBridge::GetUrl() {
@@ -483,14 +369,6 @@
                  weak_factory_.GetWeakPtr()));
 }
 
-bool RemoteMediaPlayerBridge::IsMediaPlayableRemotely() const {
-  JNIEnv* env = AttachCurrentThread();
-  CHECK(env);
-
-  return Java_RemoteMediaPlayerBridge_isMediaPlayableRemotely(
-      env, java_bridge_.obj());
-}
-
 base::android::ScopedJavaLocalRef<jstring> RemoteMediaPlayerBridge::GetTitle(
     JNIEnv* env, jobject obj) {
   base::string16 title;
@@ -509,6 +387,18 @@
   // TODO(aberent) Do we need to retrieve auth credentials for basic
   // authentication? MediaPlayerBridge does.
   cookies_ = cookies;
+  JNIEnv* env = AttachCurrentThread();
+  CHECK(env);
+  Java_RemoteMediaPlayerBridge_setCookies(
+      env, java_bridge_.obj(), ConvertUTF8ToJavaString(env, cookies).obj());
 }
 
-} // namespace remote_media
+bool RemoteMediaPlayerBridge::TakesOverCastDevice() {
+  JNIEnv* env = AttachCurrentThread();
+  CHECK(env);
+  jboolean result =
+      Java_RemoteMediaPlayerBridge_takesOverCastDevice(env, java_bridge_.obj());
+  return result;
+}
+
+}  // namespace remote_media
diff --git a/chrome/browser/media/android/remote/remote_media_player_bridge.h b/chrome/browser/media/android/remote/remote_media_player_bridge.h
index ce36079..ea21de7 100644
--- a/chrome/browser/media/android/remote/remote_media_player_bridge.h
+++ b/chrome/browser/media/android/remote/remote_media_player_bridge.h
@@ -59,11 +59,14 @@
       JNIEnv* env, jobject obj);
   void OnPlaying(JNIEnv* env, jobject obj);
   void OnPaused(JNIEnv* env, jobject obj);
-  void OnRouteSelected(JNIEnv* env, jobject obj, jstring castingMessage);
   void OnRouteUnselected(JNIEnv* env, jobject obj);
   void OnPlaybackFinished(JNIEnv* env, jobject obj);
   void OnRouteAvailabilityChanged(JNIEnv* env, jobject obj, jboolean available);
   base::android::ScopedJavaLocalRef<jstring> GetTitle(JNIEnv* env, jobject obj);
+  void PauseLocal(JNIEnv* env, jobject obj);
+  jint GetLocalPosition(JNIEnv* env, jobject obj);
+  void OnCastStarting(JNIEnv* env, jobject obj, jstring casting_message);
+  void OnCastStopping(JNIEnv* env, jobject obj);
 
   // Wrappers for calls to Java used by the remote media player manager
   void RequestRemotePlayback();
@@ -71,11 +74,7 @@
   void SetNativePlayer();
   void OnPlayerCreated();
   void OnPlayerDestroyed();
-  bool IsRemotePlaybackAvailable() const;
-  bool IsRemotePlaybackPreferredForFrame() const;
-
-  // Returns true if the we can play the media remotely
-  bool IsMediaPlayableRemotely() const;
+  bool TakesOverCastDevice();
 
   // Gets the message to display on the embedded player while casting.
   std::string GetCastingMessage();
@@ -88,13 +87,11 @@
   void OnVideoSizeChanged(int width, int height) override;
   void OnPlaybackComplete() override;
   void OnMediaInterrupted() override;
-  void OnMediaPrepared() override;
 
  private:
   // Functions that implements media player control.
   void StartInternal();
   void PauseInternal();
-  void SeekInternal(base::TimeDelta time);
 
   // Called when |time_update_timer_| fires.
   void OnTimeUpdateTimerFired();
@@ -103,8 +100,6 @@
   // are retrieved.
   void OnCookiesRetrieved(const std::string& cookies);
 
-  void PendingSeekInternal(const base::TimeDelta& time);
-
   // Prepare the player for playback, asynchronously. When succeeds,
   // OnMediaPrepared() will be called. Otherwise, OnMediaError() will
   // be called with an error type.
@@ -112,15 +107,10 @@
 
   long start_position_millis_;
   MediaPlayerAndroid* local_player_;
-  bool in_use_;
-  bool prepared_;
-  bool pending_play_;
   int width_;
   int height_;
   base::RepeatingTimer time_update_timer_;
   base::TimeDelta duration_;
-  bool should_seek_on_prepare_;
-  base::TimeDelta pending_seek_;
 
   // Hide url log from media player.
   bool hide_url_log_;
diff --git a/chrome/browser/media/android/remote/remote_media_player_manager.cc b/chrome/browser/media/android/remote/remote_media_player_manager.cc
index a5538aa2..2be1af0 100644
--- a/chrome/browser/media/android/remote/remote_media_player_manager.cc
+++ b/chrome/browser/media/android/remote/remote_media_player_manager.cc
@@ -23,13 +23,14 @@
 RemoteMediaPlayerManager::~RemoteMediaPlayerManager() {}
 
 void RemoteMediaPlayerManager::OnStart(int player_id) {
-  // TODO(aberent) This assumes this is the first time we have started this
-  // video, rather than restarting after pause. There is a lot of logic here
-  // that is unnecessary if we are restarting after pause.
-  if (MaybeStartPlayingRemotely(player_id))
-    return;
-
-  ReplaceRemotePlayerWithLocal();
+  RemoteMediaPlayerBridge* remote_player = GetRemotePlayer(player_id);
+  if (remote_player) {
+    if (IsPlayingRemotely(player_id)) {
+      remote_player->Start();
+    } else if (remote_player->TakesOverCastDevice()) {
+      return;
+    }
+  }
   BrowserMediaPlayerManager::OnStart(player_id);
 }
 
@@ -39,11 +40,8 @@
 
   MediaPlayerAndroid* player = GetPlayer(media_params.player_id);
   if (player) {
-    CreateRemoteMediaPlayer(player);
-    RemoteMediaPlayerBridge* remote_player = GetRemotePlayer(
-        media_params.player_id);
-    if (remote_player)
-      remote_player->OnPlayerCreated();
+    RemoteMediaPlayerBridge* remote_player = CreateRemoteMediaPlayer(player);
+    remote_player->OnPlayerCreated();
   }
 }
 
@@ -56,7 +54,7 @@
 
 void RemoteMediaPlayerManager::OnReleaseResources(int player_id) {
   // We only want to release resources of local players.
-  if (player_id != RemotePlayerId())
+  if (!IsPlayingRemotely(player_id))
     BrowserMediaPlayerManager::OnReleaseResources(player_id);
 }
 
@@ -125,130 +123,72 @@
       GetUserAgent(),
       false,
       this);
-  remote_players_.push_back(player);
+  alternative_players_.push_back(player);
   player->Initialize();
   return player;
 }
 
-int RemoteMediaPlayerManager::RemotePlayerId() {
-  // The remote player is created with the same id as the corresponding local
-  // player.
-  if (replaced_local_player_.get())
-    return replaced_local_player_->player_id();
-  else
-    return -1;
+// OnSuspend and OnResume are called when the local player loses or gains
+// audio focus. If we are playing remotely then ignore these.
+void RemoteMediaPlayerManager::OnSuspend(int player_id) {
+  if (!IsPlayingRemotely(player_id))
+    BrowserMediaPlayerManager::OnSuspend(player_id);
 }
 
-void RemoteMediaPlayerManager::ReplaceLocalPlayerWithRemote(
-    MediaPlayerAndroid* player) {
-  if (!player)
-    return;
+void RemoteMediaPlayerManager::OnResume(int player_id) {
+  if (!IsPlayingRemotely(player_id))
+    BrowserMediaPlayerManager::OnResume(player_id);
+}
 
-  int player_id = player->player_id();
-  if (player_id == RemotePlayerId()) {
-    // The player is already remote.
-    return;
-  }
-
-  // Before we replace the new remote player, put the old local player back
-  // in its place.
-  ReplaceRemotePlayerWithLocal();
-
-  // Pause the local player first before replacing it. This will allow the local
-  // player to reset its state, such as the PowerSaveBlocker.
-  // We have to pause locally as well as telling the renderer to pause, because
-  // by the time the renderer comes back to us telling us to pause we will have
-  // switched players.
-  player->Pause(true);
-  Send(new MediaPlayerMsg_DidMediaPlayerPause(RoutingID(), player_id));
-
+void RemoteMediaPlayerManager::SwapCurrentPlayer(int player_id) {
   // Find the remote player
-  for (auto it = remote_players_.begin(); it != remote_players_.end(); ++it) {
-    if ((*it)->player_id() == player_id) {
-      replaced_local_player_ = SwapPlayer(player_id, *it);
-
-      // Seek to the previous player's position.
-      (*it)->SeekTo(player->GetCurrentTime());
-
-      // SwapPlayers takes ownership, so we have to remove the remote player
-      // from the vector.
-      remote_players_.weak_erase(it);
-      break;
-    }
-  }
+  auto it = GetAlternativePlayer(player_id);
+  if (it == alternative_players_.end())
+    return;
+  MediaPlayerAndroid* new_player = *it;
+  scoped_ptr<MediaPlayerAndroid> old_player = SwapPlayer(player_id, new_player);
+  alternative_players_.weak_erase(it);
+  alternative_players_.push_back(old_player.release());
 }
 
-void RemoteMediaPlayerManager::ReplaceRemotePlayerWithLocal() {
-  int player_id = RemotePlayerId();
-  if (player_id == -1)
-    return;
+void RemoteMediaPlayerManager::SwitchToRemotePlayer(
+    int player_id,
+    const std::string& casting_message) {
+  DCHECK(!IsPlayingRemotely(player_id));
+  SwapCurrentPlayer(player_id);
+  players_playing_remotely_.insert(player_id);
+  Send(new MediaPlayerMsg_DidMediaPlayerPlay(RoutingID(), player_id));
+  Send(new MediaPlayerMsg_ConnectedToRemoteDevice(RoutingID(), player_id,
+                                                  casting_message));
+}
 
+void RemoteMediaPlayerManager::SwitchToLocalPlayer(int player_id) {
+  DCHECK(IsPlayingRemotely(player_id));
+  SwapCurrentPlayer(player_id);
+  players_playing_remotely_.erase(player_id);
+  Send(new MediaPlayerMsg_DisconnectedFromRemoteDevice(RoutingID(), player_id));
+}
+
+void RemoteMediaPlayerManager::ReplaceRemotePlayerWithLocal(int player_id) {
+  if (!IsPlayingRemotely(player_id))
+    return;
+  MediaPlayerAndroid* remote_player = GetPlayer(player_id);
+  remote_player->Pause(true);
   Send(new MediaPlayerMsg_DidMediaPlayerPause(RoutingID(), player_id));
   Send(new MediaPlayerMsg_DisconnectedFromRemoteDevice(RoutingID(), player_id));
 
-  scoped_ptr<MediaPlayerAndroid> remote_player =
-      SwapPlayer(player_id, replaced_local_player_.release());
-  if (remote_player) {
-    // Seek to the previous player's position.
-    GetPlayer(player_id)->SeekTo(remote_player->GetCurrentTime());
-
-    remote_player->Release();
-    // Add the remote player back into the list
-    remote_players_.push_back(
-        static_cast<RemoteMediaPlayerBridge *>(remote_player.release()));
-  }
-}
-
-bool RemoteMediaPlayerManager::MaybeStartPlayingRemotely(int player_id) {
-  MediaPlayerAndroid* player = GetPlayer(player_id);
-  if (!player)
-    return false;
-
-  RemoteMediaPlayerBridge* remote_player = GetRemotePlayer(player_id);
-
-  if (!remote_player)
-    return false;
-
-  if (remote_player->IsMediaPlayableRemotely() &&
-      remote_player->IsRemotePlaybackAvailable() &&
-      remote_player->IsRemotePlaybackPreferredForFrame()) {
-    ReplaceLocalPlayerWithRemote(player);
-
-    remote_player->SetNativePlayer();
-    remote_player->Start();
-
-    Send(new MediaPlayerMsg_DidMediaPlayerPlay(RoutingID(), player_id));
-
-    Send(new MediaPlayerMsg_ConnectedToRemoteDevice(
-        RoutingID(),
-        player_id,
-        remote_player->GetCastingMessage()));
-
-    return true;
-  }
-
-  return false;
-}
-
-void RemoteMediaPlayerManager::OnRemoteDeviceSelected(int player_id) {
-
-  MediaPlayerAndroid* player = GetPlayer(player_id);
-  if (!player)
-    return;
-
-  if (MaybeStartPlayingRemotely(player_id))
-    return;
-  OnStart(player_id);
+  SwapCurrentPlayer(player_id);
+  GetLocalPlayer(player_id)->SeekTo(remote_player->GetCurrentTime());
+  remote_player->Release();
+  players_playing_remotely_.erase(player_id);
 }
 
 void RemoteMediaPlayerManager::OnRemoteDeviceUnselected(int player_id) {
-  if (player_id == RemotePlayerId())
-    ReplaceRemotePlayerWithLocal();
+  ReplaceRemotePlayerWithLocal(player_id);
 }
 
 void RemoteMediaPlayerManager::OnRemotePlaybackFinished(int player_id) {
-  if (player_id == RemotePlayerId())
-    ReplaceRemotePlayerWithLocal();
+  ReplaceRemotePlayerWithLocal(player_id);
 }
 
 void RemoteMediaPlayerManager::OnRouteAvailabilityChanged(
@@ -260,10 +200,11 @@
 
 void RemoteMediaPlayerManager::ReleaseFullscreenPlayer(
     MediaPlayerAndroid* player) {
+  int player_id = player->player_id();
   // Release the original player's resources, not the current fullscreen player
   // (which is the remote player).
-  if (replaced_local_player_.get())
-    replaced_local_player_->Release();
+  if (IsPlayingRemotely(player_id))
+    GetLocalPlayer(player_id)->Release();
   else
     BrowserMediaPlayerManager::ReleaseFullscreenPlayer(player);
 }
@@ -276,18 +217,34 @@
   Send(new MediaPlayerMsg_DidMediaPlayerPause(RoutingID(),player_id));
 }
 
+ScopedVector<MediaPlayerAndroid>::iterator
+RemoteMediaPlayerManager::GetAlternativePlayer(int player_id) {
+  for (auto it = alternative_players_.begin(); it != alternative_players_.end();
+       ++it) {
+    if ((*it)->player_id() == player_id) {
+      return it;
+    }
+  }
+  return alternative_players_.end();
+}
+
 RemoteMediaPlayerBridge* RemoteMediaPlayerManager::GetRemotePlayer(
     int player_id) {
-  if (player_id == RemotePlayerId()) {
+  if (IsPlayingRemotely(player_id))
     return static_cast<RemoteMediaPlayerBridge*>(GetPlayer(player_id));
-  } else {
-    for (RemoteMediaPlayerBridge* player : remote_players_) {
-      if (player->player_id() == player_id) {
-        return player;
-      }
-    }
+  auto it = GetAlternativePlayer(player_id);
+  if (it == alternative_players_.end())
     return nullptr;
-  }
+  return static_cast<RemoteMediaPlayerBridge*>(*it);
+}
+
+MediaPlayerAndroid* RemoteMediaPlayerManager::GetLocalPlayer(int player_id) {
+  if (!IsPlayingRemotely(player_id))
+    return static_cast<RemoteMediaPlayerBridge*>(GetPlayer(player_id));
+  auto it = GetAlternativePlayer(player_id);
+  if (it == alternative_players_.end())
+    return nullptr;
+  return *it;
 }
 
 void RemoteMediaPlayerManager::OnMediaMetadataChanged(int player_id,
@@ -295,15 +252,19 @@
                                                       int width,
                                                       int height,
                                                       bool success) {
-  if (player_id == RemotePlayerId() && replaced_local_player_) {
+  if (IsPlayingRemotely(player_id)) {
+    MediaPlayerAndroid* local_player = GetLocalPlayer(player_id);
     Send(new MediaPlayerMsg_MediaMetadataChanged(
-        RoutingID(), player_id, duration,
-        replaced_local_player_->GetVideoWidth(),
-        replaced_local_player_->GetVideoHeight(), success));
+        RoutingID(), player_id, duration, local_player->GetVideoWidth(),
+        local_player->GetVideoHeight(), success));
   } else {
     BrowserMediaPlayerManager::OnMediaMetadataChanged(player_id, duration,
                                                       width, height, success);
   }
 }
 
+bool RemoteMediaPlayerManager::IsPlayingRemotely(int player_id) {
+  return players_playing_remotely_.count(player_id) != 0;
+}
+
 } // namespace remote_media
diff --git a/chrome/browser/media/android/remote/remote_media_player_manager.h b/chrome/browser/media/android/remote/remote_media_player_manager.h
index 1cbe8fd..6c93f95 100644
--- a/chrome/browser/media/android/remote/remote_media_player_manager.h
+++ b/chrome/browser/media/android/remote/remote_media_player_manager.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_MEDIA_ANDROID_REMOTE_REMOTE_MEDIA_PLAYER_MANAGER_H_
 #define CHROME_BROWSER_MEDIA_ANDROID_REMOTE_REMOTE_MEDIA_PLAYER_MANAGER_H_
 
+#include <set>
 #include <vector>
 
 #include "base/memory/scoped_ptr.h"
@@ -28,9 +29,6 @@
   void OnPlaying(int player_id);
   void OnPaused(int player_id);
 
-  // Callback to trigger when a remote device has been selected.
-  void OnRemoteDeviceSelected(int player_id);
-
   // Callback to trigger when a remote device has been unselected.
   void OnRemoteDeviceUnselected(int player_id);
 
@@ -46,6 +44,10 @@
                               int height,
                               bool success) override;
 
+  // Swap which player is currently in use (local or remote).
+  void SwitchToRemotePlayer(int player_id, const std::string& casting_message);
+  void SwitchToLocalPlayer(int player_id);
+
  protected:
   void OnSetPoster(int player_id, const GURL& url) override;
 
@@ -54,18 +56,9 @@
   RemoteMediaPlayerBridge* CreateRemoteMediaPlayer(
       media::MediaPlayerAndroid* local_player);
 
-  // Replaces the given local player with the remote one. Does nothing if the
-  // player is remote already.
-  void ReplaceLocalPlayerWithRemote(media::MediaPlayerAndroid* player);
-
   // Replaces the remote player with the local player this class is holding.
   // Does nothing if there is no remote player.
-  void ReplaceRemotePlayerWithLocal();
-
-  // Checks if the URL managed by the player should be played remotely.
-  // Returns true if the manager should do nothing, false if it needs to
-  // proceed.
-  bool MaybeStartPlayingRemotely(int player_id);
+  void ReplaceRemotePlayerWithLocal(int player_id);
 
   // content::BrowserMediaPlayerManager overrides.
   void OnStart(int player_id) override;
@@ -73,6 +66,8 @@
       const MediaPlayerHostMsg_Initialize_Params& media_player_params) override;
   void OnDestroyPlayer(int player_id) override;
   void OnReleaseResources(int player_id) override;
+  void OnSuspend(int player_id) override;
+  void OnResume(int player_id) override;
   void OnRequestRemotePlayback(int player_id) override;
   void OnRequestRemotePlaybackControl(int player_id) override;
 
@@ -91,18 +86,28 @@
   // -1 in case something goes wrong.
   int GetTabId();
 
-  // Get the player id of current remote player, if any, or -1 if none.
-  int RemotePlayerId();
+  // Get the player that is not currently selected
+  ScopedVector<media::MediaPlayerAndroid>::iterator GetAlternativePlayer(
+      int player_id);
 
   // Get the remote player for a given player id, whether or not it is currently
   // playing remotely.
   RemoteMediaPlayerBridge* GetRemotePlayer(int player_id);
 
-  // The local player that we have replaced with a remote player. This is NULL
-  // if we do not have a remote player currently running.
-  scoped_ptr<media::MediaPlayerAndroid> replaced_local_player_;
+  // Get the local player for a given player id, whether or not it is currently
+  // playing locally.
+  media::MediaPlayerAndroid* GetLocalPlayer(int player_id);
 
-  ScopedVector<RemoteMediaPlayerBridge> remote_players_;
+  void SwapCurrentPlayer(int player_id);
+
+  // Contains the alternative players that are not currently in use, i.e. the
+  // remote players for videos that are playing locally, and the local players
+  // for videos that are playing remotely.
+  ScopedVector<media::MediaPlayerAndroid> alternative_players_;
+
+  bool IsPlayingRemotely(int player_id);
+
+  std::set<int> players_playing_remotely_;
 
   base::WeakPtrFactory<RemoteMediaPlayerManager> weak_ptr_factory_;
 
diff --git a/chrome/browser/memory_details.cc b/chrome/browser/memory_details.cc
index c6a7e7c..c6e057b 100644
--- a/chrome/browser/memory_details.cc
+++ b/chrome/browser/memory_details.cc
@@ -24,6 +24,7 @@
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_iterator.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/bindings_policy.h"
diff --git a/chrome/browser/nacl_host/nacl_browser_delegate_impl.h b/chrome/browser/nacl_host/nacl_browser_delegate_impl.h
index 456d533..04da2ce 100644
--- a/chrome/browser/nacl_host/nacl_browser_delegate_impl.h
+++ b/chrome/browser/nacl_host/nacl_browser_delegate_impl.h
@@ -12,6 +12,7 @@
 #include "components/nacl/browser/nacl_browser_delegate.h"
 
 #if defined(ENABLE_EXTENSIONS)
+#include "base/memory/ref_counted.h"
 #include "extensions/common/url_pattern.h"
 
 namespace extensions {
diff --git a/chrome/browser/password_manager/password_generation_interactive_uitest.cc b/chrome/browser/password_manager/password_generation_interactive_uitest.cc
index 6e0ca7c..113cd4f68 100644
--- a/chrome/browser/password_manager/password_generation_interactive_uitest.cc
+++ b/chrome/browser/password_manager/password_generation_interactive_uitest.cc
@@ -18,6 +18,7 @@
 #include "components/password_manager/core/browser/password_generation_manager.h"
 #include "components/password_manager/core/browser/test_password_store.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
@@ -116,7 +117,7 @@
     content::NativeWebKeyboardEvent event;
     event.windowsKeyCode = key;
     event.type = blink::WebKeyboardEvent::RawKeyDown;
-    RenderViewHost()->ForwardKeyboardEvent(event);
+    RenderViewHost()->GetWidget()->ForwardKeyboardEvent(event);
   }
 
   bool GenerationPopupShowing() {
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index 8dc2548..cb230b6 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -129,6 +129,7 @@
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_constants.h"
 #include "content/public/common/content_paths.h"
@@ -814,9 +815,9 @@
     click_event.clickCount = 1;
     click_event.x = x;
     click_event.y = y;
-    contents->GetRenderViewHost()->ForwardMouseEvent(click_event);
+    contents->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(click_event);
     click_event.type = blink::WebInputEvent::MouseUp;
-    contents->GetRenderViewHost()->ForwardMouseEvent(click_event);
+    contents->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(click_event);
   }
 
   void SetPolicy(PolicyMap* policies, const char* key, base::Value* value) {
diff --git a/chrome/browser/prerender/prerender_browsertest.cc b/chrome/browser/prerender/prerender_browsertest.cc
index 96293556..82324f08 100644
--- a/chrome/browser/prerender/prerender_browsertest.cc
+++ b/chrome/browser/prerender/prerender_browsertest.cc
@@ -518,9 +518,8 @@
     // Used to make sure the RenderViewHost is hidden and, if used,
     // subsequently shown.
     notification_registrar().Add(
-        this,
-        content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
-        content::Source<RenderWidgetHost>(new_render_view_host));
+        this, content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
+        content::Source<RenderWidgetHost>(new_render_view_host->GetWidget()));
 
     new_render_view_host_ = new_render_view_host;
 
@@ -532,7 +531,7 @@
                const content::NotificationDetails& details) override {
     if (type ==
         content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED) {
-      EXPECT_EQ(new_render_view_host_,
+      EXPECT_EQ(new_render_view_host_->GetWidget(),
                 content::Source<RenderWidgetHost>(source).ptr());
       bool is_visible = *content::Details<bool>(details).ptr();
 
diff --git a/chrome/browser/prerender/prerender_contents.cc b/chrome/browser/prerender/prerender_contents.cc
index 67e7d101..ce5ef2d6 100644
--- a/chrome/browser/prerender/prerender_contents.cc
+++ b/chrome/browser/prerender/prerender_contents.cc
@@ -33,6 +33,7 @@
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/resource_request_details.h"
 #include "content/public/browser/session_storage_namespace.h"
 #include "content/public/browser/web_contents.h"
@@ -418,7 +419,7 @@
         // thread of the browser process.  When the RenderView receives its
         // size, is also sets itself to be visible, which would then break the
         // visibility API.
-        new_render_view_host->WasResized();
+        new_render_view_host->GetWidget()->WasResized();
         prerender_contents_->WasHidden();
       }
       break;
diff --git a/chrome/browser/referrer_policy_browsertest.cc b/chrome/browser/referrer_policy_browsertest.cc
index cb359ed..8d769258 100644
--- a/chrome/browser/referrer_policy_browsertest.cc
+++ b/chrome/browser/referrer_policy_browsertest.cc
@@ -23,6 +23,7 @@
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
@@ -179,9 +180,9 @@
       mouse_event.x = 15;
       mouse_event.y = 15;
       mouse_event.clickCount = 1;
-      tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+      tab->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(mouse_event);
       mouse_event.type = blink::WebInputEvent::MouseUp;
-      tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+      tab->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(mouse_event);
     }
 
     if (disposition == CURRENT_TAB) {
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc b/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
index 6ab5ea6a..71aab95 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
@@ -33,6 +33,7 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
@@ -153,9 +154,9 @@
   mouse_event.globalX = 15 + offset.x();
   mouse_event.globalY = 15 + offset.y();
   mouse_event.clickCount = 1;
-  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+  tab->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(mouse_event);
   mouse_event.type = blink::WebInputEvent::MouseUp;
-  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+  tab->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(mouse_event);
 
   // The menu_observer will select "Open in new tab", wait for the new tab to
   // be added.
@@ -290,9 +291,9 @@
   mouse_event.y = 15;
   content::WebContents* tab =
       browser()->tab_strip_model()->GetActiveWebContents();
-  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+  tab->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(mouse_event);
   mouse_event.type = blink::WebInputEvent::MouseUp;
-  tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+  tab->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(mouse_event);
 
   // Wait for context menu to be visible.
   menu_observer.WaitForMenuOpenAndClose();
diff --git a/chrome/browser/renderer_context_menu/spelling_menu_observer.cc b/chrome/browser/renderer_context_menu/spelling_menu_observer.cc
index 3edcc691..fb12cb3 100644
--- a/chrome/browser/renderer_context_menu/spelling_menu_observer.cc
+++ b/chrome/browser/renderer_context_menu/spelling_menu_observer.cc
@@ -26,6 +26,7 @@
 #include "chrome/common/spellcheck_result.h"
 #include "chrome/grit/generated_resources.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/context_menu_params.h"
@@ -299,14 +300,13 @@
     // service immediately.
     if (!integrate_spelling_service_.GetValue()) {
       content::RenderViewHost* rvh = proxy_->GetRenderViewHost();
-      gfx::Rect rect = rvh->GetView()->GetViewBounds();
+      gfx::Rect rect = rvh->GetWidget()->GetView()->GetViewBounds();
       scoped_ptr<SpellingBubbleModel> model(
           new SpellingBubbleModel(profile, proxy_->GetWebContents(), false));
       chrome::ShowConfirmBubble(
           proxy_->GetWebContents()->GetTopLevelNativeWindow(),
-          rvh->GetView()->GetNativeView(),
-          gfx::Point(rect.CenterPoint().x(), rect.y()),
-          model.Pass());
+          rvh->GetWidget()->GetView()->GetNativeView(),
+          gfx::Point(rect.CenterPoint().x(), rect.y()), model.Pass());
     } else {
       if (profile) {
         profile->GetPrefs()->SetBoolean(prefs::kSpellCheckUseSpellingService,
@@ -325,14 +325,13 @@
     // the bubble and just make sure to enable autocorrect as well.
     if (!integrate_spelling_service_.GetValue()) {
       content::RenderViewHost* rvh = proxy_->GetRenderViewHost();
-      gfx::Rect rect = rvh->GetView()->GetViewBounds();
+      gfx::Rect rect = rvh->GetWidget()->GetView()->GetViewBounds();
       scoped_ptr<SpellingBubbleModel> model(
           new SpellingBubbleModel(profile, proxy_->GetWebContents(), true));
       chrome::ShowConfirmBubble(
           proxy_->GetWebContents()->GetTopLevelNativeWindow(),
-          rvh->GetView()->GetNativeView(),
-          gfx::Point(rect.CenterPoint().x(), rect.y()),
-          model.Pass());
+          rvh->GetWidget()->GetView()->GetNativeView(),
+          gfx::Point(rect.CenterPoint().x(), rect.y()), model.Pass());
     } else {
       if (profile) {
         bool current_value = autocorrect_spelling_.GetValue();
diff --git a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper_browsertest.mm b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper_browsertest.mm
index bd07ab6..6025a7d 100644
--- a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper_browsertest.mm
+++ b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper_browsertest.mm
@@ -14,6 +14,7 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
@@ -180,8 +181,11 @@
     NSUInteger modifierFlags = 0;
     [(NSEvent*)[[event stub]
         andReturnValue:OCMOCK_VALUE(modifierFlags)] modifierFlags];
-    NSView* view =
-        GetWebContents()->GetRenderViewHost()->GetView()->GetNativeView();
+    NSView* view = GetWebContents()
+                       ->GetRenderViewHost()
+                       ->GetWidget()
+                       ->GetView()
+                       ->GetNativeView();
     NSWindow* window = [view window];
     [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(window)] window];
 
@@ -306,8 +310,11 @@
     while ([event_queue_ count] > 0) {
       QueuedEvent* queued_event = [event_queue_ objectAtIndex:0];
       NSEvent* event = queued_event.event;
-      NSView* view =
-          GetWebContents()->GetRenderViewHost()->GetView()->GetNativeView();
+      NSView* view = GetWebContents()
+                         ->GetRenderViewHost()
+                         ->GetWidget()
+                         ->GetView()
+                         ->GetNativeView();
       BOOL run_loop = queued_event.runMessageLoop;
       switch (queued_event.deployment) {
         case DEPLOYMENT_GESTURE_BEGIN:
diff --git a/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc b/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc
index 664f88d..68a9ba6 100644
--- a/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc
+++ b/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc
@@ -21,6 +21,7 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_iterator.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
diff --git a/chrome/browser/resources/options/clear_browser_data_overlay.js b/chrome/browser/resources/options/clear_browser_data_overlay.js
index e598111..e6b5612 100644
--- a/chrome/browser/resources/options/clear_browser_data_overlay.js
+++ b/chrome/browser/resources/options/clear_browser_data_overlay.js
@@ -90,6 +90,11 @@
       this.updateStateOfControls_();
     },
 
+    /** @override */
+    didShowPage: function() {
+      chrome.send('openedClearBrowserData');
+    },
+
     /**
      * Create a footer that explains that some content is not cleared by the
      * clear browsing data dialog and warns that the deletion may be synced.
diff --git a/chrome/browser/ssl/bad_clock_blocking_page.cc b/chrome/browser/ssl/bad_clock_blocking_page.cc
index 2d2f51d..0fb1363 100644
--- a/chrome/browser/ssl/bad_clock_blocking_page.cc
+++ b/chrome/browser/ssl/bad_clock_blocking_page.cc
@@ -9,6 +9,7 @@
 #include "base/build_time.h"
 #include "base/callback_helpers.h"
 #include "base/command_line.h"
+#include "base/files/file_util.h"
 #include "base/i18n/rtl.h"
 #include "base/i18n/time_formatting.h"
 #include "base/process/launch.h"
diff --git a/chrome/browser/status_icons/desktop_notification_balloon.cc b/chrome/browser/status_icons/desktop_notification_balloon.cc
index 91eb63e..fd43576 100644
--- a/chrome/browser/status_icons/desktop_notification_balloon.cc
+++ b/chrome/browser/status_icons/desktop_notification_balloon.cc
@@ -33,7 +33,6 @@
 
 // Prefix added to the notification ids.
 const char kNotificationPrefix[] = "desktop_notification_balloon.";
-const char kNotifierId[] = "status-icons.desktop-notification-balloon";
 
 // Timeout for automatically dismissing the notification balloon.
 const size_t kTimeoutSeconds = 6;
@@ -74,7 +73,8 @@
 void DesktopNotificationBalloon::DisplayBalloon(
     const gfx::ImageSkia& icon,
     const base::string16& title,
-    const base::string16& contents) {
+    const base::string16& contents,
+    const message_center::NotifierId& notifier_id) {
   // Allowing IO access is required here to cover the corner case where
   // there is no last used profile and the default one is loaded.
   // IO access won't be required for normal uses.
@@ -86,16 +86,9 @@
 
   NotificationDelegate* delegate =
       new DummyNotificationDelegate(base::IntToString(id_count_++), profile_);
-  // TODO(johnme): In theory the desktop notification balloon class can be used
-  // by lots of other features, which would not fall under a single system
-  // component id. So callers should pass in the notifier_id to be used here,
-  // see https://crbug.com/542232
   Notification notification(message_center::NOTIFICATION_TYPE_SIMPLE, title,
-      contents, gfx::Image(icon),
-      message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT,
-                                 kNotifierId),
-      base::string16(), GURL(), std::string(),
-      message_center::RichNotificationData(), delegate);
+      contents, gfx::Image(icon), notifier_id, base::string16(), GURL(),
+      std::string(), message_center::RichNotificationData(), delegate);
 
   g_browser_process->notification_ui_manager()->Add(notification, profile);
 
diff --git a/chrome/browser/status_icons/desktop_notification_balloon.h b/chrome/browser/status_icons/desktop_notification_balloon.h
index c027132e..e73508e6 100644
--- a/chrome/browser/status_icons/desktop_notification_balloon.h
+++ b/chrome/browser/status_icons/desktop_notification_balloon.h
@@ -16,6 +16,10 @@
 class ImageSkia;
 }
 
+namespace message_center {
+struct NotifierId;
+}
+
 // Provides the notification balloon functionality by using desktop
 // notifications to platforms that don't have a specific native API.
 class DesktopNotificationBalloon {
@@ -25,7 +29,8 @@
 
   void DisplayBalloon(const gfx::ImageSkia& icon,
                       const base::string16& title,
-                      const base::string16& contents);
+                      const base::string16& contents,
+                      const message_center::NotifierId& notifier_id);
 
  private:
   std::string notification_id_;
diff --git a/chrome/browser/status_icons/status_icon.h b/chrome/browser/status_icons/status_icon.h
index 4f35abc..e49c998 100644
--- a/chrome/browser/status_icons/status_icon.h
+++ b/chrome/browser/status_icons/status_icon.h
@@ -15,6 +15,10 @@
 class ImageSkia;
 }
 
+namespace message_center {
+struct NotifierId;
+}
+
 class StatusIconObserver;
 
 class StatusIcon {
@@ -33,9 +37,11 @@
 
   // Displays a notification balloon with the specified contents.
   // Depending on the platform it might not appear by the icon tray.
-  virtual void DisplayBalloon(const gfx::ImageSkia& icon,
-                              const base::string16& title,
-                              const base::string16& contents) = 0;
+  virtual void DisplayBalloon(
+      const gfx::ImageSkia& icon,
+      const base::string16& title,
+      const base::string16& contents,
+      const message_center::NotifierId& notifier_id) = 0;
 
   // Set the context menu for this icon. The icon takes ownership of the passed
   // context menu. Passing NULL results in no menu at all.
diff --git a/chrome/browser/status_icons/status_icon_unittest.cc b/chrome/browser/status_icons/status_icon_unittest.cc
index a108b799..87a7e0c 100644
--- a/chrome/browser/status_icons/status_icon_unittest.cc
+++ b/chrome/browser/status_icons/status_icon_unittest.cc
@@ -8,6 +8,7 @@
 #include "chrome/browser/status_icons/status_icon_observer.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/message_center/notifier_settings.h"
 
 class MockStatusIconObserver : public StatusIconObserver {
  public:
@@ -23,7 +24,8 @@
   void UpdatePlatformContextMenu(StatusIconMenuModel* menu) override {}
   void DisplayBalloon(const gfx::ImageSkia& icon,
                       const base::string16& title,
-                      const base::string16& contents) override {}
+                      const base::string16& contents,
+                      const message_center::NotifierId& notifier_id) override {}
 };
 
 TEST(StatusIconTest, ObserverAdd) {
diff --git a/chrome/browser/status_icons/status_tray_unittest.cc b/chrome/browser/status_icons/status_tray_unittest.cc
index 12adee3..90f1329 100644
--- a/chrome/browser/status_icons/status_tray_unittest.cc
+++ b/chrome/browser/status_icons/status_tray_unittest.cc
@@ -11,13 +11,15 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/image/image_skia.h"
+#include "ui/message_center/notifier_settings.h"
 
 class MockStatusIcon : public StatusIcon {
   void SetImage(const gfx::ImageSkia& image) override {}
   void SetToolTip(const base::string16& tool_tip) override {}
   void DisplayBalloon(const gfx::ImageSkia& icon,
                       const base::string16& title,
-                      const base::string16& contents) override {}
+                      const base::string16& contents,
+                      const message_center::NotifierId& notifier_id) override {}
   void UpdatePlatformContextMenu(StatusIconMenuModel* menu) override {}
 };
 
diff --git a/chrome/browser/tab_contents/navigation_metrics_recorder.cc b/chrome/browser/tab_contents/navigation_metrics_recorder.cc
index adcbf94..63ca2248 100644
--- a/chrome/browser/tab_contents/navigation_metrics_recorder.cc
+++ b/chrome/browser/tab_contents/navigation_metrics_recorder.cc
@@ -12,6 +12,7 @@
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/common/frame_navigate_params.h"
 #include "url/gurl.h"
@@ -53,7 +54,7 @@
   content::RenderViewHost* rvh = web_contents()->GetRenderViewHost();
 
   if (rvh && base::win::GetVersion() >= base::win::VERSION_WIN8) {
-    content::RenderWidgetHostView* rwhv = rvh->GetView();
+    content::RenderWidgetHostView* rwhv = rvh->GetWidget()->GetView();
     if (rwhv) {
       gfx::NativeView native_view = rwhv->GetNativeView();
       if (native_view) {
diff --git a/chrome/browser/task_manager/guest_information.cc b/chrome/browser/task_manager/guest_information.cc
index 192b3e34..a71fe8b0 100644
--- a/chrome/browser/task_manager/guest_information.cc
+++ b/chrome/browser/task_manager/guest_information.cc
@@ -18,6 +18,7 @@
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_iterator.h"
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/task_manager/task_manager.cc b/chrome/browser/task_manager/task_manager.cc
index ab4d5a9..59f179e 100644
--- a/chrome/browser/task_manager/task_manager.cc
+++ b/chrome/browser/task_manager/task_manager.cc
@@ -10,6 +10,7 @@
 #include "base/location.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
+#include "base/process/process_metrics.h"
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string16.h"
diff --git a/chrome/browser/thumbnails/thumbnail_tab_helper.cc b/chrome/browser/thumbnails/thumbnail_tab_helper.cc
index f8322e7..33deccef 100644
--- a/chrome/browser/thumbnails/thumbnail_tab_helper.cc
+++ b/chrome/browser/thumbnails/thumbnail_tab_helper.cc
@@ -15,6 +15,7 @@
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "ui/gfx/color_utils.h"
 #include "ui/gfx/geometry/size_conversions.h"
@@ -80,7 +81,8 @@
                            scoped_refptr<ThumbnailingContext> context,
                            scoped_refptr<ThumbnailingAlgorithm> algorithm) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  RenderWidgetHost* render_widget_host = web_contents->GetRenderViewHost();
+  RenderWidgetHost* render_widget_host =
+      web_contents->GetRenderViewHost()->GetWidget();
   content::RenderWidgetHostView* view = render_widget_host->GetView();
   if (!view)
     return;
@@ -151,14 +153,12 @@
 void ThumbnailTabHelper::RenderViewDeleted(
     content::RenderViewHost* render_view_host) {
   bool registered = registrar_.IsRegistered(
-      this,
-      content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
-      content::Source<RenderWidgetHost>(render_view_host));
+      this, content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
+      content::Source<RenderWidgetHost>(render_view_host->GetWidget()));
   if (registered) {
     registrar_.Remove(
-        this,
-        content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
-        content::Source<RenderWidgetHost>(render_view_host));
+        this, content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
+        content::Source<RenderWidgetHost>(render_view_host->GetWidget()));
   }
 }
 
@@ -210,14 +210,11 @@
   // RenderView, not RenderViewHost, and there is no good way to get
   // notifications of RenderViewHosts. So just be tolerant of re-registrations.
   bool registered = registrar_.IsRegistered(
-      this,
-      content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
-      content::Source<RenderWidgetHost>(renderer));
+      this, content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
+      content::Source<RenderWidgetHost>(renderer->GetWidget()));
   if (!registered) {
-    registrar_.Add(
-        this,
-        content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
-        content::Source<RenderWidgetHost>(renderer));
+    registrar_.Add(this, content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
+                   content::Source<RenderWidgetHost>(renderer->GetWidget()));
   }
 }
 
diff --git a/chrome/browser/ui/app_list/app_list_view_delegate.cc b/chrome/browser/ui/app_list/app_list_view_delegate.cc
index 7424f83..b332b52a 100644
--- a/chrome/browser/ui/app_list/app_list_view_delegate.cc
+++ b/chrome/browser/ui/app_list/app_list_view_delegate.cc
@@ -47,6 +47,7 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/page_navigator.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/speech_recognition_session_preamble.h"
 #include "content/public/browser/user_metrics.h"
@@ -715,7 +716,7 @@
 
     // Make the webview transparent.
     content::RenderWidgetHostView* render_view_host_view =
-        web_contents->GetRenderViewHost()->GetView();
+        web_contents->GetRenderViewHost()->GetWidget()->GetView();
     // The RenderWidgetHostView may be null if the renderer has crashed.
     if (render_view_host_view)
       render_view_host_view->SetBackgroundColor(SK_ColorTRANSPARENT);
diff --git a/chrome/browser/ui/app_list/start_page_service.cc b/chrome/browser/ui/app_list/start_page_service.cc
index 599f11a..6fc32fb5 100644
--- a/chrome/browser/ui/app_list/start_page_service.cc
+++ b/chrome/browser/ui/app_list/start_page_service.cc
@@ -42,6 +42,7 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/speech_recognition_session_preamble.h"
 #include "content/public/browser/web_contents.h"
@@ -634,8 +635,8 @@
       ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
       std::string());
 
-  contents_->GetRenderViewHost()->GetView()->SetBackgroundColor(
-        SK_ColorTRANSPARENT);
+  contents_->GetRenderViewHost()->GetWidget()->GetView()->SetBackgroundColor(
+      SK_ColorTRANSPARENT);
 }
 
 void StartPageService::FetchDoodleJson() {
diff --git a/chrome/browser/ui/ash/launcher/launcher_favicon_loader.cc b/chrome/browser/ui/ash/launcher/launcher_favicon_loader.cc
index fccb2db..1fd9bfa 100644
--- a/chrome/browser/ui/ash/launcher/launcher_favicon_loader.cc
+++ b/chrome/browser/ui/ash/launcher/launcher_favicon_loader.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/ash/launcher/launcher_favicon_loader.h"
 
 #include "ash/shelf/shelf_constants.h"
+#include "base/bind.h"
 #include "base/logging.h"
 #include "base/memory/weak_ptr.h"
 #include "content/public/browser/render_view_host.h"
diff --git a/chrome/browser/ui/autofill/popup_controller_common.cc b/chrome/browser/ui/autofill/popup_controller_common.cc
index 87881dd..0bf73db 100644
--- a/chrome/browser/ui/autofill/popup_controller_common.cc
+++ b/chrome/browser/ui/autofill/popup_controller_common.cc
@@ -38,7 +38,7 @@
 void PopupControllerCommon::RegisterKeyPressCallback() {
   if (web_contents_ && !key_press_event_target_) {
     key_press_event_target_ = web_contents_->GetRenderViewHost();
-    key_press_event_target_->AddKeyPressEventCallback(
+    key_press_event_target_->GetWidget()->AddKeyPressEventCallback(
         key_press_event_callback_);
   }
 }
@@ -46,8 +46,9 @@
 void PopupControllerCommon::RemoveKeyPressCallback() {
   if (web_contents_ && (!web_contents_->IsBeingDestroyed()) &&
       key_press_event_target_ == web_contents_->GetRenderViewHost()) {
-    web_contents_->GetRenderViewHost()->RemoveKeyPressEventCallback(
-        key_press_event_callback_);
+    web_contents_->GetRenderViewHost()
+        ->GetWidget()
+        ->RemoveKeyPressEventCallback(key_press_event_callback_);
   }
   key_press_event_target_ = NULL;
 }
diff --git a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
index ced26fc..636a3cb 100644
--- a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
+++ b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
@@ -40,6 +40,7 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/url_constants.h"
@@ -627,7 +628,7 @@
                        int modifiers) {
   NativeWebKeyboardEvent event;
   BuildSimpleWebKeyEvent(type, key_code, native_key_code, modifiers, &event);
-  web_contents->GetRenderViewHost()->ForwardKeyboardEvent(event);
+  web_contents->GetRenderViewHost()->GetWidget()->ForwardKeyboardEvent(event);
 }
 
 // Tests that Ctrl+Enter/Cmd+Enter keys on a link open the backgournd tab.
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 6fa115c..85839ecd 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -178,6 +178,7 @@
 #include "content/public/browser/plugin_service.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/security_style_explanation.h"
 #include "content/public/browser/security_style_explanations.h"
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index 3b5e6831..cedf67a 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -77,6 +77,7 @@
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/resource_context.h"
 #include "content/public/browser/security_style_explanation.h"
@@ -271,7 +272,7 @@
   // Cache the size when RenderViewHost is first created.
   void RenderViewCreated(content::RenderViewHost* render_view_host) override {
     render_view_sizes_[render_view_host].rwhv_create_size =
-        render_view_host->GetView()->GetViewBounds().size();
+        render_view_host->GetWidget()->GetView()->GetViewBounds().size();
   }
 
   // Enlarge WebContentsView by |wcv_resize_insets_| while the navigation entry
diff --git a/chrome/browser/ui/browser_focus_uitest.cc b/chrome/browser/ui/browser_focus_uitest.cc
index 1667d7a5..b265aea6 100644
--- a/chrome/browser/ui/browser_focus_uitest.cc
+++ b/chrome/browser/ui/browser_focus_uitest.cc
@@ -33,6 +33,7 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
@@ -181,7 +182,9 @@
 
   void DontProceed() { interstitial_page_->DontProceed(); }
 
-  bool HasFocus() { return render_view_host()->GetView()->HasFocus(); }
+  bool HasFocus() {
+    return render_view_host()->GetWidget()->GetView()->HasFocus();
+  }
 
  private:
   std::string html_contents_;
@@ -465,7 +468,7 @@
   ui_test_utils::NavigateToURL(browser(), url);
   WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
   EXPECT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
-  EXPECT_TRUE(tab->GetRenderViewHost()->GetView()->HasFocus());
+  EXPECT_TRUE(tab->GetRenderViewHost()->GetWidget()->GetView()->HasFocus());
 
   // Create and show a test interstitial page; it should gain focus.
   TestInterstitialPage* interstitial_page = new TestInterstitialPage(tab);
@@ -476,7 +479,7 @@
   interstitial_page->DontProceed();
   content::RunAllPendingInMessageLoop();
   EXPECT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
-  EXPECT_TRUE(tab->GetRenderViewHost()->GetView()->HasFocus());
+  EXPECT_TRUE(tab->GetRenderViewHost()->GetWidget()->GetView()->HasFocus());
 }
 
 // Test that find-in-page UI can request focus, even when it is already open.
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm
index 67fb9bf..2e24e1b 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller.mm
@@ -89,6 +89,7 @@
 #include "components/translate/core/browser/translate_ui_delegate.h"
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #import "ui/base/cocoa/cocoa_base_utils.h"
@@ -1067,7 +1068,8 @@
     // Send new resize rect to foreground tab.
     if (WebContents* contents = [self webContents]) {
       if (content::RenderViewHost* rvh = contents->GetRenderViewHost()) {
-        rvh->ResizeRectChanged(windowShim_->GetRootWindowResizerRect());
+        rvh->GetWidget()->ResizeRectChanged(
+            windowShim_->GetRootWindowResizerRect());
       }
     }
   }
diff --git a/chrome/browser/ui/cocoa/extensions/extension_view_mac.mm b/chrome/browser/ui/cocoa/extensions/extension_view_mac.mm
index 32c362b6..0f98745 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_view_mac.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_view_mac.mm
@@ -10,6 +10,7 @@
 #include "chrome/browser/extensions/extension_view_host.h"
 #import "chrome/browser/ui/cocoa/chrome_event_processing_window.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/browser/extension_host.h"
@@ -34,8 +35,8 @@
 }
 
 void ExtensionViewMac::WindowFrameChanged() {
-  if (render_view_host()->GetView())
-    render_view_host()->GetView()->WindowFrameChanged();
+  if (render_view_host()->GetWidget()->GetView())
+    render_view_host()->GetWidget()->GetView()->WindowFrameChanged();
 }
 
 void ExtensionViewMac::CreateWidgetHostViewIn(gfx::NativeView superview) {
diff --git a/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.mm b/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.mm
index 41ceb2e..d7e398c 100644
--- a/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.mm
+++ b/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.mm
@@ -20,6 +20,7 @@
 #include "chrome/browser/ui/find_bar/find_tab_helper.h"
 #include "chrome/grit/generated_resources.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents.h"
 #include "grit/theme_resources.h"
 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSAnimation+Duration.h"
@@ -275,7 +276,8 @@
     // the list above.
     content::RenderViewHost* render_view_host =
         web_contents->GetRenderViewHost();
-    render_view_host->ForwardKeyboardEvent(NativeWebKeyboardEvent(event));
+    render_view_host->GetWidget()->ForwardKeyboardEvent(
+        NativeWebKeyboardEvent(event));
     return YES;
   }
 
diff --git a/chrome/browser/ui/cocoa/hung_renderer_controller.mm b/chrome/browser/ui/cocoa/hung_renderer_controller.mm
index 41aa6192..7b5d14e8 100644
--- a/chrome/browser/ui/cocoa/hung_renderer_controller.mm
+++ b/chrome/browser/ui/cocoa/hung_renderer_controller.mm
@@ -17,6 +17,7 @@
 #include "chrome/grit/generated_resources.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/result_codes.h"
 #include "grit/theme_resources.h"
@@ -165,7 +166,9 @@
 
 - (IBAction)wait:(id)sender {
   if (hungContents_ && hungContents_->GetRenderViewHost())
-    hungContents_->GetRenderViewHost()->RestartHangMonitorTimeout();
+    hungContents_->GetRenderViewHost()
+        ->GetWidget()
+        ->RestartHangMonitorTimeout();
   // Cannot call performClose:, because the close button is disabled.
   [self close];
 }
diff --git a/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac.mm b/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac.mm
index 69e29654..34ccbf69 100644
--- a/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac.mm
+++ b/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac.mm
@@ -12,6 +12,7 @@
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/grit/generated_resources.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #import "ui/base/cocoa/menu_controller.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -168,8 +169,8 @@
       blink::WebTextDirection dir = blink::WebTextDirectionLeftToRight;
       if (command_id == IDC_WRITING_DIRECTION_RTL)
         dir = blink::WebTextDirectionRightToLeft;
-      view_host->UpdateTextDirection(dir);
-      view_host->NotifyTextDirection();
+      view_host->GetWidget()->UpdateTextDirection(dir);
+      view_host->GetWidget()->NotifyTextDirection();
       RenderViewContextMenu::RecordUsedItem(command_id);
       break;
     }
@@ -210,7 +211,8 @@
       return true;
 
     case IDC_CONTENT_CONTEXT_SPEECH_STOP_SPEAKING: {
-      content::RenderWidgetHostView* view = GetRenderViewHost()->GetView();
+      content::RenderWidgetHostView* view =
+          GetRenderViewHost()->GetWidget()->GetView();
       return view && view->IsSpeaking();
     }
 
@@ -271,7 +273,8 @@
     menu_model_.InsertSeparatorAt(index++, ui::NORMAL_SEPARATOR);
   }
 
-  content::RenderWidgetHostView* view = GetRenderViewHost()->GetView();
+  content::RenderWidgetHostView* view =
+      GetRenderViewHost()->GetWidget()->GetView();
   if (view && view->SupportsSpeech()) {
     menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
     speech_submenu_model_.AddItemWithStringId(
@@ -323,19 +326,22 @@
 }
 
 void RenderViewContextMenuMac::LookUpInDictionary() {
-  content::RenderWidgetHostView* view = GetRenderViewHost()->GetView();
+  content::RenderWidgetHostView* view =
+      GetRenderViewHost()->GetWidget()->GetView();
   if (view)
     view->ShowDefinitionForSelection();
 }
 
 void RenderViewContextMenuMac::StartSpeaking() {
-  content::RenderWidgetHostView* view = GetRenderViewHost()->GetView();
+  content::RenderWidgetHostView* view =
+      GetRenderViewHost()->GetWidget()->GetView();
   if (view)
     view->SpeakSelection();
 }
 
 void RenderViewContextMenuMac::StopSpeaking() {
-  content::RenderWidgetHostView* view = GetRenderViewHost()->GetView();
+  content::RenderWidgetHostView* view =
+      GetRenderViewHost()->GetWidget()->GetView();
   if (view)
     view->StopSpeaking();
 }
diff --git a/chrome/browser/ui/cocoa/status_icons/status_icon_mac.h b/chrome/browser/ui/cocoa/status_icons/status_icon_mac.h
index 8c7cbfd..e9ff3bc 100644
--- a/chrome/browser/ui/cocoa/status_icons/status_icon_mac.h
+++ b/chrome/browser/ui/cocoa/status_icons/status_icon_mac.h
@@ -28,7 +28,8 @@
   void SetToolTip(const base::string16& tool_tip) override;
   void DisplayBalloon(const gfx::ImageSkia& icon,
                       const base::string16& title,
-                      const base::string16& contents) override;
+                      const base::string16& contents,
+                      const message_center::NotifierId& notifier_id) override;
 
   bool HasStatusIconMenu();
 
diff --git a/chrome/browser/ui/cocoa/status_icons/status_icon_mac.mm b/chrome/browser/ui/cocoa/status_icons/status_icon_mac.mm
index dbecd232..a8ac589 100644
--- a/chrome/browser/ui/cocoa/status_icons/status_icon_mac.mm
+++ b/chrome/browser/ui/cocoa/status_icons/status_icon_mac.mm
@@ -12,6 +12,7 @@
 #include "third_party/skia/include/core/SkBitmap.h"
 #import "ui/base/cocoa/menu_controller.h"
 #include "ui/gfx/image/image_skia.h"
+#include "ui/message_center/notifier_settings.h"
 
 @interface StatusItemController : NSObject {
   StatusIconMac* statusIcon_; // weak
@@ -83,10 +84,12 @@
   }
 }
 
-void StatusIconMac::DisplayBalloon(const gfx::ImageSkia& icon,
-                                   const base::string16& title,
-                                   const base::string16& contents) {
-  notification_.DisplayBalloon(icon, title, contents);
+void StatusIconMac::DisplayBalloon(
+    const gfx::ImageSkia& icon,
+    const base::string16& title,
+    const base::string16& contents,
+    const message_center::NotifierId& notifier_id) {
+  notification_.DisplayBalloon(icon, title, contents, notifier_id);
 }
 
 bool StatusIconMac::HasStatusIconMenu() {
diff --git a/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.mm b/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.mm
index d3ba297..9945572 100644
--- a/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.mm
+++ b/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.mm
@@ -14,6 +14,7 @@
 #import "chrome/browser/ui/cocoa/themed_window.h"
 #include "chrome/browser/ui/view_ids.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -259,17 +260,18 @@
   // a Blur() message to the renderer, but only if the RWHV currently has focus.
   content::RenderViewHost* rvh = [self webContents]->GetRenderViewHost();
   if (rvh) {
-    if (rvh->GetView() && rvh->GetView()->HasFocus()) {
-      rvh->Blur();
+    if (rvh->GetWidget()->GetView() &&
+        rvh->GetWidget()->GetView()->HasFocus()) {
+      rvh->GetWidget()->Blur();
       return;
     }
     WebContents* devtools = DevToolsWindow::GetInTabWebContents(
         [self webContents], NULL);
     if (devtools) {
       content::RenderViewHost* devtoolsView = devtools->GetRenderViewHost();
-      if (devtoolsView && devtoolsView->GetView() &&
-          devtoolsView->GetView()->HasFocus()) {
-        devtoolsView->Blur();
+      if (devtoolsView && devtoolsView->GetWidget()->GetView() &&
+          devtoolsView->GetWidget()->GetView()->HasFocus()) {
+        devtoolsView->GetWidget()->Blur();
       }
     }
   }
diff --git a/chrome/browser/ui/cocoa/validation_message_bubble_cocoa.mm b/chrome/browser/ui/cocoa/validation_message_bubble_cocoa.mm
index b176a26..8c15b985 100644
--- a/chrome/browser/ui/cocoa/validation_message_bubble_cocoa.mm
+++ b/chrome/browser/ui/cocoa/validation_message_bubble_cocoa.mm
@@ -12,6 +12,7 @@
 #import "chrome/browser/ui/cocoa/validation_message_bubble_controller.h"
 #include "chrome/browser/ui/validation_message_bubble.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "grit/theme_resources.h"
@@ -155,7 +156,8 @@
     const gfx::Rect& anchor_in_root_view,
     const base::string16& main_text,
     const base::string16& sub_text) {
-  content::RenderWidgetHost* widget_host = web_contents->GetRenderViewHost();
+  content::RenderWidgetHost* widget_host =
+      web_contents->GetRenderViewHost()->GetWidget();
   controller_.reset([[[ValidationMessageBubbleController alloc]
             init:[widget_host->GetView()->GetNativeView() window]
       anchoredAt:GetAnchorPoint(widget_host, anchor_in_root_view)
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
index 4e59901..868bb34 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
@@ -15,6 +15,7 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/url_constants.h"
@@ -48,8 +49,13 @@
     // Verify that IsMouseLocked is consistent between the
     // Fullscreen Controller and the Render View Host View.
     EXPECT_TRUE(browser()->IsMouseLocked() ==
-                browser()->tab_strip_model()->GetActiveWebContents()->
-                    GetRenderViewHost()->GetView()->IsMouseLocked());
+                browser()
+                    ->tab_strip_model()
+                    ->GetActiveWebContents()
+                    ->GetRenderViewHost()
+                    ->GetWidget()
+                    ->GetView()
+                    ->IsMouseLocked());
     return browser()->IsMouseLocked();
   }
 
diff --git a/chrome/browser/ui/exclusive_access/mouse_lock_controller.cc b/chrome/browser/ui/exclusive_access/mouse_lock_controller.cc
index 84c3660..1a46837 100644
--- a/chrome/browser/ui/exclusive_access/mouse_lock_controller.cc
+++ b/chrome/browser/ui/exclusive_access/mouse_lock_controller.cc
@@ -14,6 +14,7 @@
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 
@@ -221,7 +222,7 @@
   if (!mouse_lock_view) {
     RenderViewHost* const rvh = exclusive_access_tab()->GetRenderViewHost();
     if (rvh)
-      mouse_lock_view = rvh->GetView();
+      mouse_lock_view = rvh->GetWidget()->GetView();
   }
 
   if (mouse_lock_view)
diff --git a/chrome/browser/ui/find_bar/find_tab_helper.cc b/chrome/browser/ui/find_bar/find_tab_helper.cc
index b9c2a36..4c15d3f5 100644
--- a/chrome/browser/ui/find_bar/find_tab_helper.cc
+++ b/chrome/browser/ui/find_bar/find_tab_helper.cc
@@ -6,6 +6,7 @@
 
 #include <vector>
 
+#include "base/strings/string_util.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/find_bar/find_bar_state.h"
diff --git a/chrome/browser/ui/toolbar/component_toolbar_actions_browsertest.cc b/chrome/browser/ui/toolbar/component_toolbar_actions_browsertest.cc
index 51d882b..b5550c84 100644
--- a/chrome/browser/ui/toolbar/component_toolbar_actions_browsertest.cc
+++ b/chrome/browser/ui/toolbar/component_toolbar_actions_browsertest.cc
@@ -49,12 +49,13 @@
 
   // Even though the method says "ExtensionId", this actually refers to any id
   // for the action.
-  EXPECT_EQ(ComponentToolbarActionsFactory::kActionIdForTesting,
+  EXPECT_EQ(MockComponentToolbarActionsFactory::kActionIdForTesting,
             browser_actions_bar.GetExtensionId(0));
 
   // There should only have been one created component action.
-  const std::vector<std::string>& action_ids = mock_factory()->action_ids();
-  ASSERT_EQ(1u, action_ids.size());
+  EXPECT_EQ(1u, ComponentToolbarActionsFactory::GetInstance()
+                    ->GetComponentIds(browser()->profile())
+                    .size());
 
   const std::vector<ToolbarActionViewController*>& actions =
       browser_actions_bar.GetToolbarActionsBar()->GetActions();
diff --git a/chrome/browser/ui/toolbar/component_toolbar_actions_factory.cc b/chrome/browser/ui/toolbar/component_toolbar_actions_factory.cc
index 45720cc..cdde653 100644
--- a/chrome/browser/ui/toolbar/component_toolbar_actions_factory.cc
+++ b/chrome/browser/ui/toolbar/component_toolbar_actions_factory.cc
@@ -25,8 +25,6 @@
 // static
 const char ComponentToolbarActionsFactory::kMediaRouterActionId[] =
     "media_router_action";
-const char ComponentToolbarActionsFactory::kActionIdForTesting[] =
-    "mock_action";
 
 ComponentToolbarActionsFactory::ComponentToolbarActionsFactory() {}
 ComponentToolbarActionsFactory::~ComponentToolbarActionsFactory() {}
@@ -36,40 +34,29 @@
   return testing_factory_ ? testing_factory_ : &lazy_factory.Get();
 }
 
-// static
-std::vector<std::string> ComponentToolbarActionsFactory::GetComponentIds() {
-  std::vector<std::string> component_ids;
+std::set<std::string> ComponentToolbarActionsFactory::GetComponentIds(
+    Profile* profile) {
+  std::set<std::string> component_ids;
 
   // This is currently behind the extension-action-redesign flag, as it is
   // designed for the new toolbar.
   if (!extensions::FeatureSwitch::extension_action_redesign()->IsEnabled())
     return component_ids;
 
-  if (testing_factory_) {
-    component_ids.push_back(
-        ComponentToolbarActionsFactory::kActionIdForTesting);
-  } else if (switches::MediaRouterEnabled()) {
-    component_ids.push_back(
-        ComponentToolbarActionsFactory::kMediaRouterActionId);
-  }
+  if (switches::MediaRouterEnabled() && !profile->IsOffTheRecord())
+    component_ids.insert(kMediaRouterActionId);
 
   return component_ids;
 }
 
-// static
-bool ComponentToolbarActionsFactory::EnabledIncognito(
-    const std::string& action_id) {
-  return action_id != kMediaRouterActionId;
-}
-
-ScopedVector<ToolbarActionViewController>
-ComponentToolbarActionsFactory::GetComponentToolbarActions(Browser* browser) {
-  ScopedVector<ToolbarActionViewController> component_actions;
-
+scoped_ptr<ToolbarActionViewController>
+ComponentToolbarActionsFactory::GetComponentToolbarActionForId(
+    const std::string& id,
+    Browser* browser) {
   // This is currently behind the extension-action-redesign flag, as it is
   // designed for the new toolbar.
-  if (!extensions::FeatureSwitch::extension_action_redesign()->IsEnabled())
-    return component_actions.Pass();
+  DCHECK(extensions::FeatureSwitch::extension_action_redesign()->IsEnabled());
+  DCHECK(GetComponentIds(browser->profile()).count(id));
 
   // Add component toolbar actions here.
   // This current design means that the ComponentToolbarActionsFactory is aware
@@ -77,11 +64,12 @@
   // (since each will have an action in the toolbar or overflow menu), this
   // should be okay. If this changes, we should rethink this design to have,
   // e.g., RegisterChromeAction().
+  if (id == kMediaRouterActionId)
+    return scoped_ptr<ToolbarActionViewController>(
+        new MediaRouterAction(browser));
 
-  if (switches::MediaRouterEnabled() && !browser->profile()->IsOffTheRecord())
-    component_actions.push_back(new MediaRouterAction(browser));
-
-  return component_actions.Pass();
+  NOTREACHED();
+  return scoped_ptr<ToolbarActionViewController>();
 }
 
 // static
diff --git a/chrome/browser/ui/toolbar/component_toolbar_actions_factory.h b/chrome/browser/ui/toolbar/component_toolbar_actions_factory.h
index 0171388..ffdc126a4 100644
--- a/chrome/browser/ui/toolbar/component_toolbar_actions_factory.h
+++ b/chrome/browser/ui/toolbar/component_toolbar_actions_factory.h
@@ -5,8 +5,11 @@
 #ifndef CHROME_BROWSER_UI_TOOLBAR_COMPONENT_TOOLBAR_ACTIONS_FACTORY_H_
 #define CHROME_BROWSER_UI_TOOLBAR_COMPONENT_TOOLBAR_ACTIONS_FACTORY_H_
 
+#include <set>
+#include <string>
+
 #include "base/macros.h"
-#include "base/memory/scoped_vector.h"
+#include "base/memory/scoped_ptr.h"
 
 class Browser;
 class Profile;
@@ -19,7 +22,6 @@
  public:
   // Component action IDs.
   static const char kMediaRouterActionId[];
-  static const char kActionIdForTesting[];  // Only used for testing.
 
   ComponentToolbarActionsFactory();
   virtual ~ComponentToolbarActionsFactory();
@@ -27,16 +29,12 @@
   static ComponentToolbarActionsFactory* GetInstance();
 
   // Returns a vector of IDs of the component actions.
-  static std::vector<std::string> GetComponentIds();
-
-  // Returns true if the component action with |action_id| should be added
-  // in incognito mode.
-  static bool EnabledIncognito(const std::string& action_id);
+  virtual std::set<std::string> GetComponentIds(Profile* profile);
 
   // Returns a collection of controllers for component actions. Declared
   // virtual for testing.
-  virtual ScopedVector<ToolbarActionViewController>
-      GetComponentToolbarActions(Browser* browser);
+  virtual scoped_ptr<ToolbarActionViewController>
+  GetComponentToolbarActionForId(const std::string& id, Browser* browser);
 
   // Sets the factory to use for testing purposes.
   // Ownership remains with the caller.
diff --git a/chrome/browser/ui/toolbar/mock_component_toolbar_actions_factory.cc b/chrome/browser/ui/toolbar/mock_component_toolbar_actions_factory.cc
index 9694d90..05ecd87 100644
--- a/chrome/browser/ui/toolbar/mock_component_toolbar_actions_factory.cc
+++ b/chrome/browser/ui/toolbar/mock_component_toolbar_actions_factory.cc
@@ -8,25 +8,32 @@
 #include "chrome/browser/ui/toolbar/test_toolbar_action_view_controller.h"
 #include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
 
+// static
+const char MockComponentToolbarActionsFactory::kActionIdForTesting[] =
+    "mock_action";
+
 MockComponentToolbarActionsFactory::MockComponentToolbarActionsFactory(
     Browser* browser) {
   ComponentToolbarActionsFactory::SetTestingFactory(this);
-
-  ScopedVector<ToolbarActionViewController> actions =
-      GetComponentToolbarActions(browser);
-  for (const ToolbarActionViewController* action : actions)
-    action_ids_.push_back(action->GetId());
 }
 
 MockComponentToolbarActionsFactory::~MockComponentToolbarActionsFactory() {
   ComponentToolbarActionsFactory::SetTestingFactory(nullptr);
 }
 
-ScopedVector<ToolbarActionViewController>
-MockComponentToolbarActionsFactory::GetComponentToolbarActions(
+std::set<std::string> MockComponentToolbarActionsFactory::GetComponentIds(
+    Profile* profile) {
+  std::set<std::string> ids;
+  ids.insert(kActionIdForTesting);
+  return ids;
+}
+
+scoped_ptr<ToolbarActionViewController>
+MockComponentToolbarActionsFactory::GetComponentToolbarActionForId(
+    const std::string& id,
     Browser* browser) {
-  ScopedVector<ToolbarActionViewController> component_actions;
-  component_actions.push_back(new TestToolbarActionViewController(
-      ComponentToolbarActionsFactory::kActionIdForTesting));
-  return component_actions.Pass();
+  DCHECK_EQ(kActionIdForTesting, id);
+  return scoped_ptr<ToolbarActionViewController>(
+      new TestToolbarActionViewController(
+          MockComponentToolbarActionsFactory::kActionIdForTesting));
 }
diff --git a/chrome/browser/ui/toolbar/mock_component_toolbar_actions_factory.h b/chrome/browser/ui/toolbar/mock_component_toolbar_actions_factory.h
index abf9d1b..6770013 100644
--- a/chrome/browser/ui/toolbar/mock_component_toolbar_actions_factory.h
+++ b/chrome/browser/ui/toolbar/mock_component_toolbar_actions_factory.h
@@ -14,18 +14,18 @@
 class MockComponentToolbarActionsFactory
     : public ComponentToolbarActionsFactory {
  public:
+  static const char kActionIdForTesting[];
+
   explicit MockComponentToolbarActionsFactory(Browser* browser);
   ~MockComponentToolbarActionsFactory() override;
 
   // ComponentToolbarActionsFactory:
-  ScopedVector<ToolbarActionViewController> GetComponentToolbarActions(
+  std::set<std::string> GetComponentIds(Profile* profile) override;
+  scoped_ptr<ToolbarActionViewController> GetComponentToolbarActionForId(
+      const std::string& id,
       Browser* browser) override;
 
-  const std::vector<std::string>& action_ids() const { return action_ids_; }
-
  private:
-  std::vector<std::string> action_ids_;
-
   DISALLOW_COPY_AND_ASSIGN(MockComponentToolbarActionsFactory);
 };
 
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar.cc b/chrome/browser/ui/toolbar/toolbar_actions_bar.cc
index e0c7e08..a3086f6 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_bar.cc
+++ b/chrome/browser/ui/toolbar/toolbar_actions_bar.cc
@@ -282,8 +282,11 @@
 
 bool ToolbarActionsBar::NeedsOverflow() const {
   DCHECK(!in_overflow_mode());
+  // We need an overflow view if either the end index is less than the number of
+  // icons, or if a drag is in progress with the redesign turned on (since the
+  // user can drag an icon into the wrench menu).
   return GetEndIndexInBounds() != toolbar_actions_.size() ||
-         is_drag_in_progress_;
+         (is_drag_in_progress_ && !platform_settings_.chevron_enabled);
 }
 
 gfx::Rect ToolbarActionsBar::GetFrameForIndex(
@@ -699,15 +702,39 @@
 void ToolbarActionsBar::OnToolbarHighlightModeChanged(bool is_highlighting) {
   if (!model_->actions_initialized())
     return;
-  // It's a bit of a pain that we delete and recreate everything here, but given
-  // everything else going on (the lack of highlight, [n] more extensions
-  // appearing, etc), it's not worth the extra complexity to create and insert
-  // only the new actions.
-  DeleteActions();
-  CreateActions();
-  // Resize the delegate. We suppress the chevron so that we don't risk showing
-  // it only for the duration of the animation.
-  ResizeDelegate(gfx::Tween::LINEAR, true);
+
+  {
+    base::AutoReset<bool> layout_resetter(&suppress_layout_, true);
+    base::AutoReset<bool> animation_resetter(&suppress_animation_, true);
+    std::set<std::string> seen;
+    for (const ToolbarActionsModel::ToolbarItem item :
+         model_->toolbar_items()) {
+      auto current_pos =
+          std::find_if(toolbar_actions_.begin(), toolbar_actions_.end(),
+                       [&item](const ToolbarActionViewController* action) {
+                         return action->GetId() == item.id;
+                       });
+      if (current_pos == toolbar_actions_.end()) {
+        toolbar_actions_.push_back(
+            model_->CreateActionForItem(browser_, this, item).release());
+        delegate_->AddViewForAction(toolbar_actions_.back(),
+                                    toolbar_actions_.size() - 1);
+      }
+      seen.insert(item.id);
+    }
+
+    for (ToolbarActions::iterator iter = toolbar_actions_.begin();
+         iter != toolbar_actions_.end();) {
+      if (seen.count((*iter)->GetId()) == 0) {
+        delegate_->RemoveViewForAction(*iter);
+        iter = toolbar_actions_.erase(iter);
+      } else {
+        ++iter;
+      }
+    }
+  }
+
+  ReorderActions();
 }
 
 void ToolbarActionsBar::OnToolbarModelInitialized() {
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc b/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc
index 0f1907d..7e793378 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc
+++ b/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc
@@ -333,6 +333,74 @@
   }
 }
 
+TEST_F(ToolbarActionsBarUnitTest, TestHighlightMode) {
+  std::vector<std::string> ids;
+  for (int i = 0; i < 3; ++i) {
+    ids.push_back(CreateAndAddExtension(
+                      base::StringPrintf("extension %d", i),
+                      extensions::extension_action_test_util::BROWSER_ACTION)
+                      ->id());
+  }
+  EXPECT_EQ(3u, toolbar_actions_bar()->GetIconCount());
+  const char kExtension0[] = "extension 0";
+  const char kExtension1[] = "extension 1";
+  const char kExtension2[] = "extension 2";
+
+  {
+    // The order should start as 0, 1, 2.
+    const char* expected_names[] = {kExtension0, kExtension1, kExtension2};
+    EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 3u));
+  }
+
+  std::vector<std::string> ids_to_highlight;
+  ids_to_highlight.push_back(ids[0]);
+  ids_to_highlight.push_back(ids[2]);
+  toolbar_model()->HighlightActions(ids_to_highlight,
+                                    ToolbarActionsModel::HIGHLIGHT_WARNING);
+
+  {
+    // The order should now be 0, 2, since 1 is not being highlighted.
+    const char* expected_names[] = {kExtension0, kExtension2};
+    EXPECT_TRUE(VerifyToolbarOrder(expected_names, 2u, 2u));
+  }
+
+  toolbar_model()->StopHighlighting();
+
+  {
+    // The order should go back to normal.
+    const char* expected_names[] = {kExtension0, kExtension1, kExtension2};
+    EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 3u));
+  }
+
+  ids_to_highlight.push_back(ids[1]);
+  toolbar_model()->HighlightActions(ids_to_highlight,
+                                    ToolbarActionsModel::HIGHLIGHT_WARNING);
+  {
+    // All actions should be highlighted (in the order of the vector passed in,
+    // so with '1' at the end).
+    const char* expected_names[] = {kExtension0, kExtension2, kExtension1};
+    EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 3u));
+  }
+
+  ids_to_highlight.clear();
+  ids_to_highlight.push_back(ids[1]);
+  toolbar_model()->HighlightActions(ids_to_highlight,
+                                    ToolbarActionsModel::HIGHLIGHT_WARNING);
+
+  {
+    // Only extension 1 should be visible.
+    const char* expected_names[] = {kExtension1};
+    EXPECT_TRUE(VerifyToolbarOrder(expected_names, 1u, 1u));
+  }
+
+  toolbar_model()->StopHighlighting();
+  {
+    // And, again, back to normal.
+    const char* expected_names[] = {kExtension0, kExtension1, kExtension2};
+    EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 3u));
+  }
+}
+
 TEST_F(ToolbarActionsBarRedesignUnitTest, IconSurfacingBubbleAppearance) {
   // Without showing anything new, we shouldn't show the bubble, and should
   // auto-acknowledge it.
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model.cc b/chrome/browser/ui/toolbar/toolbar_actions_model.cc
index e45fcb39..23f6dba 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_model.cc
+++ b/chrome/browser/ui/toolbar/toolbar_actions_model.cc
@@ -46,6 +46,8 @@
       prefs_(profile_->GetPrefs()),
       extension_action_api_(extensions::ExtensionActionAPI::Get(profile_)),
       extension_registry_(extensions::ExtensionRegistry::Get(profile_)),
+      extension_action_manager_(
+          extensions::ExtensionActionManager::Get(profile_)),
       actions_initialized_(false),
       use_redesign_(extensions::FeatureSwitch::extension_action_redesign()
                         ->IsEnabled()),
@@ -158,60 +160,45 @@
   DCHECK(bar);
   ScopedVector<ToolbarActionViewController> action_list;
 
-  // Get the component action list.
-  ScopedVector<ToolbarActionViewController> component_actions =
-      ComponentToolbarActionsFactory::GetInstance()->GetComponentToolbarActions(
-          browser);
-
-  extensions::ExtensionActionManager* action_manager =
-      extensions::ExtensionActionManager::Get(profile_);
-
   // toolbar_items() might not equate to toolbar_items_ in the case where a
-  // subset are highlighted.
-  for (const ToolbarItem& item : toolbar_items()) {
-    switch (item.type) {
-      case EXTENSION_ACTION: {
-        // Get the extension.
-        const extensions::Extension* extension = GetExtensionById(item.id);
-        DCHECK(extension);
-
-        // Create and add an ExtensionActionViewController for the extension.
-        action_list.push_back(new ExtensionActionViewController(
-            extension, browser, action_manager->GetExtensionAction(*extension),
-            bar));
-        break;
-      }
-      case COMPONENT_ACTION: {
-        DCHECK(use_redesign_);
-        // Find the index of the component action with the id.
-        auto iter = std::find_if(
-            component_actions.begin(), component_actions.end(),
-            [&item](const ToolbarActionViewController* action) {
-          return action->GetId() == item.id;
-        });
-        // We should always find a corresponding action.
-        DCHECK(iter != component_actions.end());
-        action_list.push_back(*iter);
-
-        // We have moved ownership of the action from |component_actions| to
-        // |action_list|.
-        component_actions.weak_erase(iter);
-        break;
-      }
-      case UNKNOWN_ACTION:
-        NOTREACHED();  // Should never have an UNKNOWN_ACTION in toolbar_items.
-        break;
-    }
-  }
-
-  // We've moved ownership of the subset of the component actions that we
-  // kept track of via toolbar_items() from |component_actions| to
-  // |action_list|. The rest will be deleted when |component_actions| goes out
-  // of scope.
+  // subset is highlighted.
+  for (const ToolbarItem& item : toolbar_items())
+    action_list.push_back(CreateActionForItem(browser, bar, item).release());
 
   return action_list.Pass();
 }
 
+scoped_ptr<ToolbarActionViewController>
+ToolbarActionsModel::CreateActionForItem(Browser* browser,
+                                         ToolbarActionsBar* bar,
+                                         const ToolbarItem& item) {
+  scoped_ptr<ToolbarActionViewController> result;
+  switch (item.type) {
+    case EXTENSION_ACTION: {
+      // Get the extension.
+      const extensions::Extension* extension = GetExtensionById(item.id);
+      DCHECK(extension);
+
+      // Create and add an ExtensionActionViewController for the extension.
+      result.reset(new ExtensionActionViewController(
+          extension, browser,
+          extension_action_manager_->GetExtensionAction(*extension), bar));
+      break;
+    }
+    case COMPONENT_ACTION: {
+      DCHECK(use_redesign_);
+      result = ComponentToolbarActionsFactory::GetInstance()
+                   ->GetComponentToolbarActionForId(item.id, browser)
+                   .Pass();
+      break;
+    }
+    case UNKNOWN_ACTION:
+      NOTREACHED();  // Should never have an UNKNOWN_ACTION in toolbar_items.
+      break;
+  }
+  return result.Pass();
+}
+
 void ToolbarActionsModel::OnExtensionActionVisibilityChanged(
     const std::string& extension_id,
     bool is_now_visible) {
@@ -311,15 +298,13 @@
       !extensions::util::IsIncognitoEnabled(extension->id(), profile_))
     return false;
 
-  extensions::ExtensionActionManager* action_manager =
-      extensions::ExtensionActionManager::Get(profile_);
   if (use_redesign_) {
     // In this case, we don't care about the browser action visibility, because
     // we want to show each extension regardless.
-    return action_manager->GetExtensionAction(*extension) != NULL;
+    return extension_action_manager_->GetExtensionAction(*extension) != nullptr;
   }
 
-  return action_manager->GetBrowserAction(*extension) &&
+  return extension_action_manager_->GetBrowserAction(*extension) &&
          extension_action_api_->GetBrowserActionVisibility(extension->id());
 }
 
@@ -487,8 +472,8 @@
   }
 
   // Next, add the component action ids.
-  std::vector<std::string> component_ids =
-      ComponentToolbarActionsFactory::GetComponentIds();
+  std::set<std::string> component_ids =
+      ComponentToolbarActionsFactory::GetInstance()->GetComponentIds(profile_);
   for (const std::string& id : component_ids)
     all_actions.push_back(ToolbarItem(id, COMPONENT_ACTION));
 
@@ -591,6 +576,8 @@
   // overflowed. Order is the same as in regular mode.
   visible_icon_count_ = 0;
 
+  std::set<std::string> component_ids =
+      ComponentToolbarActionsFactory::GetInstance()->GetComponentIds(profile_);
   for (std::vector<ToolbarItem>::const_iterator iter =
            original_model->toolbar_items_.begin();
        iter != original_model->toolbar_items_.end(); ++iter) {
@@ -602,7 +589,9 @@
         should_add = ShouldAddExtension(GetExtensionById(iter->id));
         break;
       case COMPONENT_ACTION:
-        should_add = ComponentToolbarActionsFactory::EnabledIncognito(iter->id);
+        // The component action factory only returns actions that should be
+        // added.
+        should_add = component_ids.count(iter->id) != 0;
         break;
       case UNKNOWN_ACTION:
         // We should never have an uninitialized action in the model.
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model.h b/chrome/browser/ui/toolbar/toolbar_actions_model.h
index 3facd79..e94938d 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_model.h
+++ b/chrome/browser/ui/toolbar/toolbar_actions_model.h
@@ -24,6 +24,7 @@
 class ToolbarActionViewController;
 
 namespace extensions {
+class ExtensionActionManager;
 class ExtensionRegistry;
 class ExtensionSet;
 }
@@ -150,6 +151,10 @@
   ScopedVector<ToolbarActionViewController> CreateActions(
       Browser* browser,
       ToolbarActionsBar* bar);
+  scoped_ptr<ToolbarActionViewController> CreateActionForItem(
+      Browser* browser,
+      ToolbarActionsBar* bar,
+      const ToolbarItem& item);
 
   const std::vector<ToolbarItem>& toolbar_items() const {
     return is_highlighting() ? highlighted_items_ : toolbar_items_;
@@ -243,6 +248,9 @@
   // The ExtensionRegistry object, cached for convenience.
   extensions::ExtensionRegistry* extension_registry_;
 
+  // The ExtensionActionManager, cached for convenience.
+  extensions::ExtensionActionManager* extension_action_manager_;
+
   // True if we've handled the initial EXTENSIONS_READY notification.
   bool actions_initialized_;
 
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc b/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc
index 3c46222f..787e5da 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc
@@ -172,7 +172,7 @@
 
   // The mock component action will be referred to as "MCA" below.
   const char* component_action_id() {
-    return ComponentToolbarActionsFactory::kActionIdForTesting;
+    return MockComponentToolbarActionsFactory::kActionIdForTesting;
   }
 
  private:
diff --git a/chrome/browser/ui/views/autofill/autofill_dialog_views_unittest.cc b/chrome/browser/ui/views/autofill/autofill_dialog_views_unittest.cc
index 7371bcd9..3cf3254 100644
--- a/chrome/browser/ui/views/autofill/autofill_dialog_views_unittest.cc
+++ b/chrome/browser/ui/views/autofill/autofill_dialog_views_unittest.cc
@@ -15,6 +15,7 @@
 #include "components/web_modal/test_web_contents_modal_dialog_host.h"
 #include "components/web_modal/test_web_contents_modal_dialog_manager_delegate.h"
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
+#include "content/public/browser/native_web_keyboard_event.h"
 #include "content/public/common/url_constants.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
index d354428c..50c520c8 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
@@ -74,14 +74,12 @@
 #include "ui/base/dragdrop/os_exchange_data.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/page_transition_types.h"
-#include "ui/base/resource/material_design/material_design_controller.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/theme_provider.h"
 #include "ui/base/window_open_disposition.h"
 #include "ui/compositor/paint_recorder.h"
 #include "ui/gfx/animation/slide_animation.h"
 #include "ui/gfx/canvas.h"
-#include "ui/gfx/favicon_size.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/gfx/text_constants.h"
 #include "ui/gfx/text_elider.h"
@@ -147,8 +145,8 @@
 static const int kSeparatorMargin = 1;
 
 // Width of the separator between the recently bookmarked button and the
-// overflow indicator, indexed by MD mode.
-static const int kSeparatorWidth[] = {4, 9, 9};
+// overflow indicator.
+static const int kSeparatorWidth = 4;
 
 // Starting x-coordinate of the separator line within a separator.
 static const int kSeparatorStartX = 2;
@@ -349,7 +347,8 @@
 class OverflowButton : public views::MenuButton {
  public:
   explicit OverflowButton(BookmarkBarView* owner)
-      : MenuButton(NULL, base::string16(), owner, false), owner_(owner) {}
+      : MenuButton(NULL, base::string16(), owner, false),
+        owner_(owner) {}
 
   bool OnMousePressed(const ui::MouseEvent& e) override {
     owner_->StopThrobbing(true);
@@ -476,40 +475,20 @@
   ~ButtonSeparatorView() override {}
 
   void OnPaint(gfx::Canvas* canvas) override {
-    if (ui::MaterialDesignController::IsModeMaterial()) {
-      // 1px wide at all scale factors. If there is an uneven amount of padding
-      // left over, place the extra pixel on the outside, i.e. away from the
-      // "Other bookmarks" folder.
-      const float scale = canvas->SaveAndUnscale();
-      const gfx::RectF scaled_bounds =
-          gfx::ScaleRect(gfx::RectF(bounds()), scale);
-
-      const int kLineThickness = 1;
-      const float fractional_x = (scaled_bounds.width() - kLineThickness) / 2.f;
-      const int x = base::i18n::IsRTL() ? std::floor(fractional_x)
-                                        : std::ceil(fractional_x);
-
-      const int height = gfx::kFaviconSize * scale;
-      const int top_y = (scaled_bounds.height() - height) / 2;
-      canvas->DrawLine(
-          gfx::Point(x, top_y), gfx::Point(x, top_y + height),
-          SkColorSetA(GetThemeProvider()->GetColor(
-                          ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON),
-                      0x4D));
-      canvas->Restore();
-    } else {
-      PaintVerticalDivider(
-          canvas, kSeparatorStartX, height(), 1, kEdgeDividerColor,
-          kMiddleDividerColor,
-          GetThemeProvider()->GetColor(ThemeProperties::COLOR_TOOLBAR));
-    }
+    PaintVerticalDivider(
+        canvas,
+        kSeparatorStartX,
+        height(),
+        1,
+        kEdgeDividerColor,
+        kMiddleDividerColor,
+        GetThemeProvider()->GetColor(ThemeProperties::COLOR_TOOLBAR));
   }
 
   gfx::Size GetPreferredSize() const override {
     // We get the full height of the bookmark bar, so that the height returned
     // here doesn't matter.
-    return gfx::Size(kSeparatorWidth[ui::MaterialDesignController::GetMode()],
-                     1);
+    return gfx::Size(kSeparatorWidth, 1);
   }
 
   void GetAccessibleState(ui::AXViewState* state) override {
diff --git a/chrome/browser/ui/views/color_chooser_win.cc b/chrome/browser/ui/views/color_chooser_win.cc
index 8d44da4c..ef84986 100644
--- a/chrome/browser/ui/views/color_chooser_win.cc
+++ b/chrome/browser/ui/views/color_chooser_win.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/ui/views/color_chooser_dialog.h"
 #include "content/public/browser/color_chooser.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/views/color_chooser/color_chooser_listener.h"
@@ -57,8 +58,11 @@
 ColorChooserWin::ColorChooserWin(content::WebContents* web_contents,
                                  SkColor initial_color)
     : web_contents_(web_contents) {
-  gfx::NativeWindow owning_window = platform_util::GetTopLevel(
-      web_contents->GetRenderViewHost()->GetView()->GetNativeView());
+  gfx::NativeWindow owning_window =
+      platform_util::GetTopLevel(web_contents->GetRenderViewHost()
+                                     ->GetWidget()
+                                     ->GetView()
+                                     ->GetNativeView());
   color_chooser_dialog_ = new ColorChooserDialog(this,
                                                  initial_color,
                                                  owning_window);
diff --git a/chrome/browser/ui/views/extensions/extension_dialog.cc b/chrome/browser/ui/views/extensions/extension_dialog.cc
index fac0c3d..51c8d6ec6 100644
--- a/chrome/browser/ui/views/extensions/extension_dialog.cc
+++ b/chrome/browser/ui/views/extensions/extension_dialog.cc
@@ -14,6 +14,7 @@
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/base/base_window.h"
@@ -132,7 +133,8 @@
   if (focus_manager->GetFocusedView())
     return;
 
-  content::RenderWidgetHostView* view = host()->render_view_host()->GetView();
+  content::RenderWidgetHostView* view =
+      host()->render_view_host()->GetWidget()->GetView();
   if (!view)
     return;
 
diff --git a/chrome/browser/ui/views/extensions/extension_view_views.cc b/chrome/browser/ui/views/extensions/extension_view_views.cc
index 106bd8a..5f064ff 100644
--- a/chrome/browser/ui/views/extensions/extension_view_views.cc
+++ b/chrome/browser/ui/views/extensions/extension_view_views.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/views/extensions/extension_popup.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/browser/extension_host.h"
@@ -47,7 +48,7 @@
     // is not part of the View hierarchy and does not know about the change
     // unless we tell it.
     content::RenderWidgetHostView* host_view =
-        host_->render_view_host()->GetView();
+        host_->render_view_host()->GetWidget()->GetView();
     if (host_view) {
       if (is_visible)
         host_view->Show();
diff --git a/chrome/browser/ui/views/find_bar_host.cc b/chrome/browser/ui/views/find_bar_host.cc
index b7bfc5b..08c4c9c 100644
--- a/chrome/browser/ui/views/find_bar_host.cc
+++ b/chrome/browser/ui/views/find_bar_host.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/ui/views/find_bar_view.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/events/event.h"
 #include "ui/events/keycodes/keyboard_codes.h"
@@ -71,7 +72,7 @@
   // input. Otherwise Up and Down arrow key strokes get eaten. "Nom Nom Nom".
   render_view_host->ClearFocusedElement();
   NativeWebKeyboardEvent event(key_event);
-  render_view_host->ForwardKeyboardEvent(event);
+  render_view_host->GetWidget()->ForwardKeyboardEvent(event);
   return true;
 }
 
diff --git a/chrome/browser/ui/views/hung_renderer_view.cc b/chrome/browser/ui/views/hung_renderer_view.cc
index 775c6d0..c59a58a 100644
--- a/chrome/browser/ui/views/hung_renderer_view.cc
+++ b/chrome/browser/ui/views/hung_renderer_view.cc
@@ -19,6 +19,7 @@
 #include "components/web_modal/web_contents_modal_dialog_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/result_codes.h"
 #include "grit/theme_resources.h"
@@ -361,8 +362,11 @@
     return true;
 
   // Start waiting again for responsiveness.
-  if (hung_pages_table_model_->GetRenderViewHost())
-    hung_pages_table_model_->GetRenderViewHost()->RestartHangMonitorTimeout();
+  if (hung_pages_table_model_->GetRenderViewHost()) {
+    hung_pages_table_model_->GetRenderViewHost()
+        ->GetWidget()
+        ->RestartHangMonitorTimeout();
+  }
   return true;
 }
 
diff --git a/chrome/browser/ui/views/login_prompt_views.cc b/chrome/browser/ui/views/login_prompt_views.cc
index 17e30f5..3e45f79 100644
--- a/chrome/browser/ui/views/login_prompt_views.cc
+++ b/chrome/browser/ui/views/login_prompt_views.cc
@@ -12,6 +12,7 @@
 #include "components/password_manager/core/browser/password_manager.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents.h"
 #include "net/url_request/url_request.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -56,7 +57,8 @@
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
     content::WebContents* web_contents = GetWebContentsForLogin();
     if (web_contents)
-      web_contents->GetRenderViewHost()->SetIgnoreInputEvents(false);
+      web_contents->GetRenderViewHost()->GetWidget()->SetIgnoreInputEvents(
+          false);
 
     // Reference is no longer valid.
     dialog_ = NULL;
diff --git a/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc b/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc
index 17fc6fe..6d4df0e8 100644
--- a/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc
+++ b/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc
@@ -12,6 +12,7 @@
 #include "chrome/grit/generated_resources.h"
 #include "components/renderer_context_menu/views/toolkit_delegate_views.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/aura/client/screen_position_client.h"
@@ -146,10 +147,11 @@
     case IDC_WRITING_DIRECTION_RTL:
     case IDC_WRITING_DIRECTION_LTR: {
       content::RenderViewHost* view_host = GetRenderViewHost();
-      view_host->UpdateTextDirection((command_id == IDC_WRITING_DIRECTION_RTL) ?
-          blink::WebTextDirectionRightToLeft :
-          blink::WebTextDirectionLeftToRight);
-      view_host->NotifyTextDirection();
+      view_host->GetWidget()->UpdateTextDirection(
+          (command_id == IDC_WRITING_DIRECTION_RTL)
+              ? blink::WebTextDirectionRightToLeft
+              : blink::WebTextDirectionLeftToRight);
+      view_host->GetWidget()->NotifyTextDirection();
       RenderViewContextMenu::RecordUsedItem(command_id);
       break;
     }
diff --git a/chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.cc b/chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.cc
index b0b1609..234bafd 100644
--- a/chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.cc
+++ b/chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.h"
 
+#include "ui/message_center/notifier_settings.h"
 #include "ui/views/linux_ui/linux_ui.h"
 
 StatusIconLinuxWrapper::StatusIconLinuxWrapper(
@@ -26,10 +27,12 @@
   status_icon_->SetToolTip(tool_tip);
 }
 
-void StatusIconLinuxWrapper::DisplayBalloon(const gfx::ImageSkia& icon,
-                                            const base::string16& title,
-                                            const base::string16& contents) {
-  notification_.DisplayBalloon(icon, title, contents);
+void StatusIconLinuxWrapper::DisplayBalloon(
+    const gfx::ImageSkia& icon,
+    const base::string16& title,
+    const base::string16& contents,
+    const message_center::NotifierId& notifier_id) {
+  notification_.DisplayBalloon(icon, title, contents, notifier_id);
 }
 
 void StatusIconLinuxWrapper::OnClick() {
diff --git a/chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.h b/chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.h
index 74fcb857..f93d61bf 100644
--- a/chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.h
+++ b/chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.h
@@ -23,7 +23,8 @@
   void SetToolTip(const base::string16& tool_tip) override;
   void DisplayBalloon(const gfx::ImageSkia& icon,
                       const base::string16& title,
-                      const base::string16& contents) override;
+                      const base::string16& contents,
+                      const message_center::NotifierId& notifier_id) override;
 
   // StatusIconLinux::Delegate overrides:
   void OnClick() override;
diff --git a/chrome/browser/ui/views/status_icons/status_icon_win.cc b/chrome/browser/ui/views/status_icons/status_icon_win.cc
index 9715ed8..105bf487 100644
--- a/chrome/browser/ui/views/status_icons/status_icon_win.cc
+++ b/chrome/browser/ui/views/status_icons/status_icon_win.cc
@@ -11,6 +11,7 @@
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/icon_util.h"
+#include "ui/message_center/notifier_settings.h"
 #include "ui/views/controls/menu/menu_runner.h"
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -115,9 +116,11 @@
     LOG(WARNING) << "Unable to set tooltip for status tray icon";
 }
 
-void StatusIconWin::DisplayBalloon(const gfx::ImageSkia& icon,
-                                   const base::string16& title,
-                                   const base::string16& contents) {
+void StatusIconWin::DisplayBalloon(
+    const gfx::ImageSkia& icon,
+    const base::string16& title,
+    const base::string16& contents,
+    const message_center::NotifierId& notifier_id) {
   NOTIFYICONDATA icon_data;
   InitIconData(&icon_data);
   icon_data.uFlags = NIF_INFO;
diff --git a/chrome/browser/ui/views/status_icons/status_icon_win.h b/chrome/browser/ui/views/status_icons/status_icon_win.h
index c2f4ac7..6113186 100644
--- a/chrome/browser/ui/views/status_icons/status_icon_win.h
+++ b/chrome/browser/ui/views/status_icons/status_icon_win.h
@@ -50,7 +50,8 @@
   void SetToolTip(const base::string16& tool_tip) override;
   void DisplayBalloon(const gfx::ImageSkia& icon,
                       const base::string16& title,
-                      const base::string16& contents) override;
+                      const base::string16& contents,
+                      const message_center::NotifierId& notifier_id) override;
   void ForceVisible() override;
 
  protected:
diff --git a/chrome/browser/ui/views/toolbar/browser_actions_container.h b/chrome/browser/ui/views/toolbar/browser_actions_container.h
index ef40806..1557376 100644
--- a/chrome/browser/ui/views/toolbar/browser_actions_container.h
+++ b/chrome/browser/ui/views/toolbar/browser_actions_container.h
@@ -267,6 +267,8 @@
 
   views::BubbleDelegateView* active_bubble() { return active_bubble_; }
 
+  ChevronMenuButton* chevron_for_testing() { return chevron_; }
+
  protected:
   // Overridden from views::View:
   void ViewHierarchyChanged(
diff --git a/chrome/browser/ui/views/toolbar/browser_actions_container_browsertest.cc b/chrome/browser/ui/views/toolbar/browser_actions_container_browsertest.cc
index 345016df..e449930 100644
--- a/chrome/browser/ui/views/toolbar/browser_actions_container_browsertest.cc
+++ b/chrome/browser/ui/views/toolbar/browser_actions_container_browsertest.cc
@@ -167,7 +167,13 @@
       drop_data, location, location, ui::DragDropTypes::DRAG_MOVE);
 
   // Drag and drop.
+  first->toolbar_actions_bar()->OnDragStarted();
   first->OnDragUpdated(target_event);
+
+  // Semi-random placement for a regression test for crbug.com/539744.
+  first->Layout();
+  EXPECT_FALSE(first->chevron_for_testing()->visible());
+
   first->OnPerformDrop(target_event);
 
   // The new order, B A C, should be reflected in *both* containers, even
@@ -184,6 +190,8 @@
   // The first and second container should each have resized.
   EXPECT_EQ(2u, first->VisibleBrowserActions());
   EXPECT_EQ(2u, second->VisibleBrowserActions());
+  EXPECT_TRUE(first->chevron_for_testing()->visible());
+  EXPECT_TRUE(second->chevron_for_testing()->visible());
 }
 
 // Test that the BrowserActionsContainer responds correctly when the underlying
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc b/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc
index 26fa110..56d34ce0 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc
@@ -276,16 +276,10 @@
       browser()->tab_strip_model()->GetActiveWebContents()->GetVisibleURL());
 }
 
-// Disabled on CrOS. See crbug.com/543194.
-#if defined(OS_CHROMEOS)
-#define MAYBE_DoubleClickToolbarActionToClose DISABLED_DoubleClickToolbarActionToClose
-#else
-#define MAYBE_DoubleClickToolbarActionToClose DoubleClickToolbarActionToClose
-#endif
 // Tests that clicking on the toolbar action a second time when the action is
 // already open results in closing the popup, and doesn't re-open it.
 IN_PROC_BROWSER_TEST_F(ToolbarActionViewInteractiveUITest,
-                       MAYBE_DoubleClickToolbarActionToClose) {
+                       DoubleClickToolbarActionToClose) {
   ASSERT_TRUE(LoadExtension(
       test_data_dir_.AppendASCII("ui").AppendASCII("browser_action_popup")));
   base::RunLoop().RunUntilIdle();  // Ensure the extension is fully loaded.
diff --git a/chrome/browser/ui/website_settings/permission_bubble_manager_unittest.cc b/chrome/browser/ui/website_settings/permission_bubble_manager_unittest.cc
index 1f5b3c3e..1b06b828 100644
--- a/chrome/browser/ui/website_settings/permission_bubble_manager_unittest.cc
+++ b/chrome/browser/ui/website_settings/permission_bubble_manager_unittest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/bind.h"
 #include "base/command_line.h"
 #include "base/message_loop/message_loop.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/chrome/browser/ui/webui/ntp/new_tab_ui.cc b/chrome/browser/ui/webui/ntp/new_tab_ui.cc
index 4053d8f..7881ece 100644
--- a/chrome/browser/ui/webui/ntp/new_tab_ui.cc
+++ b/chrome/browser/ui/webui/ntp/new_tab_ui.cc
@@ -151,7 +151,7 @@
   last_paint_ = start_;
 
   content::NotificationSource source =
-      content::Source<content::RenderWidgetHost>(render_view_host);
+      content::Source<content::RenderWidgetHost>(render_view_host->GetWidget());
   if (!registrar_.IsRegistered(this,
           content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
           source)) {
diff --git a/chrome/browser/ui/webui/options/clear_browser_data_handler.cc b/chrome/browser/ui/webui/options/clear_browser_data_handler.cc
index 5648c684..b37b79a5 100644
--- a/chrome/browser/ui/webui/options/clear_browser_data_handler.cc
+++ b/chrome/browser/ui/webui/options/clear_browser_data_handler.cc
@@ -97,10 +97,6 @@
   web_ui()->CallJavascriptFunction("ClearBrowserDataOverlay.setClearing",
                                    base::FundamentalValue(removal_in_progress));
 
-  for (BrowsingDataCounter* counter : counters_) {
-    DCHECK(AreCountersEnabled());
-    counter->Restart();
-  }
   web_ui()->CallJavascriptFunction(
       "ClearBrowserDataOverlay.markInitializationComplete");
 }
@@ -128,6 +124,13 @@
                                    base::StringValue(text));
 }
 
+void ClearBrowserDataHandler::OnPageOpened(const base::ListValue* value) {
+  for (BrowsingDataCounter* counter : counters_) {
+    DCHECK(AreCountersEnabled());
+    counter->Restart();
+  }
+}
+
 void ClearBrowserDataHandler::GetLocalizedValues(
     base::DictionaryValue* localized_strings) {
   DCHECK(localized_strings);
@@ -193,6 +196,9 @@
   web_ui()->RegisterMessageCallback("performClearBrowserData",
       base::Bind(&ClearBrowserDataHandler::HandleClearBrowserData,
                  base::Unretained(this)));
+  web_ui()->RegisterMessageCallback("openedClearBrowserData",
+      base::Bind(&ClearBrowserDataHandler::OnPageOpened,
+                 base::Unretained(this)));
 }
 
 void ClearBrowserDataHandler::HandleClearBrowserData(
diff --git a/chrome/browser/ui/webui/options/clear_browser_data_handler.h b/chrome/browser/ui/webui/options/clear_browser_data_handler.h
index 3c6ec32..47aa918 100644
--- a/chrome/browser/ui/webui/options/clear_browser_data_handler.h
+++ b/chrome/browser/ui/webui/options/clear_browser_data_handler.h
@@ -33,6 +33,10 @@
   void UpdateInfoBannerVisibility();
 
  private:
+  // Javascript callback for when the CBD dialog is opened. The caller does
+  // not provide any parameters, so |value| is unused.
+  void OnPageOpened(const base::ListValue* value);
+
   // Javascript callback to start clearing data.
   void HandleClearBrowserData(const base::ListValue* value);
 
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_distiller.cc b/chrome/browser/ui/webui/print_preview/print_preview_distiller.cc
index 2dfed82e..0a928c9 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_distiller.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_distiller.cc
@@ -20,6 +20,7 @@
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/resource_request_details.h"
 #include "content/public/browser/session_storage_namespace.h"
 #include "content/public/browser/web_contents.h"
@@ -182,7 +183,7 @@
           // size, is also sets itself to be visible, which would then break the
           // visibility API.
           content::Details<RenderViewHost> new_render_view_host(details);
-          new_render_view_host->WasResized();
+          new_render_view_host->GetWidget()->WasResized();
           web_contents()->WasHidden();
         }
         break;
diff --git a/chrome/browser/ui/zoom/zoom_controller_unittest.cc b/chrome/browser/ui/zoom/zoom_controller_unittest.cc
index b6fc9682..105d4f29 100644
--- a/chrome/browser/ui/zoom/zoom_controller_unittest.cc
+++ b/chrome/browser/ui/zoom/zoom_controller_unittest.cc
@@ -15,6 +15,7 @@
 #include "content/public/common/frame_navigate_params.h"
 #include "content/public/test/test_renderer_host.h"
 #include "content/public/test/test_utils.h"
+#include "ipc/ipc_message.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 51ae6aa2..a2ade15 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -3233,6 +3233,7 @@
             '../components/components.gyp:network_hints_common',
             '../components/components.gyp:metrics_gpu',
             '../components/components.gyp:metrics_profiler',
+            '../components/components.gyp:metrics_profiler_content',
             '../components/components.gyp:net_log',
             '../components/components.gyp:packed_ct_ev_whitelist',
             '../components/components.gyp:password_manager_content_browser',
diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi
index 7153cbe..098eae3 100644
--- a/chrome/chrome_browser_extensions.gypi
+++ b/chrome/chrome_browser_extensions.gypi
@@ -265,12 +265,12 @@
       'browser/extensions/api/downloads_internal/downloads_internal_api.h',
       'browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc',
       'browser/extensions/api/easy_unlock_private/easy_unlock_private_api.h',
-      'browser/extensions/api/easy_unlock_private/easy_unlock_private_crypto_delegate.h',
-      'browser/extensions/api/easy_unlock_private/easy_unlock_private_crypto_delegate_chromeos.cc',
       'browser/extensions/api/easy_unlock_private/easy_unlock_private_connection.cc',
       'browser/extensions/api/easy_unlock_private/easy_unlock_private_connection.h',
       'browser/extensions/api/easy_unlock_private/easy_unlock_private_connection_manager.cc',
       'browser/extensions/api/easy_unlock_private/easy_unlock_private_connection_manager.h',
+      'browser/extensions/api/easy_unlock_private/easy_unlock_private_crypto_delegate.h',
+      'browser/extensions/api/easy_unlock_private/easy_unlock_private_crypto_delegate_chromeos.cc',
       'browser/extensions/api/experience_sampling_private/experience_sampling.cc',
       'browser/extensions/api/experience_sampling_private/experience_sampling.h',
       'browser/extensions/api/experience_sampling_private/experience_sampling_private_api.cc',
@@ -815,6 +815,8 @@
       'browser/extensions/plugin_manager.h',
       'browser/extensions/proxy_overridden_bubble_controller.cc',
       'browser/extensions/proxy_overridden_bubble_controller.h',
+      'browser/extensions/scripting_permissions_modifier.cc',
+      'browser/extensions/scripting_permissions_modifier.h',
       'browser/extensions/settings_api_bubble_controller.cc',
       'browser/extensions/settings_api_bubble_controller.h',
       'browser/extensions/settings_api_helpers.cc',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index 52dee95560..0e2a7bf 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -729,6 +729,7 @@
       'browser/extensions/permission_messages_unittest.cc',
       'browser/extensions/permissions_based_management_policy_provider_unittest.cc',
       'browser/extensions/permissions_updater_unittest.cc',
+      'browser/extensions/scripting_permissions_modifier_unittest.cc',
       'browser/extensions/shared_module_service_unittest.cc',
       'browser/extensions/standard_management_policy_provider_unittest.cc',
       'browser/extensions/token_cache/token_cache_service_unittest.cc',
diff --git a/chrome/test/data/android/contextmenu/context_menu_test.html b/chrome/test/data/android/contextmenu/context_menu_test.html
index ccc202c..3c88f46 100644
--- a/chrome/test/data/android/contextmenu/context_menu_test.html
+++ b/chrome/test/data/android/contextmenu/context_menu_test.html
@@ -8,6 +8,8 @@
 
   <a href="test_link.html" id="testLink">Test Link</a><br />
 
+  <a href="test_link2.html" id="testLink2">Test Link 2></a><br />
+
   <a href="test_link.html" id="testImageLink"><img src="test_image.png"/></a><br />
 
   <a href="mailto:someone@example.com" id="testEmail">EmailTest</a><br />
@@ -20,7 +22,6 @@
     }
     </script>
     This <b id="copyLinkTextComplex">is pretty</b>
-      <img src="test_image.png"/>
     extreme <br/> (newline).
   </a><br />
 
diff --git a/chrome/test/data/android/contextmenu/test_link2.html b/chrome/test/data/android/contextmenu/test_link2.html
new file mode 100644
index 0000000..f029389
--- /dev/null
+++ b/chrome/test/data/android/contextmenu/test_link2.html
@@ -0,0 +1,6 @@
+<html>
+<head>
+<title>Testing a Link 2</title>
+</head>
+<body>Testing a Link 2!!</body>
+</html>
diff --git a/chromecast/browser/android/cast_window_android.cc b/chromecast/browser/android/cast_window_android.cc
index 9e8b1d52c..1d8f4fc 100644
--- a/chromecast/browser/android/cast_window_android.cc
+++ b/chromecast/browser/android/cast_window_android.cc
@@ -13,6 +13,7 @@
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/common/renderer_preferences.h"
 #include "jni/CastWindowAndroid_jni.h"
@@ -146,12 +147,12 @@
 
 void CastWindowAndroid::ActivateContents(content::WebContents* contents) {
   DCHECK_EQ(contents, web_contents_.get());
-  contents->GetRenderViewHost()->Focus();
+  contents->GetRenderViewHost()->GetWidget()->Focus();
 }
 
 void CastWindowAndroid::DeactivateContents(content::WebContents* contents) {
   DCHECK_EQ(contents, web_contents_.get());
-  contents->GetRenderViewHost()->Blur();
+  contents->GetRenderViewHost()->GetWidget()->Blur();
 }
 
 void CastWindowAndroid::RenderProcessGone(base::TerminationStatus status) {
diff --git a/chromecast/browser/cast_content_window.cc b/chromecast/browser/cast_content_window.cc
index ab0785c8..aa3d683 100644
--- a/chromecast/browser/cast_content_window.cc
+++ b/chromecast/browser/cast_content_window.cc
@@ -9,6 +9,7 @@
 #include "chromecast/browser/cast_browser_process.h"
 #include "chromecast/media/base/video_plane_controller.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "ipc/ipc_message.h"
@@ -131,7 +132,8 @@
 
 void CastContentWindow::RenderViewCreated(
     content::RenderViewHost* render_view_host) {
-  content::RenderWidgetHostView* view = render_view_host->GetView();
+  content::RenderWidgetHostView* view =
+      render_view_host->GetWidget()->GetView();
   if (view)
     view->SetBackgroundColor(transparent_ ? SK_ColorTRANSPARENT
                                           : SK_ColorBLACK);
diff --git a/chromecast/browser/media/cma_media_pipeline_client.cc b/chromecast/browser/media/cma_media_pipeline_client.cc
index d19aa54..0507d87 100644
--- a/chromecast/browser/media/cma_media_pipeline_client.cc
+++ b/chromecast/browser/media/cma_media_pipeline_client.cc
@@ -16,7 +16,7 @@
 
 scoped_ptr<MediaPipelineBackend>
 CmaMediaPipelineClient::CreateMediaPipelineBackend(
-    const media::MediaPipelineDeviceParams& params) {
+    const MediaPipelineDeviceParams& params) {
   return make_scoped_ptr(CastMediaShlib::CreateMediaPipelineBackend(params));
 }
 
diff --git a/chromecast/browser/media/cma_media_pipeline_client.h b/chromecast/browser/media/cma_media_pipeline_client.h
index f7ecd4b..4caa59d 100644
--- a/chromecast/browser/media/cma_media_pipeline_client.h
+++ b/chromecast/browser/media/cma_media_pipeline_client.h
@@ -14,19 +14,21 @@
 namespace chromecast {
 namespace media {
 
-// Class to provide media backend and watch media pipeline status
+struct MediaPipelineDeviceParams;
+
+// Class to provide media backend and watch media pipeline status.
 class CmaMediaPipelineClient : public base::RefCounted<CmaMediaPipelineClient>,
                                public CastResource {
  public:
   CmaMediaPipelineClient();
 
   virtual scoped_ptr<MediaPipelineBackend> CreateMediaPipelineBackend(
-      const media::MediaPipelineDeviceParams& params);
+      const MediaPipelineDeviceParams& params);
 
   virtual void OnMediaPipelineBackendCreated();
   virtual void OnMediaPipelineBackendDestroyed();
 
-  // cast::CastResource implementations
+  // cast::CastResource implementation:
   void ReleaseResource(CastResource::Resource resource) override;
 
  protected:
@@ -35,7 +37,7 @@
  private:
   friend class base::RefCounted<CmaMediaPipelineClient>;
 
-  // Number of created media pipelines
+  // Number of created media pipelines.
   size_t media_pipeline_count_;
   base::ThreadChecker thread_checker_;
 
diff --git a/chromecast/browser/media/cma_message_filter_host.h b/chromecast/browser/media/cma_message_filter_host.h
index c109f93..6a1d6f2c 100644
--- a/chromecast/browser/media/cma_message_filter_host.h
+++ b/chromecast/browser/media/cma_message_filter_host.h
@@ -46,12 +46,12 @@
  public:
   // Factory method to create a MediaPipelineBackend
   typedef base::Callback<scoped_ptr<MediaPipelineBackend>(
-      const MediaPipelineDeviceParams&)> CreateDeviceComponentsCB;
+      const MediaPipelineDeviceParams&)> CreateBackendCB;
 
   CmaMessageFilterHost(int render_process_id,
                        scoped_refptr<CmaMediaPipelineClient> client);
 
-  // content::BrowserMessageFilter implementation.
+  // content::BrowserMessageFilter implementation:
   void OnChannelClosing() override;
   void OnDestruct() const override;
   bool OnMessageReceived(const IPC::Message& message) override;
@@ -114,8 +114,8 @@
   // Render process ID correponding to this message filter.
   const int process_id_;
 
-  // Factory function for device-specific part of media pipeline creation
-  CreateDeviceComponentsCB create_device_components_cb_;
+  // Factory function for media pipeline backend.
+  CreateBackendCB create_backend_cb_;
   scoped_refptr<CmaMediaPipelineClient> client_;
 
   // List of media pipeline and message loop media pipelines are running on.
diff --git a/chromecast/browser/media/media_pipeline_host.cc b/chromecast/browser/media/media_pipeline_host.cc
index 013a40b..45cc897 100644
--- a/chromecast/browser/media/media_pipeline_host.cc
+++ b/chromecast/browser/media/media_pipeline_host.cc
@@ -53,10 +53,9 @@
   media_track_map_.clear();
 }
 
-void MediaPipelineHost::Initialize(
-    LoadType load_type,
-    const MediaPipelineClient& client,
-    const CreateDeviceComponentsCB& create_device_components_cb) {
+void MediaPipelineHost::Initialize(LoadType load_type,
+                                   const MediaPipelineClient& client,
+                                   const CreateBackendCB& create_backend_cb) {
   DCHECK(thread_checker_.CalledOnValidThread());
   media_pipeline_.reset(new MediaPipelineImpl());
   task_runner_.reset(new TaskRunnerImpl());
@@ -67,8 +66,8 @@
   MediaPipelineDeviceParams default_parameters(sync_type, task_runner_.get());
 
   media_pipeline_->SetClient(client);
-  media_pipeline_->Initialize(
-      load_type, create_device_components_cb.Run(default_parameters).Pass());
+  media_pipeline_->Initialize(load_type,
+                              create_backend_cb.Run(default_parameters).Pass());
 }
 
 void MediaPipelineHost::SetAvPipe(
@@ -99,13 +98,10 @@
   }
   media_track_host->pipe_write_cb = frame_provider_host->GetFifoWriteEventCb();
 
-  scoped_ptr<CodedFrameProvider> frame_provider(frame_provider_host.release());
   if (track_id == kAudioTrackId) {
-    media_pipeline_->GetAudioPipelineImpl()->SetCodedFrameProvider(
-        frame_provider.Pass());
+    audio_frame_provider_ = frame_provider_host.Pass();
   } else {
-    media_pipeline_->GetVideoPipelineImpl()->SetCodedFrameProvider(
-        frame_provider.Pass());
+    video_frame_provider_ = frame_provider_host.Pass();
   }
   av_pipe_set_cb.Run();
 }
@@ -117,21 +113,19 @@
     const ::media::PipelineStatusCB& status_cb) {
   DCHECK(thread_checker_.CalledOnValidThread());
   CHECK(track_id == kAudioTrackId);
-  media_pipeline_->GetAudioPipeline()->SetClient(client);
   media_pipeline_->InitializeAudio(
-      config, scoped_ptr<CodedFrameProvider>(), status_cb);
+      config, client, audio_frame_provider_.Pass(), status_cb);
 }
 
 void MediaPipelineHost::VideoInitialize(
     TrackId track_id,
     const VideoPipelineClient& client,
-    const std::vector<::media::VideoDecoderConfig>& configs,
+    const std::vector< ::media::VideoDecoderConfig>& configs,
     const ::media::PipelineStatusCB& status_cb) {
   DCHECK(thread_checker_.CalledOnValidThread());
   CHECK(track_id == kVideoTrackId);
-  media_pipeline_->GetVideoPipeline()->SetClient(client);
   media_pipeline_->InitializeVideo(
-      configs, scoped_ptr<CodedFrameProvider>(), status_cb);
+      configs, client, video_frame_provider_.Pass(), status_cb);
 }
 
 void MediaPipelineHost::StartPlayingFrom(base::TimeDelta time) {
@@ -157,7 +151,7 @@
 void MediaPipelineHost::SetVolume(TrackId track_id, float volume) {
   DCHECK(thread_checker_.CalledOnValidThread());
   CHECK(track_id == kAudioTrackId);
-  media_pipeline_->GetAudioPipeline()->SetVolume(volume);
+  media_pipeline_->SetVolume(volume);
 }
 
 void MediaPipelineHost::SetCdm(BrowserCdmCast* cdm) {
diff --git a/chromecast/browser/media/media_pipeline_host.h b/chromecast/browser/media/media_pipeline_host.h
index db26bb9..252a548 100644
--- a/chromecast/browser/media/media_pipeline_host.h
+++ b/chromecast/browser/media/media_pipeline_host.h
@@ -33,24 +33,25 @@
 namespace media {
 struct AvPipelineClient;
 class BrowserCdmCast;
-class MediaPipelineBackend;
 struct MediaPipelineClient;
+struct VideoPipelineClient;
+class CodedFrameProvider;
+class MediaPipelineBackend;
 struct MediaPipelineDeviceParams;
 class MediaPipelineImpl;
-struct VideoPipelineClient;
 
 class MediaPipelineHost {
  public:
   // Factory method to create a MediaPipelineBackend
-  typedef base::Callback<scoped_ptr<media::MediaPipelineBackend>(
-      const MediaPipelineDeviceParams&)> CreateDeviceComponentsCB;
+  typedef base::Callback<scoped_ptr<MediaPipelineBackend>(
+      const MediaPipelineDeviceParams&)> CreateBackendCB;
 
   MediaPipelineHost();
   ~MediaPipelineHost();
 
   void Initialize(LoadType load_type,
                   const MediaPipelineClient& client,
-                  const CreateDeviceComponentsCB& create_device_components_cb);
+                  const CreateBackendCB& create_backend_cb);
 
   void SetAvPipe(TrackId track_id,
                  scoped_ptr<base::SharedMemory> shared_mem,
@@ -62,7 +63,7 @@
                        const ::media::PipelineStatusCB& status_cb);
   void VideoInitialize(TrackId track_id,
                        const VideoPipelineClient& client,
-                       const std::vector<::media::VideoDecoderConfig>& configs,
+                       const std::vector< ::media::VideoDecoderConfig>& configs,
                        const ::media::PipelineStatusCB& status_cb);
   void StartPlayingFrom(base::TimeDelta time);
   void Flush(const ::media::PipelineStatusCB& status_cb);
@@ -80,6 +81,9 @@
   scoped_ptr<TaskRunnerImpl> task_runner_;
   scoped_ptr<MediaPipelineImpl> media_pipeline_;
 
+  scoped_ptr<CodedFrameProvider> audio_frame_provider_;
+  scoped_ptr<CodedFrameProvider> video_frame_provider_;
+
   // The shared memory for a track id must be valid until Stop is invoked on
   // that track id.
   struct MediaTrackHost;
diff --git a/chromecast/chromecast.gyp b/chromecast/chromecast.gyp
index f558b59..e71e25ce 100644
--- a/chromecast/chromecast.gyp
+++ b/chromecast/chromecast.gyp
@@ -56,18 +56,14 @@
         'public/graphics_properties_shlib.h',
         'public/graphics_types.h',
         'public/media_codec_support.h',
-        'public/media/audio_pipeline_device.h',
         'public/media/cast_decoder_buffer.h',
         'public/media/cast_decrypt_config.h',
         'public/media/cast_key_system.h',
         'public/media/decoder_config.h',
         'public/media/decrypt_context.h',
-        'public/media/media_clock_device.h',
-        'public/media/media_component_device.h',
         'public/media/media_pipeline_backend.h',
         'public/media/media_pipeline_device_params.h',
         'public/media/stream_id.h',
-        'public/media/video_pipeline_device.h',
         'public/osd_plane.h',
         'public/osd_plane_shlib.h',
         'public/osd_surface.h',
@@ -723,6 +719,12 @@
             'renderer/media/chromecast_media_renderer_factory.h',
             'renderer/media/cma_message_filter_proxy.cc',
             'renderer/media/cma_message_filter_proxy.h',
+            'renderer/media/cma_renderer.cc',
+            'renderer/media/cma_renderer.h',
+            'renderer/media/demuxer_stream_adapter.cc',
+            'renderer/media/demuxer_stream_adapter.h',
+            'renderer/media/hole_frame_factory.cc',
+            'renderer/media/hole_frame_factory.h',
             'renderer/media/media_channel_proxy.cc',
             'renderer/media/media_channel_proxy.h',
             'renderer/media/media_pipeline_proxy.cc',
diff --git a/chromecast/chromecast_tests.gypi b/chromecast/chromecast_tests.gypi
index ff96324..bc42b1c 100644
--- a/chromecast/chromecast_tests.gypi
+++ b/chromecast/chromecast_tests.gypi
@@ -169,6 +169,7 @@
         }],
         ['OS!="android"', {
           'dependencies': [
+            'cast_renderer_media_unittests',
             'cast_shell_unittests',
             'cast_shell_browser_test',
             'media/media.gyp:cast_media_unittests',
@@ -309,6 +310,22 @@
       ],  # end of targets
     }, {  # OS!="android"
       'targets': [
+        {
+          'target_name': 'cast_renderer_media_unittests',
+          'type': '<(gtest_target_type)',
+          'dependencies': [
+            'cast_shell_media',
+            '../base/base.gyp:run_all_unittests',
+            '../testing/gmock.gyp:gmock',
+            '../testing/gtest.gyp:gtest',
+          ],
+          'sources': [
+            'renderer/media/demuxer_stream_adapter_unittest.cc',
+            'renderer/media/demuxer_stream_for_test.cc',
+            'renderer/media/demuxer_stream_for_test.h',
+            'renderer/media/multi_demuxer_stream_adapter_unittest.cc',
+          ],
+        },  # end of cast_renderer_media_unittests
         # GN target: //chromecast/browser:test_support
         {
           'target_name': 'cast_shell_test_support',
diff --git a/chromecast/media/BUILD.gn b/chromecast/media/BUILD.gn
index 4961a3f7..f12385b 100644
--- a/chromecast/media/BUILD.gn
+++ b/chromecast/media/BUILD.gn
@@ -21,20 +21,14 @@
     "cma/base/balanced_media_task_runner_unittest.cc",
     "cma/base/buffering_controller_unittest.cc",
     "cma/base/buffering_frame_provider_unittest.cc",
-    "cma/filters/demuxer_stream_adapter_unittest.cc",
-    "cma/filters/multi_demuxer_stream_adapter_unittest.cc",
     "cma/ipc/media_message_fifo_unittest.cc",
     "cma/ipc/media_message_unittest.cc",
     "cma/ipc_streamer/av_streamer_unittest.cc",
     "cma/pipeline/audio_video_pipeline_impl_unittest.cc",
-    "cma/test/demuxer_stream_for_test.cc",
-    "cma/test/demuxer_stream_for_test.h",
     "cma/test/frame_generator_for_test.cc",
     "cma/test/frame_generator_for_test.h",
     "cma/test/frame_segmenter_for_test.cc",
     "cma/test/frame_segmenter_for_test.h",
-    "cma/test/media_component_device_feeder_for_test.cc",
-    "cma/test/media_component_device_feeder_for_test.h",
     "cma/test/mock_frame_consumer.cc",
     "cma/test/mock_frame_consumer.h",
     "cma/test/mock_frame_provider.cc",
@@ -47,6 +41,12 @@
   deps = [
     ":media",
     "//chromecast/media/audio:test_support",
+    "//chromecast/media/base:message_loop",
+    "//chromecast/media/cma/backend",
+    "//chromecast/media/cma/base",
+    "//chromecast/media/cma/ipc",
+    "//chromecast/media/cma/ipc_streamer",
+    "//chromecast/media/cma/pipeline",
     "//base",
     "//base:i18n",
     "//base/test:test_support",
diff --git a/chromecast/media/audio/BUILD.gn b/chromecast/media/audio/BUILD.gn
index a5ca0f1..5d87fa3 100644
--- a/chromecast/media/audio/BUILD.gn
+++ b/chromecast/media/audio/BUILD.gn
@@ -28,8 +28,11 @@
 
   configs += [ "//chromecast:config" ]
 
-  deps = [
+  public_deps = [
     ":audio",
+  ]
+
+  deps = [
     "//testing/gtest",
   ]
 }
diff --git a/chromecast/media/audio/cast_audio_output_stream.cc b/chromecast/media/audio/cast_audio_output_stream.cc
index 5f0645e..73c935b3 100644
--- a/chromecast/media/audio/cast_audio_output_stream.cc
+++ b/chromecast/media/audio/cast_audio_output_stream.cc
@@ -5,6 +5,7 @@
 #include "chromecast/media/audio/cast_audio_output_stream.h"
 
 #include "base/bind.h"
+#include "base/callback_helpers.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread_checker.h"
 #include "chromecast/base/metrics/cast_metrics_helper.h"
@@ -13,11 +14,8 @@
 #include "chromecast/media/base/media_message_loop.h"
 #include "chromecast/media/cma/base/cast_decoder_buffer_impl.h"
 #include "chromecast/media/cma/base/decoder_buffer_adapter.h"
-#include "chromecast/media/cma/pipeline/frame_status_cb_impl.h"
-#include "chromecast/public/media/audio_pipeline_device.h"
 #include "chromecast/public/media/decoder_config.h"
 #include "chromecast/public/media/decrypt_context.h"
-#include "chromecast/public/media/media_clock_device.h"
 #include "chromecast/public/media/media_pipeline_backend.h"
 #include "chromecast/public/media/media_pipeline_device_params.h"
 #include "media/base/bind_to_current_loop.h"
@@ -25,28 +23,18 @@
 
 namespace chromecast {
 namespace media {
-
 namespace {
-bool InitClockDevice(MediaClockDevice* clock_device) {
-  DCHECK(clock_device);
-  DCHECK_EQ(clock_device->GetState(), MediaClockDevice::kStateUninitialized);
 
-  if (!clock_device->SetState(media::MediaClockDevice::kStateIdle))
-    return false;
+MediaPipelineBackend::AudioDecoder* InitializeBackend(
+    const ::media::AudioParameters& audio_params,
+    MediaPipelineBackend* backend,
+    MediaPipelineBackend::Delegate* delegate) {
+  DCHECK(backend);
+  DCHECK(delegate);
 
-  if (!clock_device->ResetTimeline(0))
-    return false;
-
-  if (!clock_device->SetRate(1.0))
-    return false;
-
-  return true;
-}
-
-bool InitAudioDevice(const ::media::AudioParameters& audio_params,
-                     AudioPipelineDevice* audio_device) {
-  DCHECK(audio_device);
-  DCHECK_EQ(audio_device->GetState(), AudioPipelineDevice::kStateUninitialized);
+  MediaPipelineBackend::AudioDecoder* decoder = backend->CreateAudioDecoder();
+  if (!decoder)
+    return nullptr;
 
   AudioConfig audio_config;
   audio_config.codec = kCodecPCM;
@@ -57,114 +45,140 @@
   audio_config.extra_data = nullptr;
   audio_config.extra_data_size = 0;
   audio_config.is_encrypted = false;
-  if (!audio_device->SetConfig(audio_config))
-    return false;
 
-  if (!audio_device->SetState(AudioPipelineDevice::kStateIdle))
-    return false;
+  if (!decoder->SetConfig(audio_config))
+    return nullptr;
 
-  return true;
+  if (!backend->Initialize(delegate))
+    return nullptr;
+
+  return decoder;
 }
+
 }  // namespace
 
 // Backend represents a MediaPipelineBackend adapter that runs on cast
 // media thread (media::MediaMessageLoop::GetTaskRunner).
 // It can be created and destroyed on any thread, but all other member functions
 // must be called on a single thread.
-class CastAudioOutputStream::Backend {
+class CastAudioOutputStream::Backend : public MediaPipelineBackend::Delegate {
  public:
-  typedef base::Callback<void(bool)> PushFrameCompletionCallback;
+  typedef base::Callback<void(bool)> PushBufferCompletionCallback;
 
   Backend(const ::media::AudioParameters& audio_params)
-      : audio_params_(audio_params) {
+      : audio_params_(audio_params),
+        decoder_(nullptr),
+        first_start_(true),
+        error_(false),
+        backend_buffer_(nullptr) {
     thread_checker_.DetachFromThread();
   }
-  ~Backend() {}
+  ~Backend() override {}
 
   void Open(CastAudioManager* audio_manager,
             bool* success,
             base::WaitableEvent* completion_event) {
     DCHECK(thread_checker_.CalledOnValidThread());
     DCHECK(backend_ == nullptr);
+    DCHECK(audio_manager);
+    DCHECK(success);
+    DCHECK(completion_event);
 
     backend_task_runner_.reset(new TaskRunnerImpl());
     MediaPipelineDeviceParams device_params(
         MediaPipelineDeviceParams::kModeIgnorePts, backend_task_runner_.get());
-
-    scoped_ptr<MediaPipelineBackend> pipeline_backend =
-        audio_manager->CreateMediaPipelineBackend(device_params);
-    if (pipeline_backend && InitClockDevice(pipeline_backend->GetClock()) &&
-        InitAudioDevice(audio_params_, pipeline_backend->GetAudio())) {
-      backend_ = pipeline_backend.Pass();
-    }
-    *success = backend_ != nullptr;
+    backend_ = audio_manager->CreateMediaPipelineBackend(device_params);
+    if (backend_)
+      decoder_ = InitializeBackend(audio_params_, backend_.get(), this);
+    *success = decoder_ != nullptr;
     completion_event->Signal();
   }
 
   void Close() {
     DCHECK(thread_checker_.CalledOnValidThread());
 
-    if (backend_) {
-      backend_->GetClock()->SetState(MediaClockDevice::kStateIdle);
-      backend_->GetAudio()->SetState(AudioPipelineDevice::kStateIdle);
-    }
+    if (backend_)
+      backend_->Stop();
     backend_.reset();
     backend_task_runner_.reset();
   }
 
   void Start() {
     DCHECK(thread_checker_.CalledOnValidThread());
+    DCHECK(backend_);
 
-    MediaClockDevice* clock_device = backend_->GetClock();
-    clock_device->SetState(MediaClockDevice::kStateRunning);
-    clock_device->SetRate(1.0f);
-
-    AudioPipelineDevice* audio_device = backend_->GetAudio();
-    audio_device->SetState(AudioPipelineDevice::kStateRunning);
+    if (first_start_) {
+      first_start_ = false;
+      backend_->Start(0);
+    } else {
+      backend_->Resume();
+    }
   }
 
   void Stop() {
     DCHECK(thread_checker_.CalledOnValidThread());
+    DCHECK(backend_);
 
-    MediaClockDevice* clock_device = backend_->GetClock();
-    clock_device->SetRate(0.0f);
+    backend_->Pause();
   }
 
-  void PushFrame(scoped_refptr<media::DecoderBufferBase> decoder_buffer,
-                 const PushFrameCompletionCallback& completion_cb) {
+  void PushBuffer(scoped_refptr<media::DecoderBufferBase> decoder_buffer,
+                  const PushBufferCompletionCallback& completion_cb) {
     DCHECK(thread_checker_.CalledOnValidThread());
+    DCHECK(decoder_);
+    DCHECK(!completion_cb.is_null());
+    DCHECK(completion_cb_.is_null());
+    if (error_) {
+      completion_cb.Run(false);
+      return;
+    }
 
-    AudioPipelineDevice* audio_device = backend_->GetAudio();
-    MediaComponentDevice::FrameStatus status =
-        audio_device->PushFrame(nullptr,  // decrypt_context
-                                new CastDecoderBufferImpl(decoder_buffer),
-                                new media::FrameStatusCBImpl(base::Bind(
-                                    &Backend::OnPushFrameStatus,
-                                    base::Unretained(this), completion_cb)));
+    backend_buffer_.set_buffer(decoder_buffer);
 
-    if (status != MediaComponentDevice::kFramePending)
-      OnPushFrameStatus(completion_cb, status);
+    MediaPipelineBackend::BufferStatus status =
+        decoder_->PushBuffer(nullptr /* decrypt_context */, &backend_buffer_);
+    completion_cb_ = completion_cb;
+    if (status != MediaPipelineBackend::kBufferPending)
+      OnPushBufferComplete(decoder_, status);
   }
 
   void SetVolume(double volume) {
     DCHECK(thread_checker_.CalledOnValidThread());
+    DCHECK(decoder_);
+    decoder_->SetVolume(volume);
+  }
 
-    AudioPipelineDevice* audio_device = backend_->GetAudio();
-    audio_device->SetStreamVolumeMultiplier(volume);
+  // MediaPipelineBackend::Delegate implementation
+  void OnVideoResolutionChanged(MediaPipelineBackend::VideoDecoder* decoder,
+                                const Size& size) override {}
+
+  void OnPushBufferComplete(
+      MediaPipelineBackend::Decoder* decoder,
+      MediaPipelineBackend::BufferStatus status) override {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    DCHECK_NE(status, MediaPipelineBackend::kBufferPending);
+
+    base::ResetAndReturn(&completion_cb_)
+        .Run(status == MediaPipelineBackend::kBufferSuccess);
+  }
+
+  void OnEndOfStream(MediaPipelineBackend::Decoder* decoder) override {}
+
+  void OnDecoderError(MediaPipelineBackend::Decoder* decoder) override {
+    error_ = true;
+    if (!completion_cb_.is_null())
+      OnPushBufferComplete(decoder_, MediaPipelineBackend::kBufferFailed);
   }
 
  private:
-  void OnPushFrameStatus(const PushFrameCompletionCallback& completion_cb,
-                         MediaComponentDevice::FrameStatus status) {
-    DCHECK(thread_checker_.CalledOnValidThread());
-    DCHECK_NE(status, MediaComponentDevice::kFramePending);
-
-    completion_cb.Run(status == MediaComponentDevice::kFrameSuccess);
-  }
-
   const ::media::AudioParameters audio_params_;
   scoped_ptr<MediaPipelineBackend> backend_;
   scoped_ptr<TaskRunnerImpl> backend_task_runner_;
+  MediaPipelineBackend::AudioDecoder* decoder_;
+  PushBufferCompletionCallback completion_cb_;
+  bool first_start_;
+  bool error_;
+  CastDecoderBufferImpl backend_buffer_;
   base::ThreadChecker thread_checker_;
   DISALLOW_COPY_AND_ASSIGN(Backend);
 };
@@ -248,7 +262,7 @@
   next_push_time_ = base::TimeTicks::Now();
   if (!push_in_progress_) {
     audio_task_runner_->PostTask(FROM_HERE,
-                                 base::Bind(&CastAudioOutputStream::PushFrame,
+                                 base::Bind(&CastAudioOutputStream::PushBuffer,
                                             weak_factory_.GetWeakPtr()));
     push_in_progress_ = true;
   }
@@ -288,7 +302,7 @@
   audio_manager_->ReleaseOutputStream(this);
 }
 
-void CastAudioOutputStream::PushFrame() {
+void CastAudioOutputStream::PushBuffer() {
   DCHECK(audio_task_runner_->BelongsToCurrentThread());
   DCHECK(push_in_progress_);
 
@@ -307,15 +321,17 @@
   audio_bus_->ToInterleaved(frame_count, audio_params_.bits_per_sample() / 8,
                             decoder_buffer_->writable_data());
 
-  auto completion_cb = ::media::BindToCurrentLoop(base::Bind(
-      &CastAudioOutputStream::OnPushFrameComplete, weak_factory_.GetWeakPtr()));
-  backend_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&Backend::PushFrame, base::Unretained(backend_.get()),
-                 decoder_buffer_, completion_cb));
+  auto completion_cb = ::media::BindToCurrentLoop(
+      base::Bind(&CastAudioOutputStream::OnPushBufferComplete,
+                 weak_factory_.GetWeakPtr()));
+  backend_task_runner_->PostTask(FROM_HERE,
+                                 base::Bind(&Backend::PushBuffer,
+                                            base::Unretained(backend_.get()),
+                                            decoder_buffer_,
+                                            completion_cb));
 }
 
-void CastAudioOutputStream::OnPushFrameComplete(bool success) {
+void CastAudioOutputStream::OnPushBufferComplete(bool success) {
   DCHECK(audio_task_runner_->BelongsToCurrentThread());
   DCHECK(push_in_progress_);
 
@@ -329,8 +345,8 @@
     return;
   }
 
-  // Schedule next push frame.
-  // Need to account for time spent in pulling and pushing frame as well
+  // Schedule next push buffer.
+  // Need to account for time spent in pulling and pushing buffer as well
   // as the imprecision of PostDelayedTask().
   const base::TimeTicks now = base::TimeTicks::Now();
   base::TimeDelta delay = next_push_time_ + buffer_duration_ - now;
@@ -339,7 +355,8 @@
 
   audio_task_runner_->PostDelayedTask(
       FROM_HERE,
-      base::Bind(&CastAudioOutputStream::PushFrame, weak_factory_.GetWeakPtr()),
+      base::Bind(&CastAudioOutputStream::PushBuffer,
+                 weak_factory_.GetWeakPtr()),
       delay);
   push_in_progress_ = true;
 }
diff --git a/chromecast/media/audio/cast_audio_output_stream.h b/chromecast/media/audio/cast_audio_output_stream.h
index 222947f..6c54fce 100644
--- a/chromecast/media/audio/cast_audio_output_stream.h
+++ b/chromecast/media/audio/cast_audio_output_stream.h
@@ -39,8 +39,8 @@
   class Backend;
 
   void OnClosed();
-  void PushFrame();
-  void OnPushFrameComplete(bool success);
+  void PushBuffer();
+  void OnPushBufferComplete(bool success);
 
   const ::media::AudioParameters audio_params_;
   CastAudioManager* const audio_manager_;
diff --git a/chromecast/media/audio/cast_audio_output_stream_unittest.cc b/chromecast/media/audio/cast_audio_output_stream_unittest.cc
index 4869d1f9..7de01be 100644
--- a/chromecast/media/audio/cast_audio_output_stream_unittest.cc
+++ b/chromecast/media/audio/cast_audio_output_stream_unittest.cc
@@ -8,11 +8,10 @@
 #include "chromecast/media/audio/cast_audio_manager.h"
 #include "chromecast/media/audio/cast_audio_output_stream.h"
 #include "chromecast/media/base/media_message_loop.h"
-#include "chromecast/public/media/audio_pipeline_device.h"
+#include "chromecast/media/cma/backend/media_pipeline_backend_default.h"
 #include "chromecast/public/media/cast_decoder_buffer.h"
 #include "chromecast/public/media/decoder_config.h"
 #include "chromecast/public/media/decrypt_context.h"
-#include "chromecast/public/media/media_clock_device.h"
 #include "chromecast/public/media/media_pipeline_backend.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -29,31 +28,7 @@
   completion_event.Wait();
 }
 
-class FakeClockDevice : public MediaClockDevice {
- public:
-  FakeClockDevice() : state_(kStateUninitialized), rate_(0.f) {}
-  ~FakeClockDevice() override {}
-
-  State GetState() const override { return state_; }
-  bool SetState(State new_state) override {
-    state_ = new_state;
-    return true;
-  }
-  bool ResetTimeline(int64_t time_microseconds) override { return true; }
-  bool SetRate(float rate) override {
-    rate_ = rate;
-    return true;
-  }
-  int64_t GetTimeMicroseconds() override { return 0; }
-
-  float rate() const { return rate_; }
-
- private:
-  State state_;
-  float rate_;
-};
-
-class FakeAudioPipelineDevice : public AudioPipelineDevice {
+class FakeAudioDecoder : public MediaPipelineBackend::AudioDecoder {
  public:
   enum PipelineStatus {
     PIPELINE_STATUS_OK,
@@ -61,99 +36,127 @@
     PIPELINE_STATUS_ERROR
   };
 
-  FakeAudioPipelineDevice()
-      : state_(kStateUninitialized),
-        volume_multiplier_(1.0f),
+  FakeAudioDecoder()
+      : volume_(1.0f),
         pipeline_status_(PIPELINE_STATUS_OK),
-        pushed_frame_count_(0) {}
-  ~FakeAudioPipelineDevice() override {}
+        pending_push_(false),
+        pushed_buffer_count_(0),
+        last_decrypt_context_(nullptr),
+        last_buffer_(nullptr),
+        delegate_(nullptr) {}
+  ~FakeAudioDecoder() override {}
 
-  // AudioPipelineDevice overrides.
-  void SetClient(Client* client) override {}
-  bool SetState(State new_state) override {
-    state_ = new_state;
-    return true;
-  }
-  State GetState() const override { return state_; }
-  bool SetStartPts(int64_t microseconds) override { return false; }
-  FrameStatus PushFrame(DecryptContext* decrypt_context,
-                        CastDecoderBuffer* buffer,
-                        FrameStatusCB* completion_cb) override {
-    last_frame_decrypt_context_.reset(decrypt_context);
-    last_frame_buffer_.reset(buffer);
-    last_frame_completion_cb_.reset(completion_cb);
-    ++pushed_frame_count_;
+  // MediaPipelineBackend::AudioDecoder overrides.
+  BufferStatus PushBuffer(DecryptContext* decrypt_context,
+                          CastDecoderBuffer* buffer) override {
+    last_decrypt_context_ = decrypt_context;
+    last_buffer_ = buffer;
+    ++pushed_buffer_count_;
 
     switch (pipeline_status_) {
       case PIPELINE_STATUS_OK:
-        return kFrameSuccess;
+        return MediaPipelineBackend::kBufferSuccess;
       case PIPELINE_STATUS_BUSY:
-        return kFramePending;
+        pending_push_ = true;
+        return MediaPipelineBackend::kBufferPending;
       case PIPELINE_STATUS_ERROR:
-        return kFrameFailed;
+        return MediaPipelineBackend::kBufferFailed;
       default:
         NOTREACHED();
+        return MediaPipelineBackend::kBufferFailed;
     }
-
-    // This will never be reached but is necessary for compiler warnings.
-    return kFrameFailed;
   }
-  RenderingDelay GetRenderingDelay() const override { return RenderingDelay(); }
-  bool GetStatistics(Statistics* stats) const override { return false; }
+  void GetStatistics(Statistics* statistics) override {}
   bool SetConfig(const AudioConfig& config) override {
     config_ = config;
     return true;
   }
-  void SetStreamVolumeMultiplier(float multiplier) override {
-    volume_multiplier_ = multiplier;
+  bool SetVolume(float volume) override {
+    volume_ = volume;
+    return true;
   }
+  RenderingDelay GetRenderingDelay() override { return RenderingDelay(); }
 
   const AudioConfig& config() const { return config_; }
-  float volume_multiplier() const { return volume_multiplier_; }
-  void set_pipeline_status(PipelineStatus status) { pipeline_status_ = status; }
-  unsigned pushed_frame_count() const { return pushed_frame_count_; }
-  DecryptContext* last_frame_decrypt_context() {
-    return last_frame_decrypt_context_.get();
+  float volume() const { return volume_; }
+  void set_pipeline_status(PipelineStatus status) {
+    if (pipeline_status_ == PIPELINE_STATUS_BUSY &&
+        status == PIPELINE_STATUS_OK && pending_push_) {
+      pending_push_ = false;
+      delegate_->OnPushBufferComplete(this,
+                                      MediaPipelineBackend::kBufferSuccess);
+    }
+    pipeline_status_ = status;
   }
-  CastDecoderBuffer* last_frame_buffer() { return last_frame_buffer_.get(); }
-  FrameStatusCB* last_frame_completion_cb() {
-    return last_frame_completion_cb_.get();
+  unsigned pushed_buffer_count() const { return pushed_buffer_count_; }
+  DecryptContext* last_decrypt_context() { return last_decrypt_context_; }
+  CastDecoderBuffer* last_buffer() { return last_buffer_; }
+  void set_delegate(MediaPipelineBackend::Delegate* delegate) {
+    delegate_ = delegate;
   }
 
  private:
-  State state_;
   AudioConfig config_;
-  float volume_multiplier_;
+  float volume_;
 
   PipelineStatus pipeline_status_;
-  unsigned pushed_frame_count_;
-  scoped_ptr<DecryptContext> last_frame_decrypt_context_;
-  scoped_ptr<CastDecoderBuffer> last_frame_buffer_;
-  scoped_ptr<FrameStatusCB> last_frame_completion_cb_;
+  bool pending_push_;
+  int pushed_buffer_count_;
+  DecryptContext* last_decrypt_context_;
+  CastDecoderBuffer* last_buffer_;
+  MediaPipelineBackend::Delegate* delegate_;
 };
 
 class FakeMediaPipelineBackend : public MediaPipelineBackend {
  public:
+  enum State { kStateStopped, kStateRunning, kStatePaused };
+
+  FakeMediaPipelineBackend() : state_(kStateStopped), audio_decoder_(nullptr) {}
   ~FakeMediaPipelineBackend() override {}
 
-  MediaClockDevice* GetClock() override {
-    if (!clock_device_)
-      clock_device_.reset(new FakeClockDevice);
-    return clock_device_.get();
+  // MediaPipelineBackend implementation:
+  AudioDecoder* CreateAudioDecoder() override {
+    DCHECK(!audio_decoder_);
+    audio_decoder_ = new FakeAudioDecoder();
+    return audio_decoder_;
   }
-  AudioPipelineDevice* GetAudio() override {
-    if (!audio_device_)
-      audio_device_.reset(new FakeAudioPipelineDevice);
-    return audio_device_.get();
-  }
-  VideoPipelineDevice* GetVideo() override {
+  VideoDecoder* CreateVideoDecoder() override {
     NOTREACHED();
     return nullptr;
   }
 
+  bool Initialize(Delegate* delegate) override {
+    audio_decoder_->set_delegate(delegate);
+    return true;
+  }
+  bool Start(int64_t start_pts) override {
+    DCHECK(state_ == kStateStopped);
+    state_ = kStateRunning;
+    return true;
+  }
+  bool Stop() override {
+    state_ = kStateStopped;
+    return true;
+  }
+  bool Pause() override {
+    DCHECK(state_ == kStateRunning);
+    state_ = kStatePaused;
+    return true;
+  }
+  bool Resume() override {
+    DCHECK(state_ == kStatePaused);
+    state_ = kStateRunning;
+    return true;
+  }
+  int64_t GetCurrentPts() override { return 0; }
+  bool SetPlaybackRate(float rate) override { return true; }
+
+  State state() const { return state_; }
+  FakeAudioDecoder* decoder() const { return audio_decoder_; }
+
  private:
-  scoped_ptr<FakeClockDevice> clock_device_;
-  scoped_ptr<FakeAudioPipelineDevice> audio_device_;
+  State state_;
+  FakeAudioDecoder* audio_decoder_;
 };
 
 class FakeAudioSourceCallback
@@ -187,7 +190,8 @@
     DCHECK(media::MediaMessageLoop::GetTaskRunner()->BelongsToCurrentThread());
     DCHECK(!media_pipeline_backend_);
 
-    scoped_ptr<FakeMediaPipelineBackend> backend(new FakeMediaPipelineBackend);
+    scoped_ptr<FakeMediaPipelineBackend> backend(
+        new FakeMediaPipelineBackend());
     // Cache the backend locally to be used by tests.
     media_pipeline_backend_ = backend.get();
     return backend.Pass();
@@ -236,15 +240,14 @@
     return ::media::AudioParameters(format_, channel_layout_, sample_rate_,
                                     bits_per_sample_, frames_per_buffer_);
   }
-  FakeClockDevice* GetClock() {
-    MediaPipelineBackend* backend = audio_manager_->media_pipeline_backend();
-    return backend ? static_cast<FakeClockDevice*>(backend->GetClock())
-                   : nullptr;
+
+  FakeMediaPipelineBackend* GetBackend() {
+    return audio_manager_->media_pipeline_backend();
   }
-  FakeAudioPipelineDevice* GetAudio() {
-    MediaPipelineBackend* backend = audio_manager_->media_pipeline_backend();
-    return backend ? static_cast<FakeAudioPipelineDevice*>(backend->GetAudio())
-                   : nullptr;
+
+  FakeAudioDecoder* GetAudio() {
+    FakeMediaPipelineBackend* backend = GetBackend();
+    return (backend ? backend->decoder() : nullptr);
   }
 
   // Synchronous utility functions.
@@ -373,9 +376,9 @@
     ASSERT_TRUE(stream);
     EXPECT_TRUE(OpenStream(stream));
 
-    FakeAudioPipelineDevice* audio_device = GetAudio();
-    ASSERT_TRUE(audio_device);
-    const AudioConfig& audio_config = audio_device->config();
+    FakeAudioDecoder* audio_decoder = GetAudio();
+    ASSERT_TRUE(audio_decoder);
+    const AudioConfig& audio_config = audio_decoder->config();
     EXPECT_EQ(kCodecPCM, audio_config.codec);
     EXPECT_EQ(kSampleFormatS16, audio_config.sample_format);
     EXPECT_FALSE(audio_config.is_encrypted);
@@ -393,9 +396,9 @@
     ASSERT_TRUE(stream);
     EXPECT_TRUE(OpenStream(stream));
 
-    FakeAudioPipelineDevice* audio_device = GetAudio();
-    ASSERT_TRUE(audio_device);
-    const AudioConfig& audio_config = audio_device->config();
+    FakeAudioDecoder* audio_decoder = GetAudio();
+    ASSERT_TRUE(audio_decoder);
+    const AudioConfig& audio_config = audio_decoder->config();
     EXPECT_EQ(::media::ChannelLayoutToChannelCount(channel_layout_),
               audio_config.channel_number);
 
@@ -409,9 +412,9 @@
   ASSERT_TRUE(stream);
   EXPECT_TRUE(OpenStream(stream));
 
-  FakeAudioPipelineDevice* audio_device = GetAudio();
-  ASSERT_TRUE(audio_device);
-  const AudioConfig& audio_config = audio_device->config();
+  FakeAudioDecoder* audio_decoder = GetAudio();
+  ASSERT_TRUE(audio_decoder);
+  const AudioConfig& audio_config = audio_decoder->config();
   EXPECT_EQ(sample_rate_, audio_config.samples_per_second);
 
   CloseStream(stream);
@@ -423,9 +426,9 @@
   ASSERT_TRUE(stream);
   EXPECT_TRUE(OpenStream(stream));
 
-  FakeAudioPipelineDevice* audio_device = GetAudio();
-  ASSERT_TRUE(audio_device);
-  const AudioConfig& audio_config = audio_device->config();
+  FakeAudioDecoder* audio_decoder = GetAudio();
+  ASSERT_TRUE(audio_decoder);
+  const AudioConfig& audio_config = audio_decoder->config();
   EXPECT_EQ(bits_per_sample_ / 8, audio_config.bytes_per_channel);
 
   CloseStream(stream);
@@ -437,25 +440,19 @@
   EXPECT_FALSE(GetAudio());
 
   EXPECT_TRUE(OpenStream(stream));
-  AudioPipelineDevice* audio_device = GetAudio();
-  ASSERT_TRUE(audio_device);
-  FakeClockDevice* clock_device = GetClock();
-  ASSERT_TRUE(clock_device);
-  EXPECT_EQ(AudioPipelineDevice::kStateIdle, audio_device->GetState());
-  EXPECT_EQ(MediaClockDevice::kStateIdle, clock_device->GetState());
-  EXPECT_EQ(1.f, clock_device->rate());
+  FakeAudioDecoder* audio_decoder = GetAudio();
+  ASSERT_TRUE(audio_decoder);
+  FakeMediaPipelineBackend* backend = GetBackend();
+  ASSERT_TRUE(backend);
+  EXPECT_EQ(FakeMediaPipelineBackend::kStateStopped, backend->state());
 
   scoped_ptr<FakeAudioSourceCallback> source_callback(
       new FakeAudioSourceCallback);
   StartStream(stream, source_callback.get());
-  EXPECT_EQ(AudioPipelineDevice::kStateRunning, audio_device->GetState());
-  EXPECT_EQ(MediaClockDevice::kStateRunning, clock_device->GetState());
-  EXPECT_EQ(1.f, clock_device->rate());
+  EXPECT_EQ(FakeMediaPipelineBackend::kStateRunning, backend->state());
 
   StopStream(stream);
-  EXPECT_EQ(AudioPipelineDevice::kStateRunning, audio_device->GetState());
-  EXPECT_EQ(MediaClockDevice::kStateRunning, clock_device->GetState());
-  EXPECT_EQ(0.f, clock_device->rate());
+  EXPECT_EQ(FakeMediaPipelineBackend::kStatePaused, backend->state());
 
   CloseStream(stream);
   EXPECT_FALSE(GetAudio());
@@ -466,13 +463,12 @@
   ASSERT_TRUE(stream);
   EXPECT_TRUE(OpenStream(stream));
 
-  FakeAudioPipelineDevice* audio_device = GetAudio();
-  ASSERT_TRUE(audio_device);
+  FakeAudioDecoder* audio_decoder = GetAudio();
+  ASSERT_TRUE(audio_decoder);
   // Verify initial state.
-  EXPECT_EQ(0u, audio_device->pushed_frame_count());
-  EXPECT_FALSE(audio_device->last_frame_decrypt_context());
-  EXPECT_FALSE(audio_device->last_frame_buffer());
-  EXPECT_FALSE(audio_device->last_frame_completion_cb());
+  EXPECT_EQ(0u, audio_decoder->pushed_buffer_count());
+  EXPECT_FALSE(audio_decoder->last_decrypt_context());
+  EXPECT_FALSE(audio_decoder->last_buffer());
 
   scoped_ptr<FakeAudioSourceCallback> source_callback(
       new FakeAudioSourceCallback);
@@ -480,17 +476,16 @@
   StopStream(stream);
 
   // Verify that the stream pushed frames to the backend.
-  EXPECT_LT(0u, audio_device->pushed_frame_count());
+  EXPECT_LT(0u, audio_decoder->pushed_buffer_count());
   // DecryptContext is always NULL becuase of "raw" audio.
-  EXPECT_FALSE(audio_device->last_frame_decrypt_context());
-  EXPECT_TRUE(audio_device->last_frame_buffer());
-  EXPECT_TRUE(audio_device->last_frame_completion_cb());
+  EXPECT_FALSE(audio_decoder->last_decrypt_context());
+  EXPECT_TRUE(audio_decoder->last_buffer());
 
   // Verify decoder buffer.
   ::media::AudioParameters audio_params = GetAudioParams();
   const size_t expected_frame_size =
       static_cast<size_t>(audio_params.GetBytesPerBuffer());
-  const CastDecoderBuffer* buffer = audio_device->last_frame_buffer();
+  const CastDecoderBuffer* buffer = audio_decoder->last_buffer();
   EXPECT_TRUE(buffer->data());
   EXPECT_EQ(expected_frame_size, buffer->data_size());
   EXPECT_FALSE(buffer->decrypt_config());  // Null because of raw audio.
@@ -507,17 +502,16 @@
   ASSERT_TRUE(stream);
   EXPECT_TRUE(OpenStream(stream));
 
-  FakeAudioPipelineDevice* audio_device = GetAudio();
-  ASSERT_TRUE(audio_device);
-  audio_device->set_pipeline_status(
-      FakeAudioPipelineDevice::PIPELINE_STATUS_BUSY);
+  FakeAudioDecoder* audio_decoder = GetAudio();
+  ASSERT_TRUE(audio_decoder);
+  audio_decoder->set_pipeline_status(FakeAudioDecoder::PIPELINE_STATUS_BUSY);
 
   scoped_ptr<FakeAudioSourceCallback> source_callback(
       new FakeAudioSourceCallback);
   StartStream(stream, source_callback.get());
 
   // Make sure that one frame was pushed.
-  EXPECT_EQ(1u, audio_device->pushed_frame_count());
+  EXPECT_EQ(1u, audio_decoder->pushed_buffer_count());
   // No error must be reported to source callback.
   EXPECT_FALSE(source_callback->error());
 
@@ -528,17 +522,20 @@
   base::PlatformThread::Sleep(pause);
   RunUntilIdle(audio_task_runner_.get());
   RunUntilIdle(backend_task_runner_.get());
-  EXPECT_EQ(1u, audio_device->pushed_frame_count());
+  EXPECT_EQ(1u, audio_decoder->pushed_buffer_count());
 
   // Unblock the pipeline and verify that PushFrame resumes.
-  audio_device->set_pipeline_status(
-      FakeAudioPipelineDevice::PIPELINE_STATUS_OK);
-  audio_device->last_frame_completion_cb()->Run(
-      MediaComponentDevice::kFrameSuccess);
+  // (have to post because this directly calls buffer complete)
+  backend_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&FakeAudioDecoder::set_pipeline_status,
+                 base::Unretained(audio_decoder),
+                 FakeAudioDecoder::PIPELINE_STATUS_OK));
+
   base::PlatformThread::Sleep(pause);
   RunUntilIdle(audio_task_runner_.get());
   RunUntilIdle(backend_task_runner_.get());
-  EXPECT_LT(1u, audio_device->pushed_frame_count());
+  EXPECT_LT(1u, audio_decoder->pushed_buffer_count());
   EXPECT_FALSE(source_callback->error());
 
   StopStream(stream);
@@ -550,17 +547,16 @@
   ASSERT_TRUE(stream);
   EXPECT_TRUE(OpenStream(stream));
 
-  FakeAudioPipelineDevice* audio_device = GetAudio();
-  ASSERT_TRUE(audio_device);
-  audio_device->set_pipeline_status(
-      FakeAudioPipelineDevice::PIPELINE_STATUS_ERROR);
+  FakeAudioDecoder* audio_decoder = GetAudio();
+  ASSERT_TRUE(audio_decoder);
+  audio_decoder->set_pipeline_status(FakeAudioDecoder::PIPELINE_STATUS_ERROR);
 
   scoped_ptr<FakeAudioSourceCallback> source_callback(
       new FakeAudioSourceCallback);
   StartStream(stream, source_callback.get());
 
   // Make sure that AudioOutputStream attempted to push the initial frame.
-  EXPECT_LT(0u, audio_device->pushed_frame_count());
+  EXPECT_LT(0u, audio_decoder->pushed_buffer_count());
   // AudioOutputStream must report error to source callback.
   EXPECT_TRUE(source_callback->error());
 
@@ -572,17 +568,17 @@
   ::media::AudioOutputStream* stream = CreateStream();
   ASSERT_TRUE(stream);
   ASSERT_TRUE(OpenStream(stream));
-  FakeAudioPipelineDevice* audio_device = GetAudio();
-  ASSERT_TRUE(audio_device);
+  FakeAudioDecoder* audio_decoder = GetAudio();
+  ASSERT_TRUE(audio_decoder);
 
   double volume = GetStreamVolume(stream);
   EXPECT_EQ(1.0, volume);
-  EXPECT_EQ(1.0f, audio_device->volume_multiplier());
+  EXPECT_EQ(1.0f, audio_decoder->volume());
 
   SetStreamVolume(stream, 0.5);
   volume = GetStreamVolume(stream);
   EXPECT_EQ(0.5, volume);
-  EXPECT_EQ(0.5f, audio_device->volume_multiplier());
+  EXPECT_EQ(0.5f, audio_decoder->volume());
 
   CloseStream(stream);
 }
@@ -606,12 +602,9 @@
   RunUntilIdle(audio_task_runner_.get());
   RunUntilIdle(backend_task_runner_.get());
 
-  AudioPipelineDevice* audio_device = GetAudio();
-  FakeClockDevice* clock_device = GetClock();
-  ASSERT_TRUE(audio_device && clock_device);
-  EXPECT_EQ(AudioPipelineDevice::kStateRunning, audio_device->GetState());
-  EXPECT_EQ(MediaClockDevice::kStateRunning, clock_device->GetState());
-  EXPECT_EQ(1.f, clock_device->rate());
+  FakeAudioDecoder* audio_device = GetAudio();
+  EXPECT_TRUE(audio_device);
+  EXPECT_EQ(FakeMediaPipelineBackend::kStateRunning, GetBackend()->state());
 
   CloseStream(stream);
 }
diff --git a/chromecast/media/base/cast_media_default.cc b/chromecast/media/base/cast_media_default.cc
index 9c83431..1f44a68e 100644
--- a/chromecast/media/base/cast_media_default.cc
+++ b/chromecast/media/base/cast_media_default.cc
@@ -39,7 +39,7 @@
 
 MediaPipelineBackend* CastMediaShlib::CreateMediaPipelineBackend(
     const MediaPipelineDeviceParams& params) {
-  return new MediaPipelineBackendDefault(params);
+  return new MediaPipelineBackendDefault();
 }
 
 MediaCodecSupportShlib::CodecSupport MediaCodecSupportShlib::IsSupported(
diff --git a/chromecast/media/cma/BUILD.gn b/chromecast/media/cma/BUILD.gn
index c9da6296f..b4b1f6d 100644
--- a/chromecast/media/cma/BUILD.gn
+++ b/chromecast/media/cma/BUILD.gn
@@ -6,7 +6,6 @@
   deps = [
     "//chromecast/media/cma/backend",
     "//chromecast/media/cma/base",
-    "//chromecast/media/cma/filters",
     "//chromecast/media/cma/ipc",
     "//chromecast/media/cma/ipc_streamer",
     "//chromecast/media/cma/pipeline",
diff --git a/chromecast/media/cma/backend/BUILD.gn b/chromecast/media/cma/backend/BUILD.gn
index 7507b7d6..57f67ae7 100644
--- a/chromecast/media/cma/backend/BUILD.gn
+++ b/chromecast/media/cma/backend/BUILD.gn
@@ -4,22 +4,8 @@
 
 source_set("backend") {
   sources = [
-    "audio_pipeline_device_default.cc",
-    "audio_pipeline_device_default.h",
-    "media_clock_device_default.cc",
-    "media_clock_device_default.h",
-    "media_component_device_default.cc",
-    "media_component_device_default.h",
     "media_pipeline_backend_default.cc",
     "media_pipeline_backend_default.h",
-    "video_pipeline_device_default.cc",
-    "video_pipeline_device_default.h",
-  ]
-
-  # This target cannot depend on //media. Include these headers directly.
-  sources += [
-    "//media/base/media_export.h",
-    "//media/base/timestamp_constants.h",
   ]
 
   public_deps = [
diff --git a/chromecast/media/cma/backend/audio_pipeline_device_default.cc b/chromecast/media/cma/backend/audio_pipeline_device_default.cc
deleted file mode 100644
index dede9777..0000000
--- a/chromecast/media/cma/backend/audio_pipeline_device_default.cc
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2015 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 "chromecast/media/cma/backend/audio_pipeline_device_default.h"
-
-#include "chromecast/media/cma/backend/media_component_device_default.h"
-
-namespace chromecast {
-namespace media {
-
-AudioPipelineDeviceDefault::AudioPipelineDeviceDefault(
-    const MediaPipelineDeviceParams& params,
-    MediaClockDevice* media_clock_device)
-    : pipeline_(new MediaComponentDeviceDefault(params, media_clock_device)) {
-  thread_checker_.DetachFromThread();
-}
-
-AudioPipelineDeviceDefault::~AudioPipelineDeviceDefault() {
-}
-
-void AudioPipelineDeviceDefault::SetClient(Client* client) {
-  pipeline_->SetClient(client);
-}
-
-MediaComponentDevice::State AudioPipelineDeviceDefault::GetState() const {
-  return pipeline_->GetState();
-}
-
-bool AudioPipelineDeviceDefault::SetState(State new_state) {
-  bool success = pipeline_->SetState(new_state);
-  if (!success)
-    return false;
-
-  if (new_state == kStateIdle) {
-    DCHECK(IsValidConfig(config_));
-  }
-  if (new_state == kStateUninitialized) {
-    config_ = AudioConfig();
-  }
-  return true;
-}
-
-bool AudioPipelineDeviceDefault::SetStartPts(int64_t time_microseconds) {
-  return pipeline_->SetStartPts(time_microseconds);
-}
-
-MediaComponentDevice::FrameStatus AudioPipelineDeviceDefault::PushFrame(
-    DecryptContext* decrypt_context,
-    CastDecoderBuffer* buffer,
-    FrameStatusCB* completion_cb) {
-  return pipeline_->PushFrame(decrypt_context, buffer, completion_cb);
-}
-
-AudioPipelineDeviceDefault::RenderingDelay
-AudioPipelineDeviceDefault::GetRenderingDelay() const {
-  return pipeline_->GetRenderingDelay();
-}
-
-bool AudioPipelineDeviceDefault::SetConfig(const AudioConfig& config) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  if (!IsValidConfig(config))
-    return false;
-  config_ = config;
-  if (config.extra_data_size > 0)
-    config_extra_data_.assign(config.extra_data,
-                              config.extra_data + config.extra_data_size);
-  else
-    config_extra_data_.clear();
-  return true;
-}
-
-void AudioPipelineDeviceDefault::SetStreamVolumeMultiplier(float multiplier) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-}
-
-bool AudioPipelineDeviceDefault::GetStatistics(Statistics* stats) const {
-  return pipeline_->GetStatistics(stats);
-}
-
-}  // namespace media
-}  // namespace chromecast
diff --git a/chromecast/media/cma/backend/audio_pipeline_device_default.h b/chromecast/media/cma/backend/audio_pipeline_device_default.h
deleted file mode 100644
index 814a027..0000000
--- a/chromecast/media/cma/backend/audio_pipeline_device_default.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2015 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 CHROMECAST_MEDIA_CMA_BACKEND_AUDIO_PIPELINE_DEVICE_DEFAULT_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_AUDIO_PIPELINE_DEVICE_DEFAULT_H_
-
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "chromecast/public/media/audio_pipeline_device.h"
-#include "chromecast/public/media/decoder_config.h"
-
-namespace chromecast {
-namespace media {
-
-class MediaClockDevice;
-class MediaComponentDeviceDefault;
-struct MediaPipelineDeviceParams;
-
-class AudioPipelineDeviceDefault : public AudioPipelineDevice {
- public:
-  AudioPipelineDeviceDefault(const MediaPipelineDeviceParams& params,
-                             MediaClockDevice* media_clock_device);
-  ~AudioPipelineDeviceDefault() override;
-
-  // AudioPipelineDevice implementation.
-  void SetClient(Client* client) override;
-  State GetState() const override;
-  bool SetState(State new_state) override;
-  bool SetStartPts(int64_t time_microseconds) override;
-  FrameStatus PushFrame(DecryptContext* decrypt_context,
-                        CastDecoderBuffer* buffer,
-                        FrameStatusCB* completion_cb) override;
-  RenderingDelay GetRenderingDelay() const override;
-  bool SetConfig(const AudioConfig& config) override;
-  void SetStreamVolumeMultiplier(float multiplier) override;
-  bool GetStatistics(Statistics* stats) const override;
-
- private:
-  scoped_ptr<MediaComponentDeviceDefault> pipeline_;
-
-  AudioConfig config_;
-  std::vector<uint8_t> config_extra_data_;
-
-  base::ThreadChecker thread_checker_;
-  DISALLOW_COPY_AND_ASSIGN(AudioPipelineDeviceDefault);
-};
-
-}  // namespace media
-}  // namespace chromecast
-
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_AUDIO_PIPELINE_DEVICE_DEFAULT_H_
diff --git a/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc b/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc
index 84004a8..beca1ab 100644
--- a/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc
+++ b/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc
@@ -20,18 +20,15 @@
 #include "base/threading/thread.h"
 #include "base/time/time.h"
 #include "chromecast/base/task_runner_impl.h"
+#include "chromecast/media/cma/base/cast_decoder_buffer_impl.h"
 #include "chromecast/media/cma/base/decoder_buffer_adapter.h"
 #include "chromecast/media/cma/base/decoder_config_adapter.h"
 #include "chromecast/media/cma/test/frame_segmenter_for_test.h"
-#include "chromecast/media/cma/test/media_component_device_feeder_for_test.h"
 #include "chromecast/public/cast_media_shlib.h"
-#include "chromecast/public/media/audio_pipeline_device.h"
 #include "chromecast/public/media/cast_decoder_buffer.h"
 #include "chromecast/public/media/decoder_config.h"
-#include "chromecast/public/media/media_clock_device.h"
 #include "chromecast/public/media/media_pipeline_backend.h"
 #include "chromecast/public/media/media_pipeline_device_params.h"
-#include "chromecast/public/media/video_pipeline_device.h"
 #include "media/base/audio_decoder_config.h"
 #include "media/base/decoder_buffer.h"
 #include "media/base/video_decoder_config.h"
@@ -42,9 +39,6 @@
 
 namespace {
 
-typedef ScopedVector<MediaComponentDeviceFeederForTest>::iterator
-    ComponentDeviceIterator;
-
 const base::TimeDelta kMonitorLoopDelay = base::TimeDelta::FromMilliseconds(20);
 
 base::FilePath GetTestDataFilePath(const std::string& name) {
@@ -59,7 +53,8 @@
 
 }  // namespace
 
-class AudioVideoPipelineDeviceTest : public testing::Test {
+class AudioVideoPipelineDeviceTest : public testing::Test,
+                                     public MediaPipelineBackend::Delegate {
  public:
   struct PauseInfo {
     PauseInfo() {}
@@ -96,25 +91,31 @@
 
   void Start();
 
+  // MediaPipelineBackend::Delegate implementation:
+  void OnVideoResolutionChanged(MediaPipelineBackend::VideoDecoder* decoder,
+                                const Size& size) override {}
+  void OnPushBufferComplete(MediaPipelineBackend::Decoder* decoder,
+                            MediaPipelineBackend::BufferStatus status) override;
+  void OnEndOfStream(MediaPipelineBackend::Decoder* decoder) override;
+  void OnDecoderError(MediaPipelineBackend::Decoder* decoder) override;
+
  private:
   void Initialize();
 
   void LoadAudioStream(const std::string& filename);
   void LoadVideoStream(const std::string& filename, bool raw_h264);
 
+  void FeedAudioBuffer();
+  void FeedVideoBuffer();
+
   void MonitorLoop();
 
   void OnPauseCompleted();
 
-  void OnEos(MediaComponentDeviceFeederForTest* device_feeder);
-
   scoped_ptr<TaskRunnerImpl> task_runner_;
   scoped_ptr<MediaPipelineBackend> backend_;
-  MediaClockDevice* media_clock_device_;
-
-  // Devices to feed
-  ScopedVector<MediaComponentDeviceFeederForTest>
-      component_device_feeders_;
+  CastDecoderBufferImpl backend_audio_buffer_;
+  CastDecoderBufferImpl backend_video_buffer_;
 
   // Current media time.
   base::TimeDelta pause_time_;
@@ -123,11 +124,25 @@
   std::vector<PauseInfo> pause_pattern_;
   int pause_pattern_idx_;
 
+  BufferList audio_buffers_;
+  BufferList video_buffers_;
+
+  MediaPipelineBackend::AudioDecoder* audio_decoder_;
+  MediaPipelineBackend::VideoDecoder* video_decoder_;
+  bool audio_feeding_completed_;
+  bool video_feeding_completed_;
+
   DISALLOW_COPY_AND_ASSIGN(AudioVideoPipelineDeviceTest);
 };
 
 AudioVideoPipelineDeviceTest::AudioVideoPipelineDeviceTest()
-    : pause_pattern_() {
+    : backend_audio_buffer_(nullptr),
+      backend_video_buffer_(nullptr),
+      pause_pattern_(),
+      audio_decoder_(nullptr),
+      video_decoder_(nullptr),
+      audio_feeding_completed_(true),
+      video_feeding_completed_(true) {
 }
 
 AudioVideoPipelineDeviceTest::~AudioVideoPipelineDeviceTest() {
@@ -147,6 +162,8 @@
     const std::string& filename) {
   Initialize();
   LoadAudioStream(filename);
+  bool success = backend_->Initialize(this);
+  ASSERT_TRUE(success);
 }
 
 void AudioVideoPipelineDeviceTest::ConfigureForVideoOnly(
@@ -154,6 +171,8 @@
     bool raw_h264) {
   Initialize();
   LoadVideoStream(filename, raw_h264);
+  bool success = backend_->Initialize(this);
+  ASSERT_TRUE(success);
 }
 
 void AudioVideoPipelineDeviceTest::ConfigureForFile(
@@ -161,38 +180,32 @@
   Initialize();
   LoadVideoStream(filename, false /* raw_h264 */);
   LoadAudioStream(filename);
+  bool success = backend_->Initialize(this);
+  ASSERT_TRUE(success);
 }
 
 void AudioVideoPipelineDeviceTest::LoadAudioStream(
     const std::string& filename) {
   base::FilePath file_path = GetTestDataFilePath(filename);
   DemuxResult demux_result = FFmpegDemuxForTest(file_path, true /* audio */);
-  BufferList frames = demux_result.frames;
 
-  AudioPipelineDevice* audio_pipeline_device = backend_->GetAudio();
+  audio_buffers_ = demux_result.frames;
+  audio_decoder_ = backend_->CreateAudioDecoder();
+  audio_feeding_completed_ = false;
 
-  bool success = audio_pipeline_device->SetConfig(
-      DecoderConfigAdapter::ToCastAudioConfig(kPrimary,
-                                              demux_result.audio_config));
+  bool success =
+      audio_decoder_->SetConfig(DecoderConfigAdapter::ToCastAudioConfig(
+          kPrimary, demux_result.audio_config));
   ASSERT_TRUE(success);
 
-  VLOG(2) << "Got " << frames.size() << " audio input frames";
+  VLOG(2) << "Got " << audio_buffers_.size() << " audio input frames";
 
-  frames.push_back(
-      scoped_refptr<DecoderBufferBase>(
-          new DecoderBufferAdapter(::media::DecoderBuffer::CreateEOSBuffer())));
-
-  MediaComponentDeviceFeederForTest* device_feeder =
-      new MediaComponentDeviceFeederForTest(audio_pipeline_device, frames);
-  device_feeder->Initialize(base::Bind(&AudioVideoPipelineDeviceTest::OnEos,
-                                       base::Unretained(this),
-                                       device_feeder));
-  component_device_feeders_.push_back(device_feeder);
+  audio_buffers_.push_back(scoped_refptr<DecoderBufferBase>(
+      new DecoderBufferAdapter(::media::DecoderBuffer::CreateEOSBuffer())));
 }
 
 void AudioVideoPipelineDeviceTest::LoadVideoStream(const std::string& filename,
                                                    bool raw_h264) {
-  BufferList frames;
   VideoConfig video_config;
 
   if (raw_h264) {
@@ -200,7 +213,8 @@
     base::MemoryMappedFile video_stream;
     ASSERT_TRUE(video_stream.Initialize(file_path))
         << "Couldn't open stream file: " << file_path.MaybeAsASCII();
-    frames = H264SegmenterForTest(video_stream.data(), video_stream.length());
+    video_buffers_ =
+        H264SegmenterForTest(video_stream.data(), video_stream.length());
 
     // TODO(erickung): Either pull data from stream or make caller specify value
     video_config.codec = kCodecH264;
@@ -211,59 +225,161 @@
     base::FilePath file_path = GetTestDataFilePath(filename);
     DemuxResult demux_result = FFmpegDemuxForTest(file_path,
                                                   /*audio*/ false);
-    frames = demux_result.frames;
+    video_buffers_ = demux_result.frames;
     video_config = DecoderConfigAdapter::ToCastVideoConfig(
         kPrimary, demux_result.video_config);
   }
 
-  VideoPipelineDevice* video_pipeline_device = backend_->GetVideo();
-
-  // Set configuration.
-  bool success = video_pipeline_device->SetConfig(video_config);
+  video_decoder_ = backend_->CreateVideoDecoder();
+  video_feeding_completed_ = false;
+  bool success = video_decoder_->SetConfig(video_config);
   ASSERT_TRUE(success);
 
-  VLOG(2) << "Got " << frames.size() << " video input frames";
+  VLOG(2) << "Got " << video_buffers_.size() << " video input frames";
 
-  frames.push_back(
-      scoped_refptr<DecoderBufferBase>(new DecoderBufferAdapter(
-          ::media::DecoderBuffer::CreateEOSBuffer())));
+  video_buffers_.push_back(scoped_refptr<DecoderBufferBase>(
+      new DecoderBufferAdapter(::media::DecoderBuffer::CreateEOSBuffer())));
+}
 
-  MediaComponentDeviceFeederForTest* device_feeder =
-      new MediaComponentDeviceFeederForTest(video_pipeline_device, frames);
-  device_feeder->Initialize(base::Bind(&AudioVideoPipelineDeviceTest::OnEos,
-                                       base::Unretained(this),
-                                       device_feeder));
-  component_device_feeders_.push_back(device_feeder);
+void AudioVideoPipelineDeviceTest::FeedAudioBuffer() {
+  // Possibly feed one frame
+  DCHECK(!audio_buffers_.empty());
+  if (audio_feeding_completed_)
+    return;
+
+  scoped_refptr<DecoderBufferBase> buffer = audio_buffers_.front();
+  backend_audio_buffer_.set_buffer(buffer);
+
+  MediaPipelineBackend::BufferStatus status =
+      audio_decoder_->PushBuffer(nullptr,  // decrypt_context
+                                 &backend_audio_buffer_);
+  EXPECT_NE(status, MediaPipelineBackend::kBufferFailed);
+  audio_buffers_.pop_front();
+
+  // Feeding is done, just wait for the end of stream callback.
+  if (buffer->end_of_stream() || audio_buffers_.empty()) {
+    if (audio_buffers_.empty() && !buffer->end_of_stream()) {
+      LOG(WARNING) << "Stream emptied without feeding EOS frame";
+    }
+
+    audio_feeding_completed_ = true;
+    return;
+  }
+
+  if (status == MediaPipelineBackend::kBufferPending)
+    return;
+
+  OnPushBufferComplete(audio_decoder_, MediaPipelineBackend::kBufferSuccess);
+}
+
+void AudioVideoPipelineDeviceTest::FeedVideoBuffer() {
+  // Possibly feed one frame
+  DCHECK(!video_buffers_.empty());
+  if (video_feeding_completed_)
+    return;
+
+  scoped_refptr<DecoderBufferBase> buffer = video_buffers_.front();
+  backend_video_buffer_.set_buffer(buffer);
+
+  MediaPipelineBackend::BufferStatus status =
+      video_decoder_->PushBuffer(nullptr,  // decrypt_context
+                                 &backend_video_buffer_);
+  EXPECT_NE(status, MediaPipelineBackend::kBufferFailed);
+  video_buffers_.pop_front();
+
+  // Feeding is done, just wait for the end of stream callback.
+  if (buffer->end_of_stream() || video_buffers_.empty()) {
+    if (video_buffers_.empty() && !buffer->end_of_stream()) {
+      LOG(WARNING) << "Stream emptied without feeding EOS frame";
+    }
+
+    video_feeding_completed_ = true;
+    return;
+  }
+
+  if (status == MediaPipelineBackend::kBufferPending)
+    return;
+
+  OnPushBufferComplete(video_decoder_, MediaPipelineBackend::kBufferSuccess);
 }
 
 void AudioVideoPipelineDeviceTest::Start() {
   pause_time_ = base::TimeDelta();
   pause_pattern_idx_ = 0;
 
-  for (size_t i = 0; i < component_device_feeders_.size(); i++) {
+  if (audio_decoder_) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(&MediaComponentDeviceFeederForTest::Feed,
-                              base::Unretained(component_device_feeders_[i])));
+        FROM_HERE,
+        base::Bind(&AudioVideoPipelineDeviceTest::FeedAudioBuffer,
+                   base::Unretained(this)));
+  }
+  if (video_decoder_) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::Bind(&AudioVideoPipelineDeviceTest::FeedVideoBuffer,
+                   base::Unretained(this)));
   }
 
-  media_clock_device_->SetState(MediaClockDevice::kStateRunning);
+  backend_->Start(0);
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&AudioVideoPipelineDeviceTest::MonitorLoop,
                             base::Unretained(this)));
 }
 
+void AudioVideoPipelineDeviceTest::OnEndOfStream(
+    MediaPipelineBackend::Decoder* decoder) {
+  bool success = backend_->Stop();
+  ASSERT_TRUE(success);
+
+  if (decoder == audio_decoder_)
+    audio_decoder_ = nullptr;
+  else if (decoder == video_decoder_)
+    video_decoder_ = nullptr;
+
+  if (!audio_decoder_ && !video_decoder_)
+    base::MessageLoop::current()->QuitWhenIdle();
+}
+
+void AudioVideoPipelineDeviceTest::OnDecoderError(
+    MediaPipelineBackend::Decoder* decoder) {
+  ASSERT_TRUE(false);
+}
+
+void AudioVideoPipelineDeviceTest::OnPushBufferComplete(
+    MediaPipelineBackend::Decoder* decoder,
+    MediaPipelineBackend::BufferStatus status) {
+  EXPECT_NE(status, MediaPipelineBackend::kBufferFailed);
+
+  if (decoder == audio_decoder_) {
+    if (audio_feeding_completed_)
+      return;
+
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::Bind(&AudioVideoPipelineDeviceTest::FeedAudioBuffer,
+                   base::Unretained(this)));
+  } else if (decoder == video_decoder_) {
+    if (video_feeding_completed_)
+      return;
+
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::Bind(&AudioVideoPipelineDeviceTest::FeedVideoBuffer,
+                   base::Unretained(this)));
+  }
+}
+
 void AudioVideoPipelineDeviceTest::MonitorLoop() {
-  base::TimeDelta media_time = base::TimeDelta::FromMicroseconds(
-      media_clock_device_->GetTimeMicroseconds());
+  base::TimeDelta media_time =
+      base::TimeDelta::FromMicroseconds(backend_->GetCurrentPts());
 
   if (!pause_pattern_.empty() &&
       pause_pattern_[pause_pattern_idx_].delay >= base::TimeDelta() &&
       media_time >= pause_time_ + pause_pattern_[pause_pattern_idx_].delay) {
     // Do Pause
-    media_clock_device_->SetRate(0.0);
-    pause_time_ = base::TimeDelta::FromMicroseconds(
-        media_clock_device_->GetTimeMicroseconds());
+    backend_->Pause();
+    pause_time_ = base::TimeDelta::FromMicroseconds(backend_->GetCurrentPts());
 
     VLOG(2) << "Pausing at " << pause_time_.InMilliseconds() << "ms for " <<
         pause_pattern_[pause_pattern_idx_].length.InMilliseconds() << "ms";
@@ -285,8 +401,8 @@
 
 void AudioVideoPipelineDeviceTest::OnPauseCompleted() {
   // Make sure the media time didn't move during that time.
-  base::TimeDelta media_time = base::TimeDelta::FromMicroseconds(
-      media_clock_device_->GetTimeMicroseconds());
+  base::TimeDelta media_time =
+      base::TimeDelta::FromMicroseconds(backend_->GetCurrentPts());
 
   // TODO(damienv):
   // Should be:
@@ -303,41 +419,16 @@
   VLOG(2) << "Pause complete, restarting media clock";
 
   // Resume playback and frame feeding.
-  media_clock_device_->SetRate(1.0);
+  backend_->Resume();
 
   MonitorLoop();
 }
 
-void AudioVideoPipelineDeviceTest::OnEos(
-    MediaComponentDeviceFeederForTest* device_feeder) {
-  for (ComponentDeviceIterator it = component_device_feeders_.begin();
-       it != component_device_feeders_.end();
-       ++it) {
-    if (*it == device_feeder) {
-      component_device_feeders_.erase(it);
-      break;
-    }
-  }
-
-  // Check if all streams finished
-  if (component_device_feeders_.empty())
-    base::MessageLoop::current()->QuitWhenIdle();
-}
-
 void AudioVideoPipelineDeviceTest::Initialize() {
   // Create the media device.
   task_runner_.reset(new TaskRunnerImpl());
   MediaPipelineDeviceParams params(task_runner_.get());
   backend_.reset(CastMediaShlib::CreateMediaPipelineBackend(params));
-  media_clock_device_ = backend_->GetClock();
-
-  // Clock initialization and configuration.
-  bool success =
-      media_clock_device_->SetState(MediaClockDevice::kStateIdle);
-  ASSERT_TRUE(success);
-  success = media_clock_device_->ResetTimeline(0);
-  ASSERT_TRUE(success);
-  media_clock_device_->SetRate(1.0);
 }
 
 TEST_F(AudioVideoPipelineDeviceTest, Mp3Playback) {
diff --git a/chromecast/media/cma/backend/media_clock_device_default.cc b/chromecast/media/cma/backend/media_clock_device_default.cc
deleted file mode 100644
index 3c7893d..0000000
--- a/chromecast/media/cma/backend/media_clock_device_default.cc
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright 2015 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 "chromecast/media/cma/backend/media_clock_device_default.h"
-
-#include "media/base/timestamp_constants.h"
-
-namespace chromecast {
-namespace media {
-namespace {
-
-// Return true if transition from |state1| to |state2| is a valid state
-// transition.
-inline static bool IsValidStateTransition(MediaClockDevice::State state1,
-                                          MediaClockDevice::State state2) {
-  if (state2 == state1)
-    return true;
-
-  // All states can transition to |kStateError|.
-  if (state2 == MediaClockDevice::kStateError)
-    return true;
-
-  // All the other valid FSM transitions.
-  switch (state1) {
-    case MediaClockDevice::kStateUninitialized:
-      return state2 == MediaClockDevice::kStateIdle;
-    case MediaClockDevice::kStateIdle:
-      return state2 == MediaClockDevice::kStateRunning ||
-             state2 == MediaClockDevice::kStateUninitialized;
-    case MediaClockDevice::kStateRunning:
-      return state2 == MediaClockDevice::kStateIdle;
-    case MediaClockDevice::kStateError:
-      return state2 == MediaClockDevice::kStateUninitialized;
-    default:
-      return false;
-  }
-}
-
-}  // namespace
-
-MediaClockDeviceDefault::MediaClockDeviceDefault()
-    : state_(kStateUninitialized),
-      media_time_(::media::kNoTimestamp()),
-      rate_(0.0f) {
-  thread_checker_.DetachFromThread();
-}
-
-MediaClockDeviceDefault::~MediaClockDeviceDefault() {
-}
-
-MediaClockDevice::State MediaClockDeviceDefault::GetState() const {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  return state_;
-}
-
-bool MediaClockDeviceDefault::SetState(State new_state) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(IsValidStateTransition(state_, new_state));
-
-  if (new_state == state_)
-    return true;
-
-  state_ = new_state;
-
-  if (state_ == kStateRunning) {
-    stc_ = base::TimeTicks::Now();
-    DCHECK(media_time_ != ::media::kNoTimestamp());
-    return true;
-  }
-
-  if (state_ == kStateIdle) {
-    media_time_ = ::media::kNoTimestamp();
-    return true;
-  }
-
-  return true;
-}
-
-bool MediaClockDeviceDefault::ResetTimeline(int64_t time_microseconds) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK_EQ(state_, kStateIdle);
-  media_time_ = base::TimeDelta::FromMicroseconds(time_microseconds);
-  return true;
-}
-
-bool MediaClockDeviceDefault::SetRate(float rate) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  if (state_ == kStateRunning) {
-    base::TimeTicks now = base::TimeTicks::Now();
-    media_time_ = media_time_ + (now - stc_) * rate_;
-    stc_ = now;
-  }
-
-  rate_ = rate;
-  return true;
-}
-
-int64_t MediaClockDeviceDefault::GetTimeMicroseconds() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  if (state_ != kStateRunning)
-    return media_time_.InMicroseconds();
-
-  if (media_time_ == ::media::kNoTimestamp())
-    return media_time_.InMicroseconds();
-
-  base::TimeTicks now = base::TimeTicks::Now();
-  base::TimeDelta interpolated_media_time =
-      media_time_ + (now - stc_) * rate_;
-  return interpolated_media_time.InMicroseconds();
-}
-
-}  // namespace media
-}  // namespace chromecast
diff --git a/chromecast/media/cma/backend/media_clock_device_default.h b/chromecast/media/cma/backend/media_clock_device_default.h
deleted file mode 100644
index e8953542..0000000
--- a/chromecast/media/cma/backend/media_clock_device_default.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2015 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 CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_CLOCK_DEVICE_DEFAULT_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_CLOCK_DEVICE_DEFAULT_H_
-
-#include "base/macros.h"
-#include "base/threading/thread_checker.h"
-#include "base/time/time.h"
-#include "chromecast/public/media/media_clock_device.h"
-
-namespace chromecast {
-namespace media {
-
-class MediaClockDeviceDefault : public MediaClockDevice {
- public:
-  MediaClockDeviceDefault();
-  ~MediaClockDeviceDefault() override;
-
-  // MediaClockDevice implementation.
-  State GetState() const override;
-  bool SetState(State new_state) override;
-  bool ResetTimeline(int64_t time_microseconds) override;
-  bool SetRate(float rate) override;
-  int64_t GetTimeMicroseconds() override;
-
- private:
-  State state_;
-
-  // Media time sampled at STC time |stc_|.
-  base::TimeDelta media_time_;
-  base::TimeTicks stc_;
-
-  float rate_;
-
-  base::ThreadChecker thread_checker_;
-
-  DISALLOW_COPY_AND_ASSIGN(MediaClockDeviceDefault);
-};
-
-}  // namespace media
-}  // namespace chromecast
-
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_CLOCK_DEVICE_DEFAULT_H_
diff --git a/chromecast/media/cma/backend/media_component_device_default.cc b/chromecast/media/cma/backend/media_component_device_default.cc
deleted file mode 100644
index bc2a5678..0000000
--- a/chromecast/media/cma/backend/media_component_device_default.cc
+++ /dev/null
@@ -1,241 +0,0 @@
-// Copyright 2015 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 "chromecast/media/cma/backend/media_component_device_default.h"
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/location.h"
-#include "base/thread_task_runner_handle.h"
-#include "chromecast/public/media/cast_decoder_buffer.h"
-#include "chromecast/public/media/decrypt_context.h"
-#include "chromecast/public/media/media_pipeline_device_params.h"
-#include "chromecast/public/task_runner.h"
-#include "media/base/timestamp_constants.h"
-
-namespace chromecast {
-namespace media {
-
-namespace {
-
-// Maximum number of frames that can be buffered.
-const size_t kMaxFrameCount = 20;
-
-// Wraps base::Closure in the chromecast/public TaskRunner interface.
-class ClosureTask : public TaskRunner::Task {
- public:
-  ClosureTask(const base::Closure& cb) : cb_(cb) {}
-  void Run() override { cb_.Run(); }
-
- private:
-  base::Closure cb_;
-};
-
-// Returns whether or not transitioning from |state1| to |state2| is valid.
-inline static bool IsValidStateTransition(MediaComponentDevice::State state1,
-                                          MediaComponentDevice::State state2) {
-  if (state2 == state1)
-    return true;
-
-  // All states can transition to |kStateError|.
-  if (state2 == MediaComponentDevice::kStateError)
-    return true;
-
-  // All the other valid FSM transitions.
-  switch (state1) {
-    case MediaComponentDevice::kStateUninitialized:
-      return state2 == MediaComponentDevice::kStateIdle;
-    case MediaComponentDevice::kStateIdle:
-      return state2 == MediaComponentDevice::kStateRunning ||
-             state2 == MediaComponentDevice::kStatePaused ||
-             state2 == MediaComponentDevice::kStateUninitialized;
-    case MediaComponentDevice::kStatePaused:
-      return state2 == MediaComponentDevice::kStateIdle ||
-             state2 == MediaComponentDevice::kStateRunning;
-    case MediaComponentDevice::kStateRunning:
-      return state2 == MediaComponentDevice::kStateIdle ||
-             state2 == MediaComponentDevice::kStatePaused;
-    case MediaComponentDevice::kStateError:
-      return state2 == MediaComponentDevice::kStateUninitialized;
-
-    default:
-      return false;
-  }
-}
-
-}  // namespace
-
-MediaComponentDeviceDefault::DefaultDecoderBuffer::DefaultDecoderBuffer()
-  : size(0) {
-}
-
-MediaComponentDeviceDefault::DefaultDecoderBuffer::~DefaultDecoderBuffer() {
-}
-
-MediaComponentDeviceDefault::MediaComponentDeviceDefault(
-    const MediaPipelineDeviceParams& params,
-    MediaClockDevice* media_clock_device)
-    : task_runner_(params.task_runner),
-      media_clock_device_(media_clock_device),
-      state_(kStateUninitialized),
-      rendering_time_(::media::kNoTimestamp()),
-      decoded_frame_count_(0),
-      decoded_byte_count_(0),
-      scheduled_rendering_task_(false),
-      weak_factory_(this) {
-  weak_this_ = weak_factory_.GetWeakPtr();
-  thread_checker_.DetachFromThread();
-}
-
-MediaComponentDeviceDefault::~MediaComponentDeviceDefault() {
-}
-
-void MediaComponentDeviceDefault::SetClient(Client* client) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  client_.reset(client);
-}
-
-MediaComponentDevice::State MediaComponentDeviceDefault::GetState() const {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  return state_;
-}
-
-bool MediaComponentDeviceDefault::SetState(State new_state) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(IsValidStateTransition(state_, new_state));
-  state_ = new_state;
-
-  if (state_ == kStateIdle) {
-    // Back to the idle state: reset a bunch of parameters.
-    is_eos_ = false;
-    rendering_time_ = ::media::kNoTimestamp();
-    decoded_frame_count_ = 0;
-    decoded_byte_count_ = 0;
-    frames_.clear();
-    pending_buffer_ = scoped_ptr<CastDecoderBuffer>();
-    frame_pushed_cb_.reset();
-    return true;
-  }
-
-  if (state_ == kStateRunning) {
-    if (!scheduled_rendering_task_) {
-      scheduled_rendering_task_ = true;
-      task_runner_->PostTask(
-          new ClosureTask(
-              base::Bind(&MediaComponentDeviceDefault::RenderTask, weak_this_)),
-          0);
-    }
-    return true;
-  }
-
-  return true;
-}
-
-bool MediaComponentDeviceDefault::SetStartPts(int64_t time_microseconds) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK_EQ(state_, kStateIdle);
-  rendering_time_ = base::TimeDelta::FromMicroseconds(time_microseconds);
-  return true;
-}
-
-MediaComponentDevice::FrameStatus MediaComponentDeviceDefault::PushFrame(
-    DecryptContext* decrypt_context_in,
-    CastDecoderBuffer* buffer_in,
-    FrameStatusCB* completion_cb_in) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(state_ == kStatePaused || state_ == kStateRunning);
-  DCHECK(!is_eos_);
-  DCHECK(!pending_buffer_.get());
-  DCHECK(buffer_in);
-
-  scoped_ptr<DecryptContext> decrypt_context(decrypt_context_in);
-  scoped_ptr<FrameStatusCB> completion_cb(completion_cb_in);
-
-  scoped_ptr<CastDecoderBuffer> buffer(buffer_in);
-  if (buffer->end_of_stream()) {
-    is_eos_ = true;
-    return kFrameSuccess;
-  }
-
-  if (frames_.size() > kMaxFrameCount) {
-    pending_buffer_ = buffer.Pass();
-    frame_pushed_cb_ = completion_cb.Pass();
-    return kFramePending;
-  }
-
-  DefaultDecoderBuffer fake_buffer;
-  fake_buffer.size = buffer->data_size();
-  fake_buffer.pts = base::TimeDelta::FromMicroseconds(buffer->timestamp());
-  frames_.push_back(fake_buffer);
-  return kFrameSuccess;
-}
-
-MediaComponentDeviceDefault::RenderingDelay
-MediaComponentDeviceDefault::GetRenderingDelay() const {
-  NOTIMPLEMENTED();
-  return RenderingDelay();
-}
-
-void MediaComponentDeviceDefault::RenderTask() {
-  scheduled_rendering_task_ = false;
-
-  if (state_ != kStateRunning)
-    return;
-
-  base::TimeDelta media_time = base::TimeDelta::FromMicroseconds(
-      media_clock_device_->GetTimeMicroseconds());
-  if (media_time == ::media::kNoTimestamp()) {
-    scheduled_rendering_task_ = true;
-    task_runner_->PostTask(
-        new ClosureTask(
-            base::Bind(&MediaComponentDeviceDefault::RenderTask, weak_this_)),
-        50);
-    return;
-  }
-
-  while (!frames_.empty() && frames_.front().pts <= media_time) {
-    rendering_time_ = frames_.front().pts;
-    decoded_frame_count_++;
-    decoded_byte_count_ += frames_.front().size;
-    frames_.pop_front();
-    if (pending_buffer_.get()) {
-      DefaultDecoderBuffer fake_buffer;
-      fake_buffer.size = pending_buffer_->data_size();
-      fake_buffer.pts =
-          base::TimeDelta::FromMicroseconds(pending_buffer_->timestamp());
-      frames_.push_back(fake_buffer);
-      pending_buffer_ = scoped_ptr<CastDecoderBuffer>();
-      frame_pushed_cb_->Run(kFrameSuccess);
-      frame_pushed_cb_.reset();
-    }
-  }
-
-  if (frames_.empty() && is_eos_) {
-    if (client_) {
-      client_->OnEndOfStream();
-    }
-    return;
-  }
-
-  scheduled_rendering_task_ = true;
-  task_runner_->PostTask(
-      new ClosureTask(
-          base::Bind(&MediaComponentDeviceDefault::RenderTask, weak_this_)),
-      50);
-}
-
-bool MediaComponentDeviceDefault::GetStatistics(Statistics* stats) const {
-  if (state_ != kStateRunning)
-    return false;
-
-  // Note: what is returned here is not the number of samples but the number of
-  // frames. The value is different for audio.
-  stats->decoded_bytes = decoded_byte_count_;
-  stats->decoded_samples = decoded_frame_count_;
-  stats->dropped_samples = 0;
-  return true;
-}
-
-}  // namespace media
-}  // namespace chromecast
diff --git a/chromecast/media/cma/backend/media_component_device_default.h b/chromecast/media/cma/backend/media_component_device_default.h
deleted file mode 100644
index d6dc7ea..0000000
--- a/chromecast/media/cma/backend/media_component_device_default.h
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2015 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 CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_COMPONENT_DEVICE_DEFAULT_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_COMPONENT_DEVICE_DEFAULT_H_
-
-#include <list>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
-
-#include "chromecast/public/media/media_clock_device.h"
-#include "chromecast/public/media/media_component_device.h"
-
-namespace chromecast {
-class TaskRunner;
-
-namespace media {
-struct MediaPipelineDeviceParams;
-
-class MediaComponentDeviceDefault : public MediaComponentDevice {
- public:
-  MediaComponentDeviceDefault(const MediaPipelineDeviceParams& params,
-                              MediaClockDevice* media_clock_device);
-  ~MediaComponentDeviceDefault() override;
-
-  // MediaComponentDevice implementation.
-  void SetClient(Client* client) override;
-  State GetState() const override;
-  bool SetState(State new_state) override;
-  bool SetStartPts(int64_t time_microseconds) override;
-  FrameStatus PushFrame(DecryptContext* decrypt_context,
-                        CastDecoderBuffer* buffer,
-                        FrameStatusCB* completion_cb) override;
-  RenderingDelay GetRenderingDelay() const override;
-  bool GetStatistics(Statistics* stats) const override;
-
- private:
-  struct DefaultDecoderBuffer {
-    DefaultDecoderBuffer();
-    ~DefaultDecoderBuffer();
-
-    // Buffer size.
-    size_t size;
-
-    // Presentation timestamp.
-    base::TimeDelta pts;
-  };
-
-  void RenderTask();
-
-  TaskRunner* task_runner_;
-  MediaClockDevice* const media_clock_device_;
-  scoped_ptr<Client> client_;
-
-  State state_;
-
-  // Indicate whether the end of stream has been received.
-  bool is_eos_;
-
-  // Media time of the last rendered audio sample.
-  base::TimeDelta rendering_time_;
-
-  // Frame decoded/rendered since the pipeline left the idle state.
-  uint64 decoded_frame_count_;
-  uint64 decoded_byte_count_;
-
-  // List of frames not rendered yet.
-  std::list<DefaultDecoderBuffer> frames_;
-
-  // Indicate whether there is a scheduled rendering task.
-  bool scheduled_rendering_task_;
-
-  // Pending frame.
-  scoped_ptr<CastDecoderBuffer> pending_buffer_;
-  scoped_ptr<FrameStatusCB> frame_pushed_cb_;
-
-  base::ThreadChecker thread_checker_;
-
-  base::WeakPtr<MediaComponentDeviceDefault> weak_this_;
-  base::WeakPtrFactory<MediaComponentDeviceDefault> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(MediaComponentDeviceDefault);
-};
-
-}  // namespace media
-}  // namespace chromecast
-
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_COMPONENT_DEVICE_DEFAULT_H_
diff --git a/chromecast/media/cma/backend/media_pipeline_backend_default.cc b/chromecast/media/cma/backend/media_pipeline_backend_default.cc
index 498c5be..bb0cc1e7 100644
--- a/chromecast/media/cma/backend/media_pipeline_backend_default.cc
+++ b/chromecast/media/cma/backend/media_pipeline_backend_default.cc
@@ -4,35 +4,145 @@
 
 #include "chromecast/media/cma/backend/media_pipeline_backend_default.h"
 
-#include "chromecast/media/cma/backend/audio_pipeline_device_default.h"
-#include "chromecast/media/cma/backend/media_clock_device_default.h"
-#include "chromecast/media/cma/backend/video_pipeline_device_default.h"
+#include "chromecast/public/media/cast_decoder_buffer.h"
 
 namespace chromecast {
 namespace media {
 
-MediaPipelineBackendDefault::MediaPipelineBackendDefault(
-    const MediaPipelineDeviceParams& params)
-    : params_(params) {}
+class MediaPipelineBackendDefault::AudioDecoderDefault
+    : public MediaPipelineBackend::AudioDecoder {
+ public:
+  AudioDecoderDefault() : delegate_(nullptr) {}
+  ~AudioDecoderDefault() override {}
 
-MediaPipelineBackendDefault::~MediaPipelineBackendDefault() {}
+  void SetDelegate(MediaPipelineBackend::Delegate* delegate) {
+    delegate_ = delegate;
+  }
 
-MediaClockDevice* MediaPipelineBackendDefault::GetClock() {
-  if (!clock_)
-    clock_.reset(new MediaClockDeviceDefault());
-  return clock_.get();
+  // MediaPipelineBackend::AudioDecoder implementation:
+  BufferStatus PushBuffer(DecryptContext* decrypt_context,
+                          CastDecoderBuffer* buffer) override {
+    if (buffer->end_of_stream())
+      delegate_->OnEndOfStream(this);
+    return MediaPipelineBackend::kBufferSuccess;
+  }
+
+  void GetStatistics(Statistics* statistics) override {}
+
+  bool SetConfig(const AudioConfig& config) override { return true; }
+
+  bool SetVolume(float multiplier) override { return true; }
+
+  RenderingDelay GetRenderingDelay() override { return RenderingDelay(); }
+
+ private:
+  MediaPipelineBackend::Delegate* delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(AudioDecoderDefault);
+};
+
+class MediaPipelineBackendDefault::VideoDecoderDefault
+    : public MediaPipelineBackend::VideoDecoder {
+ public:
+  VideoDecoderDefault() : delegate_(nullptr) {}
+  ~VideoDecoderDefault() override {}
+
+  void SetDelegate(MediaPipelineBackend::Delegate* delegate) {
+    delegate_ = delegate;
+  }
+
+  // MediaPipelineBackend::VideoDecoder implementation:
+  BufferStatus PushBuffer(DecryptContext* decrypt_context,
+                          CastDecoderBuffer* buffer) override {
+    if (buffer->end_of_stream())
+      delegate_->OnEndOfStream(this);
+    return MediaPipelineBackend::kBufferSuccess;
+  }
+
+  void GetStatistics(Statistics* statistics) override {}
+
+  bool SetConfig(const VideoConfig& config) override { return true; }
+
+ private:
+  MediaPipelineBackend::Delegate* delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(VideoDecoderDefault);
+};
+
+MediaPipelineBackendDefault::MediaPipelineBackendDefault()
+    : running_(false), rate_(1.0f) {
 }
 
-AudioPipelineDevice* MediaPipelineBackendDefault::GetAudio() {
-  if (!audio_)
-    audio_.reset(new AudioPipelineDeviceDefault(params_, GetClock()));
-  return audio_.get();
+MediaPipelineBackendDefault::~MediaPipelineBackendDefault() {
 }
 
-VideoPipelineDevice* MediaPipelineBackendDefault::GetVideo() {
-  if (!video_)
-    video_.reset(new VideoPipelineDeviceDefault(params_, GetClock()));
-  return video_.get();
+MediaPipelineBackend::AudioDecoder*
+MediaPipelineBackendDefault::CreateAudioDecoder() {
+  DCHECK(!audio_decoder_);
+  audio_decoder_.reset(new AudioDecoderDefault());
+  return audio_decoder_.get();
+}
+
+MediaPipelineBackend::VideoDecoder*
+MediaPipelineBackendDefault::CreateVideoDecoder() {
+  DCHECK(!video_decoder_);
+  video_decoder_.reset(new VideoDecoderDefault());
+  return video_decoder_.get();
+}
+
+bool MediaPipelineBackendDefault::Initialize(Delegate* delegate) {
+  DCHECK(delegate);
+  if (audio_decoder_)
+    audio_decoder_->SetDelegate(delegate);
+  if (video_decoder_)
+    video_decoder_->SetDelegate(delegate);
+  return true;
+}
+
+bool MediaPipelineBackendDefault::Start(int64_t start_pts) {
+  DCHECK(!running_);
+  start_pts_ = base::TimeDelta::FromMicroseconds(start_pts);
+  start_clock_ = base::TimeTicks::Now();
+  running_ = true;
+  return true;
+}
+
+bool MediaPipelineBackendDefault::Stop() {
+  start_pts_ = base::TimeDelta::FromMicroseconds(GetCurrentPts());
+  running_ = false;
+  return true;
+}
+
+bool MediaPipelineBackendDefault::Pause() {
+  DCHECK(running_);
+  start_pts_ = base::TimeDelta::FromMicroseconds(GetCurrentPts());
+  running_ = false;
+  return true;
+}
+
+bool MediaPipelineBackendDefault::Resume() {
+  DCHECK(!running_);
+  running_ = true;
+  start_clock_ = base::TimeTicks::Now();
+  return true;
+}
+
+int64_t MediaPipelineBackendDefault::GetCurrentPts() {
+  if (!running_)
+    return start_pts_.InMicroseconds();
+
+  base::TimeTicks now = base::TimeTicks::Now();
+  base::TimeDelta interpolated_media_time =
+      start_pts_ + (now - start_clock_) * rate_;
+  return interpolated_media_time.InMicroseconds();
+}
+
+bool MediaPipelineBackendDefault::SetPlaybackRate(float rate) {
+  DCHECK_GT(rate, 0.0f);
+  start_pts_ = base::TimeDelta::FromMicroseconds(GetCurrentPts());
+  start_clock_ = base::TimeTicks::Now();
+  rate_ = rate;
+  return true;
 }
 
 }  // namespace media
diff --git a/chromecast/media/cma/backend/media_pipeline_backend_default.h b/chromecast/media/cma/backend/media_pipeline_backend_default.h
index 7a9a602..8dc2b94 100644
--- a/chromecast/media/cma/backend/media_pipeline_backend_default.h
+++ b/chromecast/media/cma/backend/media_pipeline_backend_default.h
@@ -2,12 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_PIPELINE_DEVICE_FACTORY_DEFAULT_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_PIPELINE_DEVICE_FACTORY_DEFAULT_H_
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_PIPELINE_BACKEND_DEFAULT_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_PIPELINE_BACKEND_DEFAULT_H_
 
+#include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
 #include "chromecast/public/media/media_pipeline_backend.h"
-#include "chromecast/public/media/media_pipeline_device_params.h"
 
 namespace chromecast {
 namespace media {
@@ -15,19 +16,31 @@
 // Factory that instantiates default (stub) media pipeline device elements.
 class MediaPipelineBackendDefault : public MediaPipelineBackend {
  public:
-  MediaPipelineBackendDefault(const MediaPipelineDeviceParams& params);
+  MediaPipelineBackendDefault();
   ~MediaPipelineBackendDefault() override;
 
-  // MediaPipelineBackend implementation
-  MediaClockDevice* GetClock() override;
-  AudioPipelineDevice* GetAudio() override;
-  VideoPipelineDevice* GetVideo() override;
+  // MediaPipelineBackend implementation:
+  AudioDecoder* CreateAudioDecoder() override;
+  VideoDecoder* CreateVideoDecoder() override;
+  bool Initialize(Delegate* delegate) override;
+  bool Start(int64_t start_pts) override;
+  bool Stop() override;
+  bool Pause() override;
+  bool Resume() override;
+  int64_t GetCurrentPts() override;
+  bool SetPlaybackRate(float rate) override;
 
  private:
-  MediaPipelineDeviceParams params_;
-  scoped_ptr<MediaClockDevice> clock_;
-  scoped_ptr<AudioPipelineDevice> audio_;
-  scoped_ptr<VideoPipelineDevice> video_;
+  class AudioDecoderDefault;
+  class VideoDecoderDefault;
+
+  base::TimeDelta start_pts_;
+  base::TimeTicks start_clock_;
+  bool running_;
+  float rate_;
+
+  scoped_ptr<AudioDecoderDefault> audio_decoder_;
+  scoped_ptr<VideoDecoderDefault> video_decoder_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaPipelineBackendDefault);
 };
@@ -35,4 +48,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_PIPELINE_DEVICE_FACTORY_DEFAULT_H_
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_PIPELINE_BACKEND_DEFAULT_H_
diff --git a/chromecast/media/cma/backend/video_pipeline_device_default.cc b/chromecast/media/cma/backend/video_pipeline_device_default.cc
deleted file mode 100644
index dd30517..0000000
--- a/chromecast/media/cma/backend/video_pipeline_device_default.cc
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2015 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 "chromecast/media/cma/backend/video_pipeline_device_default.h"
-
-#include "chromecast/media/cma/backend/media_component_device_default.h"
-
-namespace chromecast {
-namespace media {
-
-VideoPipelineDeviceDefault::VideoPipelineDeviceDefault(
-    const MediaPipelineDeviceParams& params,
-    MediaClockDevice* media_clock_device)
-    : pipeline_(new MediaComponentDeviceDefault(params, media_clock_device)) {
-  thread_checker_.DetachFromThread();
-}
-
-VideoPipelineDeviceDefault::~VideoPipelineDeviceDefault() {
-}
-
-void VideoPipelineDeviceDefault::SetClient(Client* client) {
-  pipeline_->SetClient(client);
-}
-
-MediaComponentDevice::State VideoPipelineDeviceDefault::GetState() const {
-  return pipeline_->GetState();
-}
-
-bool VideoPipelineDeviceDefault::SetState(State new_state) {
-  bool success = pipeline_->SetState(new_state);
-  if (!success)
-    return false;
-
-  if (new_state == kStateIdle) {
-    DCHECK(IsValidConfig(config_));
-  }
-  if (new_state == kStateUninitialized) {
-    config_ = VideoConfig();
-  }
-  return true;
-}
-
-bool VideoPipelineDeviceDefault::SetStartPts(int64_t time_microseconds) {
-  return pipeline_->SetStartPts(time_microseconds);
-}
-
-MediaComponentDevice::FrameStatus VideoPipelineDeviceDefault::PushFrame(
-    DecryptContext* decrypt_context,
-    CastDecoderBuffer* buffer,
-    FrameStatusCB* completion_cb) {
-  return pipeline_->PushFrame(decrypt_context, buffer, completion_cb);
-}
-
-VideoPipelineDeviceDefault::RenderingDelay
-VideoPipelineDeviceDefault::GetRenderingDelay() const {
-  return pipeline_->GetRenderingDelay();
-}
-
-void VideoPipelineDeviceDefault::SetVideoClient(VideoClient* client) {
-  delete client;
-}
-
-bool VideoPipelineDeviceDefault::SetConfig(const VideoConfig& config) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  if (!IsValidConfig(config))
-    return false;
-  config_ = config;
-  if (config.extra_data_size > 0)
-    config_extra_data_.assign(config.extra_data,
-                              config.extra_data + config.extra_data_size);
-  else
-    config_extra_data_.clear();
-  return true;
-}
-
-bool VideoPipelineDeviceDefault::GetStatistics(Statistics* stats) const {
-  return pipeline_->GetStatistics(stats);
-}
-
-}  // namespace media
-}  // namespace chromecast
diff --git a/chromecast/media/cma/backend/video_pipeline_device_default.h b/chromecast/media/cma/backend/video_pipeline_device_default.h
deleted file mode 100644
index 8dd61d8a..0000000
--- a/chromecast/media/cma/backend/video_pipeline_device_default.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2015 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 CHROMECAST_MEDIA_CMA_BACKEND_VIDEO_PIPELINE_DEVICE_DEFAULT_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_VIDEO_PIPELINE_DEVICE_DEFAULT_H_
-
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "chromecast/public/media/decoder_config.h"
-#include "chromecast/public/media/video_pipeline_device.h"
-
-namespace chromecast {
-namespace media {
-
-class MediaClockDevice;
-class MediaComponentDeviceDefault;
-struct MediaPipelineDeviceParams;
-
-class VideoPipelineDeviceDefault : public VideoPipelineDevice {
- public:
-  VideoPipelineDeviceDefault(const MediaPipelineDeviceParams& params,
-                             MediaClockDevice* media_clock_device);
-  ~VideoPipelineDeviceDefault() override;
-
-  // VideoPipelineDevice implementation.
-  void SetClient(Client* client) override;
-  State GetState() const override;
-  bool SetState(State new_state) override;
-  bool SetStartPts(int64_t time_microseconds) override;
-  FrameStatus PushFrame(DecryptContext* decrypt_context,
-                        CastDecoderBuffer* buffer,
-                        FrameStatusCB* completion_cb) override;
-  RenderingDelay GetRenderingDelay() const override;
-  void SetVideoClient(VideoClient* client) override;
-  bool SetConfig(const VideoConfig& config) override;
-  bool GetStatistics(Statistics* stats) const override;
-
- private:
-  scoped_ptr<MediaComponentDeviceDefault> pipeline_;
-
-  VideoConfig config_;
-  std::vector<uint8_t> config_extra_data_;
-
-  base::ThreadChecker thread_checker_;
-  DISALLOW_COPY_AND_ASSIGN(VideoPipelineDeviceDefault);
-};
-
-}  // namespace media
-}  // namespace chromecast
-
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_VIDEO_PIPELINE_DEVICE_DEFAULT_H_
diff --git a/chromecast/media/cma/base/cast_decoder_buffer_impl.cc b/chromecast/media/cma/base/cast_decoder_buffer_impl.cc
index e29b620e..e9580482 100644
--- a/chromecast/media/cma/base/cast_decoder_buffer_impl.cc
+++ b/chromecast/media/cma/base/cast_decoder_buffer_impl.cc
@@ -41,5 +41,10 @@
   return buffer_;
 }
 
+void CastDecoderBufferImpl::set_buffer(
+    const scoped_refptr<DecoderBufferBase>& buffer) {
+  buffer_ = buffer;
+}
+
 }  // namespace media
 }  // namespace chromecast
diff --git a/chromecast/media/cma/base/cast_decoder_buffer_impl.h b/chromecast/media/cma/base/cast_decoder_buffer_impl.h
index 444ccf4..adc663c 100644
--- a/chromecast/media/cma/base/cast_decoder_buffer_impl.h
+++ b/chromecast/media/cma/base/cast_decoder_buffer_impl.h
@@ -42,6 +42,7 @@
   bool end_of_stream() const override;
 
   const scoped_refptr<DecoderBufferBase>& buffer() const;
+  void set_buffer(const scoped_refptr<DecoderBufferBase>& buffer);
 
  private:
   scoped_refptr<DecoderBufferBase> buffer_;
diff --git a/chromecast/media/cma/filters/BUILD.gn b/chromecast/media/cma/filters/BUILD.gn
deleted file mode 100644
index 003b5b19f..0000000
--- a/chromecast/media/cma/filters/BUILD.gn
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright 2015 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.
-
-source_set("filters") {
-  sources = [
-    "cma_renderer.cc",
-    "cma_renderer.h",
-    "demuxer_stream_adapter.cc",
-    "demuxer_stream_adapter.h",
-    "hole_frame_factory.cc",
-    "hole_frame_factory.h",
-  ]
-
-  configs += [ "//chromecast:config" ]
-
-  deps = [
-    "//base",
-    "//chromecast/media/cma/base",
-    "//chromecast/media/cma/pipeline",
-    "//gpu/command_buffer/client:gles2_interface",
-    "//gpu/command_buffer/common",
-    "//media",
-    "//ui/gfx/geometry",
-  ]
-}
diff --git a/chromecast/media/cma/pipeline/BUILD.gn b/chromecast/media/cma/pipeline/BUILD.gn
index 8f2054fb..1bfbd84 100644
--- a/chromecast/media/cma/pipeline/BUILD.gn
+++ b/chromecast/media/cma/pipeline/BUILD.gn
@@ -4,8 +4,6 @@
 
 source_set("pipeline") {
   sources = [
-    "audio_pipeline.cc",
-    "audio_pipeline.h",
     "audio_pipeline_impl.cc",
     "audio_pipeline_impl.h",
     "av_pipeline_client.cc",
@@ -14,22 +12,13 @@
     "av_pipeline_impl.h",
     "decrypt_util.cc",
     "decrypt_util.h",
-    "frame_status_cb_impl.cc",
-    "frame_status_cb_impl.h",
     "load_type.h",
-    "media_component_device_client_impl.cc",
-    "media_component_device_client_impl.h",
-    "media_pipeline.h",
     "media_pipeline_client.cc",
     "media_pipeline_client.h",
     "media_pipeline_impl.cc",
     "media_pipeline_impl.h",
-    "video_pipeline.cc",
-    "video_pipeline.h",
     "video_pipeline_client.cc",
     "video_pipeline_client.h",
-    "video_pipeline_device_client_impl.cc",
-    "video_pipeline_device_client_impl.h",
     "video_pipeline_impl.cc",
     "video_pipeline_impl.h",
   ]
diff --git a/chromecast/media/cma/pipeline/audio_pipeline.cc b/chromecast/media/cma/pipeline/audio_pipeline.cc
deleted file mode 100644
index 7d98e09..0000000
--- a/chromecast/media/cma/pipeline/audio_pipeline.cc
+++ /dev/null
@@ -1,17 +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 "chromecast/media/cma/pipeline/audio_pipeline.h"
-
-namespace chromecast {
-namespace media {
-
-AudioPipeline::AudioPipeline() {
-}
-
-AudioPipeline::~AudioPipeline() {
-}
-
-}  // namespace media
-}  // namespace chromecast
diff --git a/chromecast/media/cma/pipeline/audio_pipeline.h b/chromecast/media/cma/pipeline/audio_pipeline.h
deleted file mode 100644
index d7284a10..0000000
--- a/chromecast/media/cma/pipeline/audio_pipeline.h
+++ /dev/null
@@ -1,34 +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 CHROMECAST_MEDIA_CMA_PIPELINE_AUDIO_PIPELINE_H_
-#define CHROMECAST_MEDIA_CMA_PIPELINE_AUDIO_PIPELINE_H_
-
-#include "base/macros.h"
-#include "chromecast/media/cma/pipeline/av_pipeline_client.h"
-
-namespace chromecast {
-namespace media {
-
-class AudioPipeline {
- public:
-  AudioPipeline();
-  virtual ~AudioPipeline();
-
-  // Set the audio client.
-  virtual void SetClient(const AvPipelineClient& client) = 0;
-
-  // Set the stream volume.
-  // - A value of 1.0 is the neutral value.
-  // - |volume|=0.0 mutes the stream.
-  virtual void SetVolume(float volume) = 0;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(AudioPipeline);
-};
-
-}  // namespace media
-}  // namespace chromecast
-
-#endif  // CHROMECAST_MEDIA_CMA_PIPELINE_AUDIO_PIPELINE_H_
diff --git a/chromecast/media/cma/pipeline/audio_pipeline_impl.cc b/chromecast/media/cma/pipeline/audio_pipeline_impl.cc
index c7bdfda..b88f686 100644
--- a/chromecast/media/cma/pipeline/audio_pipeline_impl.cc
+++ b/chromecast/media/cma/pipeline/audio_pipeline_impl.cc
@@ -10,7 +10,6 @@
 #include "chromecast/media/cma/base/coded_frame_provider.h"
 #include "chromecast/media/cma/base/decoder_config_adapter.h"
 #include "chromecast/media/cma/pipeline/av_pipeline_impl.h"
-#include "chromecast/public/media/audio_pipeline_device.h"
 #include "chromecast/public/media/decoder_config.h"
 #include "media/base/audio_decoder_config.h"
 
@@ -21,11 +20,12 @@
 const size_t kMaxAudioFrameSize = 32 * 1024;
 }
 
-AudioPipelineImpl::AudioPipelineImpl(AudioPipelineDevice* audio_device)
-    : audio_device_(audio_device),
-      weak_factory_(this) {
+AudioPipelineImpl::AudioPipelineImpl(
+    MediaPipelineBackend::AudioDecoder* decoder,
+    const AvPipelineClient& client)
+    : decoder_(decoder), audio_client_(client), weak_factory_(this) {
   av_pipeline_impl_.reset(new AvPipelineImpl(
-      audio_device_,
+      decoder_,
       base::Bind(&AudioPipelineImpl::OnUpdateConfig, base::Unretained(this))));
   weak_this_ = weak_factory_.GetWeakPtr();
 }
@@ -39,16 +39,10 @@
       frame_provider.Pass(), kAppAudioBufferSize, kMaxAudioFrameSize);
 }
 
-void AudioPipelineImpl::SetClient(const AvPipelineClient& client) {
-  audio_client_ = client;
-  av_pipeline_impl_->SetClient(client);
-}
-
 bool AudioPipelineImpl::StartPlayingFrom(
     base::TimeDelta time,
     const scoped_refptr<BufferingState>& buffering_state) {
-  CMALOG(kLogControl) << "AudioPipelineImpl::StartPlayingFrom t0="
-                      << time.InMilliseconds();
+  CMALOG(kLogControl) << __FUNCTION__ << " t0=" << time.InMilliseconds();
 
   // Reset the pipeline statistics.
   previous_stats_ = ::media::PipelineStatistics();
@@ -68,7 +62,7 @@
 }
 
 void AudioPipelineImpl::Flush(const ::media::PipelineStatusCB& status_cb) {
-  CMALOG(kLogControl) << "AudioPipelineImpl::Flush";
+  CMALOG(kLogControl) << __FUNCTION__;
   if (av_pipeline_impl_->GetState() == AvPipelineImpl::kError) {
     status_cb.Run(::media::PIPELINE_ERROR_ABORT);
     return;
@@ -81,7 +75,7 @@
 
 void AudioPipelineImpl::OnFlushDone(
     const ::media::PipelineStatusCB& status_cb) {
-  CMALOG(kLogControl) << "AudioPipelineImpl::OnFlushDone";
+  CMALOG(kLogControl) << __FUNCTION__;
   if (av_pipeline_impl_->GetState() == AvPipelineImpl::kError) {
     status_cb.Run(::media::PIPELINE_ERROR_ABORT);
     return;
@@ -91,7 +85,7 @@
 }
 
 void AudioPipelineImpl::Stop() {
-  CMALOG(kLogControl) << "AudioPipelineImpl::Stop";
+  CMALOG(kLogControl) << __FUNCTION__;
   av_pipeline_impl_->Stop();
   av_pipeline_impl_->TransitionToState(AvPipelineImpl::kStopped);
 }
@@ -104,15 +98,14 @@
     const ::media::AudioDecoderConfig& audio_config,
     scoped_ptr<CodedFrameProvider> frame_provider,
     const ::media::PipelineStatusCB& status_cb) {
-  CMALOG(kLogControl) << "AudioPipelineImpl::Initialize "
+  CMALOG(kLogControl) << __FUNCTION__ << " "
                       << audio_config.AsHumanReadableString();
   if (frame_provider)
     SetCodedFrameProvider(frame_provider.Pass());
 
   DCHECK(audio_config.IsValidConfig());
-  if (!audio_device_->SetConfig(
-         DecoderConfigAdapter::ToCastAudioConfig(kPrimary, audio_config)) ||
-      !av_pipeline_impl_->Initialize()) {
+  if (!decoder_->SetConfig(
+          DecoderConfigAdapter::ToCastAudioConfig(kPrimary, audio_config))) {
     status_cb.Run(::media::PIPELINE_ERROR_INITIALIZATION_FAILED);
     return;
   }
@@ -121,7 +114,24 @@
 }
 
 void AudioPipelineImpl::SetVolume(float volume) {
-  audio_device_->SetStreamVolumeMultiplier(volume);
+  decoder_->SetVolume(volume);
+}
+
+void AudioPipelineImpl::OnBufferPushed(
+    MediaPipelineBackend::BufferStatus status) {
+  av_pipeline_impl_->OnBufferPushed(status);
+}
+
+void AudioPipelineImpl::OnEndOfStream() {
+  if (!audio_client_.eos_cb.is_null())
+    audio_client_.eos_cb.Run();
+}
+
+void AudioPipelineImpl::OnError() {
+  if (!audio_client_.playback_error_cb.is_null()) {
+    audio_client_.playback_error_cb.Run(
+        ::media::PIPELINE_ERROR_COULD_NOT_RENDER);
+  }
 }
 
 void AudioPipelineImpl::OnUpdateConfig(
@@ -129,10 +139,10 @@
     const ::media::AudioDecoderConfig& audio_config,
     const ::media::VideoDecoderConfig& video_config) {
   if (audio_config.IsValidConfig()) {
-    CMALOG(kLogControl) << "AudioPipelineImpl::OnUpdateConfig id:" << id << " "
+    CMALOG(kLogControl) << __FUNCTION__ << " id:" << id << " "
                         << audio_config.AsHumanReadableString();
 
-    bool success = audio_device_->SetConfig(
+    bool success = decoder_->SetConfig(
         DecoderConfigAdapter::ToCastAudioConfig(id, audio_config));
     if (!success && !audio_client_.playback_error_cb.is_null())
       audio_client_.playback_error_cb.Run(::media::PIPELINE_ERROR_DECODE);
@@ -143,9 +153,8 @@
   if (audio_client_.statistics_cb.is_null())
     return;
 
-  MediaComponentDevice::Statistics device_stats;
-  if (!audio_device_->GetStatistics(&device_stats))
-    return;
+  MediaPipelineBackend::Decoder::Statistics device_stats;
+  decoder_->GetStatistics(&device_stats);
 
   ::media::PipelineStatistics current_stats;
   current_stats.audio_bytes_decoded = device_stats.decoded_bytes;
diff --git a/chromecast/media/cma/pipeline/audio_pipeline_impl.h b/chromecast/media/cma/pipeline/audio_pipeline_impl.h
index 31cadf9..9afe19b 100644
--- a/chromecast/media/cma/pipeline/audio_pipeline_impl.h
+++ b/chromecast/media/cma/pipeline/audio_pipeline_impl.h
@@ -10,8 +10,8 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread_checker.h"
-#include "chromecast/media/cma/pipeline/audio_pipeline.h"
 #include "chromecast/media/cma/pipeline/av_pipeline_client.h"
+#include "chromecast/public/media/media_pipeline_backend.h"
 #include "chromecast/public/media/stream_id.h"
 
 namespace media {
@@ -21,17 +21,16 @@
 
 namespace chromecast {
 namespace media {
-class AudioPipelineDevice;
 class AvPipelineImpl;
 class BrowserCdmCast;
 class BufferingState;
 class CodedFrameProvider;
 
-class AudioPipelineImpl : public AudioPipeline {
+class AudioPipelineImpl {
  public:
-  // |buffering_controller| can be NULL.
-  explicit AudioPipelineImpl(AudioPipelineDevice* audio_device);
-  ~AudioPipelineImpl() override;
+  AudioPipelineImpl(MediaPipelineBackend::AudioDecoder* decoder,
+                    const AvPipelineClient& client);
+  ~AudioPipelineImpl();
 
   // Input port of the pipeline.
   void SetCodedFrameProvider(scoped_ptr<CodedFrameProvider> frame_provider);
@@ -52,9 +51,11 @@
   // Update the playback statistics for this audio stream.
   void UpdateStatistics();
 
-  // AudioPipeline implementation.
-  void SetClient(const AvPipelineClient& client) override;
-  void SetVolume(float volume) override;
+  void SetVolume(float volume);
+
+  void OnBufferPushed(MediaPipelineBackend::BufferStatus status);
+  void OnEndOfStream();
+  void OnError();
 
  private:
   void OnFlushDone(const ::media::PipelineStatusCB& status_cb);
@@ -62,7 +63,7 @@
                       const ::media::AudioDecoderConfig& audio_config,
                       const ::media::VideoDecoderConfig& video_config);
 
-  AudioPipelineDevice* audio_device_;
+  MediaPipelineBackend::AudioDecoder* decoder_;
 
   scoped_ptr<AvPipelineImpl> av_pipeline_impl_;
   AvPipelineClient audio_client_;
diff --git a/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc b/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc
index 4d716524..040f96e 100644
--- a/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc
+++ b/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc
@@ -23,8 +23,6 @@
 #include "chromecast/media/cma/pipeline/video_pipeline_impl.h"
 #include "chromecast/media/cma/test/frame_generator_for_test.h"
 #include "chromecast/media/cma/test/mock_frame_provider.h"
-#include "chromecast/public/media/audio_pipeline_device.h"
-#include "chromecast/public/media/media_clock_device.h"
 #include "media/base/audio_decoder_config.h"
 #include "media/base/decoder_buffer.h"
 #include "media/base/video_decoder_config.h"
@@ -63,9 +61,9 @@
     : message_loop_(new base::MessageLoop()),
       task_runner_(new TaskRunnerImpl()),
       media_pipeline_(new MediaPipelineImpl()) {
-  MediaPipelineDeviceParams params(task_runner_.get());
   scoped_ptr<MediaPipelineBackend> backend =
-      make_scoped_ptr(new MediaPipelineBackendDefault(params));
+      make_scoped_ptr(new MediaPipelineBackendDefault());
+
   media_pipeline_->Initialize(kLoadTypeURL, backend.Pass());
   media_pipeline_->SetPlaybackRate(1.0);
 }
@@ -77,18 +75,6 @@
     const base::Closure& done_cb,
     ::media::PipelineStatus status,
     bool is_audio) {
-  if (is_audio) {
-    AvPipelineClient client;
-    client.eos_cb =
-        base::Bind(&AudioVideoPipelineImplTest::OnEos, base::Unretained(this));
-    media_pipeline_->GetAudioPipeline()->SetClient(client);
-  } else {
-    VideoPipelineClient client;
-    client.av_pipeline_client.eos_cb =
-        base::Bind(&AudioVideoPipelineImplTest::OnEos, base::Unretained(this));
-    media_pipeline_->GetVideoPipeline()->SetClient(client);
-  }
-
   ::media::AudioDecoderConfig audio_config(
       ::media::kCodecMP3,
       ::media::kSampleFormatS16,
@@ -129,19 +115,32 @@
                  done_cb);
 
   scoped_ptr<CodedFrameProvider> frame_provider_base(frame_provider.release());
-  base::Closure task = is_audio ?
-      base::Bind(&MediaPipeline::InitializeAudio,
-                 base::Unretained(media_pipeline_.get()),
-                 audio_config,
-                 base::Passed(&frame_provider_base),
-                 next_task) :
-      base::Bind(&MediaPipeline::InitializeVideo,
-                 base::Unretained(media_pipeline_.get()),
-                 video_configs,
-                 base::Passed(&frame_provider_base),
-                 next_task);
 
-  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, task);
+  if (is_audio) {
+    AvPipelineClient client;
+    client.eos_cb =
+        base::Bind(&AudioVideoPipelineImplTest::OnEos, base::Unretained(this));
+
+    base::Closure task = base::Bind(&MediaPipelineImpl::InitializeAudio,
+                                    base::Unretained(media_pipeline_.get()),
+                                    audio_config,
+                                    client,
+                                    base::Passed(&frame_provider_base),
+                                    next_task);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, task);
+  } else {
+    VideoPipelineClient client;
+    client.av_pipeline_client.eos_cb =
+        base::Bind(&AudioVideoPipelineImplTest::OnEos, base::Unretained(this));
+
+    base::Closure task = base::Bind(&MediaPipelineImpl::InitializeVideo,
+                                    base::Unretained(media_pipeline_.get()),
+                                    video_configs,
+                                    client,
+                                    base::Passed(&frame_provider_base),
+                                    next_task);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, task);
+  }
 }
 
 void AudioVideoPipelineImplTest::StartPlaying(
@@ -164,7 +163,8 @@
                  done_cb);
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
-      base::Bind(&MediaPipeline::Flush, base::Unretained(media_pipeline_.get()),
+      base::Bind(&MediaPipelineImpl::Flush,
+                 base::Unretained(media_pipeline_.get()),
                  next_task));
 }
 
diff --git a/chromecast/media/cma/pipeline/av_pipeline_impl.cc b/chromecast/media/cma/pipeline/av_pipeline_impl.cc
index ae31b3a..a8eff13 100644
--- a/chromecast/media/cma/pipeline/av_pipeline_impl.cc
+++ b/chromecast/media/cma/pipeline/av_pipeline_impl.cc
@@ -13,16 +13,11 @@
 #include "chromecast/media/cdm/browser_cdm_cast.h"
 #include "chromecast/media/cma/base/buffering_frame_provider.h"
 #include "chromecast/media/cma/base/buffering_state.h"
-#include "chromecast/media/cma/base/cast_decoder_buffer_impl.h"
 #include "chromecast/media/cma/base/cma_logging.h"
 #include "chromecast/media/cma/base/coded_frame_provider.h"
 #include "chromecast/media/cma/base/decoder_buffer_base.h"
 #include "chromecast/media/cma/pipeline/decrypt_util.h"
-#include "chromecast/media/cma/pipeline/frame_status_cb_impl.h"
-#include "chromecast/media/cma/pipeline/media_component_device_client_impl.h"
 #include "chromecast/public/media/cast_decrypt_config.h"
-#include "chromecast/public/media/media_clock_device.h"
-#include "chromecast/public/media/media_component_device.h"
 #include "media/base/audio_decoder_config.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/decrypt_config.h"
@@ -37,29 +32,28 @@
 
 }  // namespace
 
-AvPipelineImpl::AvPipelineImpl(MediaComponentDevice* media_component_device,
+AvPipelineImpl::AvPipelineImpl(MediaPipelineBackend::Decoder* decoder,
                                const UpdateConfigCB& update_config_cb)
     : update_config_cb_(update_config_cb),
-      media_component_device_(media_component_device),
+      decoder_(decoder),
       state_(kUninitialized),
       buffered_time_(::media::kNoTimestamp()),
       playable_buffered_time_(::media::kNoTimestamp()),
       enable_feeding_(false),
       pending_read_(false),
-      pending_push_(false),
+      pushed_buffer_(nullptr),
       enable_time_update_(false),
       pending_time_update_task_(false),
       media_keys_(NULL),
       media_keys_callback_id_(kNoCallbackId),
       weak_factory_(this) {
-  DCHECK(media_component_device);
+  DCHECK(decoder_);
   weak_this_ = weak_factory_.GetWeakPtr();
   thread_checker_.DetachFromThread();
 }
 
 AvPipelineImpl::~AvPipelineImpl() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  media_component_device_->SetClient(nullptr);
 
   if (media_keys_ && media_keys_callback_id_ != kNoCallbackId)
     media_keys_->UnregisterPlayer(media_keys_callback_id_);
@@ -78,30 +72,11 @@
   DCHECK(frame_provider);
 
   // Wrap the incoming frame provider to add some buffering capabilities.
-  frame_provider_.reset(
-      new BufferingFrameProvider(
-          frame_provider.Pass(),
-          max_buffer_size,
-          max_frame_size,
-          base::Bind(&AvPipelineImpl::OnFrameBuffered, weak_this_)));
-}
-
-void AvPipelineImpl::SetClient(const AvPipelineClient& client) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK_EQ(state_, kUninitialized);
-  client_ = client;
-}
-
-bool AvPipelineImpl::Initialize() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK_EQ(state_, kUninitialized);
-
-  media_component_device_->SetClient(new MediaComponentDeviceClientImpl(
-      base::Bind(&AvPipelineImpl::OnEos, weak_this_)));
-  if (!media_component_device_->SetState(MediaComponentDevice::kStateIdle))
-    return false;
-
-  return true;
+  frame_provider_.reset(new BufferingFrameProvider(
+      frame_provider.Pass(),
+      max_buffer_size,
+      max_frame_size,
+      base::Bind(&AvPipelineImpl::OnDataBuffered, weak_this_)));
 }
 
 bool AvPipelineImpl::StartPlayingFrom(
@@ -110,22 +85,12 @@
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK_EQ(state_, kFlushed);
 
-  // Media time where rendering should start
-  // and switch to a state where the audio device accepts incoming buffers.
-  if (!media_component_device_->SetStartPts(time.InMicroseconds()) ||
-      !media_component_device_->SetState(MediaComponentDevice::kStatePaused)) {
-    return false;
-  }
-
   // Buffering related initialization.
   DCHECK(frame_provider_);
   buffering_state_ = buffering_state;
   if (buffering_state_.get())
     buffering_state_->SetMediaTime(time);
 
-  if (!media_component_device_->SetState(MediaComponentDevice::kStateRunning))
-    return false;
-
   // Start feeding the pipeline.
   enable_feeding_ = true;
   base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -137,11 +102,9 @@
 void AvPipelineImpl::Flush(const base::Closure& done_cb) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK_EQ(state_, kFlushing);
-  DCHECK_EQ(
-      media_component_device_->GetState(), MediaComponentDevice::kStateRunning);
+
   // Note: returning to idle state aborts any pending frame push.
-  media_component_device_->SetState(MediaComponentDevice::kStateIdle);
-  pending_push_ = false;
+  pushed_buffer_.set_buffer(nullptr);
 
   // Break the feeding loop.
   enable_feeding_ = false;
@@ -166,18 +129,6 @@
 
   // Stop feeding the pipeline.
   enable_feeding_ = false;
-
-  // Release hardware resources on Stop.
-  if (media_component_device_->GetState() ==
-          MediaComponentDevice::kStatePaused ||
-      media_component_device_->GetState() ==
-          MediaComponentDevice::kStateRunning) {
-    media_component_device_->SetState(MediaComponentDevice::kStateIdle);
-  }
-  if (media_component_device_->GetState() == MediaComponentDevice::kStateIdle) {
-    media_component_device_->SetState(
-        MediaComponentDevice::kStateUninitialized);
-  }
 }
 
 void AvPipelineImpl::SetCdm(BrowserCdmCast* media_keys) {
@@ -193,16 +144,6 @@
       base::Bind(&AvPipelineImpl::OnCdmDestroyed, weak_this_));
 }
 
-void AvPipelineImpl::OnEos() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  CMALOG(kLogControl) << __FUNCTION__;
-  if (state_ != kPlaying)
-    return;
-
-  if (!client_.eos_cb.is_null())
-    client_.eos_cb.Run();
-}
-
 void AvPipelineImpl::FetchBufferIfNeeded() {
   DCHECK(thread_checker_.CalledOnValidThread());
   if (!enable_feeding_)
@@ -245,7 +186,7 @@
     return;
   }
 
-  if (!pending_buffer_.get() || pending_push_)
+  if (!pending_buffer_.get() || pushed_buffer_.buffer())
     return;
 
   // Break the feeding loop when the end of stream is reached.
@@ -289,21 +230,20 @@
       buffering_state_->SetMaxRenderingTime(timestamp);
   }
 
-  MediaComponentDevice::FrameStatus status = media_component_device_->PushFrame(
-      decrypt_context.release(), new CastDecoderBufferImpl(pending_buffer_),
-      new FrameStatusCBImpl(
-          base::Bind(&AvPipelineImpl::OnFramePushed, weak_this_)));
+  DCHECK(!pushed_buffer_.buffer());
+  pushed_buffer_.set_buffer(pending_buffer_);
+  MediaPipelineBackend::BufferStatus status =
+      decoder_->PushBuffer(decrypt_context.release(), &pushed_buffer_);
   pending_buffer_ = scoped_refptr<DecoderBufferBase>();
 
-  pending_push_ = (status == MediaComponentDevice::kFramePending);
-  if (!pending_push_)
-    OnFramePushed(status);
+  if (status != MediaPipelineBackend::kBufferPending)
+    OnBufferPushed(status);
 }
 
-void AvPipelineImpl::OnFramePushed(MediaComponentDevice::FrameStatus status) {
+void AvPipelineImpl::OnBufferPushed(MediaPipelineBackend::BufferStatus status) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  pending_push_ = false;
-  if (status == MediaComponentDevice::kFrameFailed) {
+  pushed_buffer_.set_buffer(nullptr);
+  if (status == MediaPipelineBackend::kBufferFailed) {
     LOG(WARNING) << "AvPipelineImpl: PushFrame failed";
     enable_feeding_ = false;
     state_ = kError;
@@ -329,7 +269,7 @@
   media_keys_ = NULL;
 }
 
-void AvPipelineImpl::OnFrameBuffered(
+void AvPipelineImpl::OnDataBuffered(
     const scoped_refptr<DecoderBufferBase>& buffer,
     bool is_at_max_capacity) {
   DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/chromecast/media/cma/pipeline/av_pipeline_impl.h b/chromecast/media/cma/pipeline/av_pipeline_impl.h
index 2aa9d51c..fe1a8286 100644
--- a/chromecast/media/cma/pipeline/av_pipeline_impl.h
+++ b/chromecast/media/cma/pipeline/av_pipeline_impl.h
@@ -12,8 +12,8 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread_checker.h"
-#include "chromecast/media/cma/pipeline/av_pipeline_client.h"
-#include "chromecast/public/media/media_component_device.h"
+#include "chromecast/media/cma/base/cast_decoder_buffer_impl.h"
+#include "chromecast/public/media/media_pipeline_backend.h"
 #include "chromecast/public/media/stream_id.h"
 
 namespace media {
@@ -28,7 +28,6 @@
 class BufferingState;
 class CodedFrameProvider;
 class DecoderBufferBase;
-class MediaComponentDevice;
 
 class AvPipelineImpl {
  public:
@@ -47,9 +46,8 @@
            const ::media::AudioDecoderConfig&,
            const ::media::VideoDecoderConfig&)> UpdateConfigCB;
 
-  AvPipelineImpl(
-      MediaComponentDevice* media_component_device,
-      const UpdateConfigCB& update_config_cb);
+  AvPipelineImpl(MediaPipelineBackend::Decoder* decoder,
+                 const UpdateConfigCB& update_config_cb);
   ~AvPipelineImpl();
 
   // Setting the frame provider or the client must be done in the
@@ -57,10 +55,6 @@
   void SetCodedFrameProvider(scoped_ptr<CodedFrameProvider> frame_provider,
                              size_t max_buffer_size,
                              size_t max_frame_size);
-  void SetClient(const AvPipelineClient& client);
-
-  // Initialize the pipeline.
-  bool Initialize();
 
   // Setup the pipeline and ensure samples are available for the given media
   // time, then start rendering samples.
@@ -79,14 +73,13 @@
 
   void SetCdm(BrowserCdmCast* media_keys);
 
+  void OnBufferPushed(MediaPipelineBackend::BufferStatus status);
+
  private:
   // Callback invoked when the CDM state has changed in a way that might
   // impact media playback.
   void OnCdmStateChange();
 
-  // Callback invoked when playback has reached the end of stream.
-  void OnEos();
-
   // Feed the pipeline, getting the frames from |frame_provider_|.
   void FetchBufferIfNeeded();
 
@@ -98,28 +91,24 @@
   // Process a pending buffer.
   void ProcessPendingBuffer();
 
-  void OnFramePushed(MediaComponentDevice::FrameStatus status);
-
   // Callbacks:
   // - when BrowserCdm updated its state.
   // - when BrowserCdm has been destroyed.
   void OnCdmStateChanged();
   void OnCdmDestroyed();
 
-  // Callback invoked when a frame has been buffered by |frame_provider_|
+  // Callback invoked when a media buffer has been buffered by |frame_provider_|
   // which is a BufferingFrameProvider.
-  void OnFrameBuffered(const scoped_refptr<DecoderBufferBase>& buffer,
-                       bool is_at_max_capacity);
+  void OnDataBuffered(const scoped_refptr<DecoderBufferBase>& buffer,
+                      bool is_at_max_capacity);
   void UpdatePlayableFrames();
 
   base::ThreadChecker thread_checker_;
 
   UpdateConfigCB update_config_cb_;
 
-  AvPipelineClient client_;
-
   // Backends.
-  MediaComponentDevice* media_component_device_;
+  MediaPipelineBackend::Decoder* decoder_;
 
   // AV pipeline state.
   State state_;
@@ -147,11 +136,11 @@
   // Indicate whether there is a pending buffer read.
   bool pending_read_;
 
-  // Pending buffer.
+  // Pending buffer (not pushed to device yet)
   scoped_refptr<DecoderBufferBase> pending_buffer_;
 
-  // Indicate if there is a frame being pushed to the audio device.
-  bool pending_push_;
+  // Buffer that has been pushed to the device but not processed yet.
+  CastDecoderBufferImpl pushed_buffer_;
 
   // The media time is retrieved at regular intervals.
   // Indicate whether time update is enabled.
diff --git a/chromecast/media/cma/pipeline/frame_status_cb_impl.cc b/chromecast/media/cma/pipeline/frame_status_cb_impl.cc
deleted file mode 100644
index 06769f7..0000000
--- a/chromecast/media/cma/pipeline/frame_status_cb_impl.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2015 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 "chromecast/media/cma/pipeline/frame_status_cb_impl.h"
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/single_thread_task_runner.h"
-#include "base/thread_task_runner_handle.h"
-
-namespace chromecast {
-namespace media {
-
-FrameStatusCBImpl::FrameStatusCBImpl(const CallbackType& cb)
-    : cb_(cb), task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
-
-FrameStatusCBImpl::~FrameStatusCBImpl() {}
-
-void FrameStatusCBImpl::Run(MediaComponentDevice::FrameStatus status) {
-  if (task_runner_->BelongsToCurrentThread()) {
-    if (!cb_.is_null())
-      cb_.Run(status);
-  } else {
-    task_runner_->PostTask(FROM_HERE, base::Bind(cb_, status));
-  }
-}
-
-}  // namespace media
-}  // namespace chromecast
diff --git a/chromecast/media/cma/pipeline/frame_status_cb_impl.h b/chromecast/media/cma/pipeline/frame_status_cb_impl.h
deleted file mode 100644
index 9cd3de7..0000000
--- a/chromecast/media/cma/pipeline/frame_status_cb_impl.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2015 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 CHROMECAST_MEDIA_CMA_PIPELINE_FRAME_STATUS_CB_IMPL_H_
-#define CHROMECAST_MEDIA_CMA_PIPELINE_FRAME_STATUS_CB_IMPL_H_
-
-#include "base/callback.h"
-#include "base/memory/ref_counted.h"
-#include "chromecast/public/media/media_component_device.h"
-
-namespace base {
-class SingleThreadTaskRunner;
-}
-
-namespace chromecast {
-namespace media {
-
-// Helper for implementing MediaComponentDevice::FrameStatusCB with
-// a base::Callback.
-class FrameStatusCBImpl : public MediaComponentDevice::FrameStatusCB {
- public:
-  typedef base::Callback<void(MediaComponentDevice::FrameStatus)> CallbackType;
-
-  FrameStatusCBImpl(const CallbackType& cb);
-  ~FrameStatusCBImpl() override;
-
-  void Run(MediaComponentDevice::FrameStatus status) override;
-
- private:
-  CallbackType cb_;
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-};
-
-}  // namespace media
-}  // namespace chromecast
-
-#endif  // CHROMECAST_MEDIA_CMA_PIPELINE_FRAME_STATUS_CB_IMPL_H_
diff --git a/chromecast/media/cma/pipeline/media_component_device_client_impl.cc b/chromecast/media/cma/pipeline/media_component_device_client_impl.cc
deleted file mode 100644
index e81ec0a..0000000
--- a/chromecast/media/cma/pipeline/media_component_device_client_impl.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2015 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 "chromecast/media/cma/pipeline/media_component_device_client_impl.h"
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/single_thread_task_runner.h"
-#include "base/thread_task_runner_handle.h"
-
-namespace chromecast {
-namespace media {
-
-MediaComponentDeviceClientImpl::MediaComponentDeviceClientImpl(
-    const base::Closure& eos_cb)
-    : eos_cb_(eos_cb), task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
-
-MediaComponentDeviceClientImpl::~MediaComponentDeviceClientImpl() {}
-
-void MediaComponentDeviceClientImpl::OnEndOfStream() {
-  if (task_runner_->BelongsToCurrentThread()) {
-    if (!eos_cb_.is_null())
-      eos_cb_.Run();
-  } else {
-    task_runner_->PostTask(FROM_HERE, eos_cb_);
-  }
-}
-
-}  // namespace media
-}  // namespace chromecast
diff --git a/chromecast/media/cma/pipeline/media_component_device_client_impl.h b/chromecast/media/cma/pipeline/media_component_device_client_impl.h
deleted file mode 100644
index 8f47d30..0000000
--- a/chromecast/media/cma/pipeline/media_component_device_client_impl.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2015 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 CHROMECAST_MEDIA_CMA_PIPELINE_MEDIA_COMPONENT_DEVICE_CLIENT_IMPL_H_
-#define CHROMECAST_MEDIA_CMA_PIPELINE_MEDIA_COMPONENT_DEVICE_CLIENT_IMPL_H_
-
-#include "base/callback.h"
-#include "base/memory/ref_counted.h"
-#include "chromecast/public/media/media_component_device.h"
-#include "chromecast/public/media/video_pipeline_device.h"
-
-namespace base {
-class SingleThreadTaskRunner;
-}
-
-namespace chromecast {
-namespace media {
-
-// Helper for implementing MediaComponentDevice::Client with
-// a base::Callback.
-class MediaComponentDeviceClientImpl : public MediaComponentDevice::Client {
- public:
-  MediaComponentDeviceClientImpl(const base::Closure& eos_cb);
-  ~MediaComponentDeviceClientImpl() override;
-
-  void OnEndOfStream() override;
-
- private:
-  base::Closure eos_cb_;
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-};
-
-}  // namespace media
-}  // namespace chromecast
-
-#endif  // CHROMECAST_MEDIA_CMA_PIPELINE_MEDIA_COMPONENT_DEVICE_CLIENT_IMPL_H_
diff --git a/chromecast/media/cma/pipeline/media_pipeline.h b/chromecast/media/cma/pipeline/media_pipeline.h
deleted file mode 100644
index 625917c..0000000
--- a/chromecast/media/cma/pipeline/media_pipeline.h
+++ /dev/null
@@ -1,71 +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 CHROMECAST_MEDIA_CMA_PIPELINE_MEDIA_PIPELINE_H_
-#define CHROMECAST_MEDIA_CMA_PIPELINE_MEDIA_PIPELINE_H_
-
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/macros.h"
-#include "base/time/time.h"
-#include "media/base/pipeline_status.h"
-
-namespace media {
-class AudioDecoderConfig;
-class BrowserCdm;
-class VideoDecoderConfig;
-}
-
-namespace chromecast {
-namespace media {
-class AudioPipeline;
-class CodedFrameProvider;
-struct MediaPipelineClient;
-class VideoPipeline;
-
-class MediaPipeline {
- public:
-  MediaPipeline() {}
-  virtual ~MediaPipeline() {}
-
-  // Set the media pipeline client.
-  virtual void SetClient(const MediaPipelineClient& client) = 0;
-
-  // Set the CDM to use for decryption.
-  // The CDM is refered by its id.
-  virtual void SetCdm(int cdm_id) = 0;
-
-  // Return the audio/video pipeline owned by the MediaPipeline.
-  virtual AudioPipeline* GetAudioPipeline() const = 0;
-  virtual VideoPipeline* GetVideoPipeline() const = 0;
-
-  // Create an audio/video pipeline.
-  // MediaPipeline owns the resulting audio/video pipeline.
-  // Only one audio and one video pipeline can be created.
-  virtual void InitializeAudio(
-      const ::media::AudioDecoderConfig& config,
-      scoped_ptr<CodedFrameProvider> frame_provider,
-      const ::media::PipelineStatusCB& status_cb) = 0;
-  virtual void InitializeVideo(
-      const std::vector<::media::VideoDecoderConfig>& configs,
-      scoped_ptr<CodedFrameProvider> frame_provider,
-      const ::media::PipelineStatusCB& status_cb) = 0;
-
-  // Control the media pipeline state machine.
-  virtual void StartPlayingFrom(base::TimeDelta time) = 0;
-  virtual void Flush(const ::media::PipelineStatusCB& status_cb) = 0;
-  virtual void Stop() = 0;
-
-  // Set the playback rate.
-  virtual void SetPlaybackRate(double playback_rate) = 0;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(MediaPipeline);
-};
-
-}  // namespace media
-}  // namespace chromecast
-
-#endif  // CHROMECAST_MEDIA_CMA_PIPELINE_MEDIA_PIPELINE_H_
diff --git a/chromecast/media/cma/pipeline/media_pipeline_client.h b/chromecast/media/cma/pipeline/media_pipeline_client.h
index 1918ef17..340a3e5 100644
--- a/chromecast/media/cma/pipeline/media_pipeline_client.h
+++ b/chromecast/media/cma/pipeline/media_pipeline_client.h
@@ -14,8 +14,8 @@
 namespace media {
 
 struct MediaPipelineClient {
-  typedef base::Callback<void(
-      base::TimeDelta, base::TimeDelta, base::TimeTicks)> TimeUpdateCB;
+  typedef base::Callback<
+      void(base::TimeDelta, base::TimeDelta, base::TimeTicks)> TimeUpdateCB;
 
   MediaPipelineClient();
   ~MediaPipelineClient();
diff --git a/chromecast/media/cma/pipeline/media_pipeline_impl.cc b/chromecast/media/cma/pipeline/media_pipeline_impl.cc
index 1b39870..85ead1ee 100644
--- a/chromecast/media/cma/pipeline/media_pipeline_impl.cc
+++ b/chromecast/media/cma/pipeline/media_pipeline_impl.cc
@@ -19,7 +19,6 @@
 #include "chromecast/media/cma/base/coded_frame_provider.h"
 #include "chromecast/media/cma/pipeline/audio_pipeline_impl.h"
 #include "chromecast/media/cma/pipeline/video_pipeline_impl.h"
-#include "chromecast/public/media/media_clock_device.h"
 #include "chromecast/public/media/media_pipeline_backend.h"
 #include "media/base/timestamp_constants.h"
 
@@ -51,9 +50,13 @@
 }  // namespace
 
 MediaPipelineImpl::MediaPipelineImpl()
-    : has_audio_(false),
+    : audio_decoder_(nullptr),
+      video_decoder_(nullptr),
+      backend_initialized_(false),
+      has_audio_(false),
       has_video_(false),
-      target_playback_rate_(0.0),
+      paused_(false),
+      target_playback_rate_(1.0f),
       enable_time_update_(false),
       pending_time_update_task_(false),
       statistics_rolling_counter_(0),
@@ -84,7 +87,6 @@
   CMALOG(kLogControl) << __FUNCTION__;
   DCHECK(thread_checker_.CalledOnValidThread());
   media_pipeline_backend_.reset(media_pipeline_backend.release());
-  clock_device_ = media_pipeline_backend_->GetClock();
   if (!client_.pipeline_backend_created_cb.is_null())
     client_.pipeline_backend_created_cb.Run();
 
@@ -101,12 +103,6 @@
         buffering_config,
         base::Bind(&MediaPipelineImpl::OnBufferingNotification, weak_this_)));
   }
-
-  audio_pipeline_.reset(
-      new AudioPipelineImpl(media_pipeline_backend_->GetAudio()));
-
-  video_pipeline_.reset(
-      new VideoPipelineImpl(media_pipeline_backend_->GetVideo()));
 }
 
 void MediaPipelineImpl::SetClient(const MediaPipelineClient& client) {
@@ -127,6 +123,36 @@
   // One possibility would be a GetCdmByIdCB that's passed in.
 }
 
+void MediaPipelineImpl::OnVideoResolutionChanged(
+    MediaPipelineBackend::VideoDecoder* decoder,
+    const Size& size) {
+  DCHECK(decoder == video_decoder_);
+  video_pipeline_->OnNaturalSizeChanged(size);
+}
+
+void MediaPipelineImpl::OnPushBufferComplete(
+    MediaPipelineBackend::Decoder* decoder,
+    MediaPipelineBackend::BufferStatus status) {
+  if (decoder == audio_decoder_)
+    audio_pipeline_->OnBufferPushed(status);
+  else if (decoder == video_decoder_)
+    video_pipeline_->OnBufferPushed(status);
+}
+
+void MediaPipelineImpl::OnEndOfStream(MediaPipelineBackend::Decoder* decoder) {
+  if (decoder == audio_decoder_)
+    audio_pipeline_->OnEndOfStream();
+  else if (decoder == video_decoder_)
+    video_pipeline_->OnEndOfStream();
+}
+
+void MediaPipelineImpl::OnDecoderError(MediaPipelineBackend::Decoder* decoder) {
+  if (decoder == audio_decoder_)
+    audio_pipeline_->OnError();
+  else if (decoder == video_decoder_)
+    video_pipeline_->OnError();
+}
+
 void MediaPipelineImpl::SetCdm(BrowserCdmCast* cdm) {
   CMALOG(kLogControl) << __FUNCTION__;
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -134,41 +160,41 @@
   video_pipeline_->SetCdm(cdm);
 }
 
-AudioPipeline* MediaPipelineImpl::GetAudioPipeline() const {
-  return audio_pipeline_.get();
-}
-
-VideoPipeline* MediaPipelineImpl::GetVideoPipeline() const {
-  return video_pipeline_.get();
-}
-
 void MediaPipelineImpl::InitializeAudio(
     const ::media::AudioDecoderConfig& config,
+    const AvPipelineClient& client,
     scoped_ptr<CodedFrameProvider> frame_provider,
     const ::media::PipelineStatusCB& status_cb) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!has_audio_);
-  if (clock_device_->GetState() == MediaClockDevice::kStateUninitialized &&
-      !clock_device_->SetState(MediaClockDevice::kStateIdle)) {
-    status_cb.Run(::media::PIPELINE_ERROR_INITIALIZATION_FAILED);
+
+  has_audio_ = true;
+
+  audio_decoder_ = media_pipeline_backend_->CreateAudioDecoder();
+  if (!audio_decoder_) {
+    status_cb.Run(::media::PIPELINE_ERROR_ABORT);
     return;
   }
-  has_audio_ = true;
+  audio_pipeline_.reset(new AudioPipelineImpl(audio_decoder_, client));
   audio_pipeline_->Initialize(config, frame_provider.Pass(), status_cb);
 }
 
 void MediaPipelineImpl::InitializeVideo(
-    const std::vector<::media::VideoDecoderConfig>& configs,
+    const std::vector< ::media::VideoDecoderConfig>& configs,
+    const VideoPipelineClient& client,
     scoped_ptr<CodedFrameProvider> frame_provider,
     const ::media::PipelineStatusCB& status_cb) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!has_video_);
-  if (clock_device_->GetState() == MediaClockDevice::kStateUninitialized &&
-      !clock_device_->SetState(MediaClockDevice::kStateIdle)) {
-    status_cb.Run(::media::PIPELINE_ERROR_INITIALIZATION_FAILED);
+
+  has_video_ = true;
+  video_decoder_ = media_pipeline_backend_->CreateVideoDecoder();
+  if (!video_decoder_) {
+    status_cb.Run(::media::PIPELINE_ERROR_ABORT);
     return;
   }
-  has_video_ = true;
+  video_pipeline_.reset(new VideoPipelineImpl(video_decoder_, client));
+
   video_pipeline_->Initialize(configs, frame_provider.Pass(), status_cb);
 }
 
@@ -177,14 +203,20 @@
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(has_audio_ || has_video_);
   DCHECK(!pending_flush_callbacks_);
+  // When starting, we always enter the "playing" state (not paused).
+  paused_ = false;
 
-  // Reset the start of the timeline.
-  DCHECK_EQ(clock_device_->GetState(), MediaClockDevice::kStateIdle);
-  clock_device_->ResetTimeline(time.InMicroseconds());
+  // Lazy initialise
+  if (!backend_initialized_) {
+    backend_initialized_ = media_pipeline_backend_->Initialize(this);
+    if (!backend_initialized_) {
+      OnError(::media::PIPELINE_ERROR_ABORT);
+      return;
+    }
+  }
 
-  // Start the clock. If the playback rate is 0, then the clock is started
-  // but does not increase.
-  if (!clock_device_->SetState(MediaClockDevice::kStateRunning)) {
+  // Start the backend.
+  if (!media_pipeline_backend_->Start(time.InMicroseconds())) {
     OnError(::media::PIPELINE_ERROR_ABORT);
     return;
   }
@@ -224,16 +256,14 @@
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(has_audio_ || has_video_);
   DCHECK(!pending_flush_callbacks_);
-  DCHECK(clock_device_->GetState() == MediaClockDevice::kStateUninitialized ||
-         clock_device_->GetState() == MediaClockDevice::kStateRunning);
 
   // No need to update media time anymore.
   enable_time_update_ = false;
 
   buffering_controller_->Reset();
 
-  // The clock should return to idle.
-  if (!clock_device_->SetState(MediaClockDevice::kStateIdle)) {
+  // Stop the backend
+  if (!media_pipeline_backend_->Stop()) {
     status_cb.Run(::media::PIPELINE_ERROR_ABORT);
     return;
   }
@@ -269,34 +299,42 @@
   // No need to update media time anymore.
   enable_time_update_ = false;
 
-  // Release hardware resources on Stop.
-  // Note: Stop can be called from any state.
-  if (clock_device_->GetState() == MediaClockDevice::kStateRunning)
-    clock_device_->SetState(MediaClockDevice::kStateIdle);
-  if (clock_device_->GetState() == MediaClockDevice::kStateIdle)
-    clock_device_->SetState(MediaClockDevice::kStateUninitialized);
-
   // Stop both the audio and video pipeline.
   if (has_audio_)
     audio_pipeline_->Stop();
   if (has_video_)
     video_pipeline_->Stop();
+
+  // Release hardware resources on Stop.
+  audio_pipeline_ = nullptr;
+  video_pipeline_ = nullptr;
+  media_pipeline_backend_.reset();
 }
 
 void MediaPipelineImpl::SetPlaybackRate(double rate) {
   CMALOG(kLogControl) << __FUNCTION__ << " rate=" << rate;
   DCHECK(thread_checker_.CalledOnValidThread());
+  if (!buffering_controller_ || !buffering_controller_->IsBuffering()) {
+    if (paused_ && rate != 0.0f) {
+      if (rate != target_playback_rate_)
+        media_pipeline_backend_->SetPlaybackRate(rate);
+      paused_ = false;
+      media_pipeline_backend_->Resume();
+    } else if (!paused_ && rate == 0.0f) {
+      paused_ = true;
+      media_pipeline_backend_->Pause();
+    } else {
+      media_pipeline_backend_->SetPlaybackRate(rate);
+    }
+  }
   target_playback_rate_ = rate;
-  if (!buffering_controller_ || !buffering_controller_->IsBuffering())
-    media_pipeline_backend_->GetClock()->SetRate(rate);
 }
 
-AudioPipelineImpl* MediaPipelineImpl::GetAudioPipelineImpl() const {
-  return audio_pipeline_.get();
-}
-
-VideoPipelineImpl* MediaPipelineImpl::GetVideoPipelineImpl() const {
-  return video_pipeline_.get();
+void MediaPipelineImpl::SetVolume(float volume) {
+  CMALOG(kLogControl) << __FUNCTION__ << " vol=" << volume;
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(audio_pipeline_);
+  audio_pipeline_->SetVolume(volume);
 }
 
 void MediaPipelineImpl::StateTransition(
@@ -317,16 +355,15 @@
     client_.buffering_state_cb.Run(buffering_state);
   }
 
-  if (media_pipeline_backend_->GetClock()->GetState() ==
-      MediaClockDevice::kStateUninitialized) {
-    return;
-  }
-
   if (is_buffering) {
     // Do not consume data in a rebuffering phase.
-    media_pipeline_backend_->GetClock()->SetRate(0.0);
-  } else {
-    media_pipeline_backend_->GetClock()->SetRate(target_playback_rate_);
+    if (!paused_) {
+      paused_ = true;
+      media_pipeline_backend_->Pause();
+    }
+  } else if (paused_) {
+    paused_ = false;
+    media_pipeline_backend_->Resume();
   }
 }
 
@@ -336,14 +373,16 @@
     return;
 
   if (statistics_rolling_counter_ == 0) {
-    audio_pipeline_->UpdateStatistics();
-    video_pipeline_->UpdateStatistics();
+    if (audio_pipeline_)
+      audio_pipeline_->UpdateStatistics();
+    if (video_pipeline_)
+      video_pipeline_->UpdateStatistics();
   }
   statistics_rolling_counter_ =
       (statistics_rolling_counter_ + 1) % kStatisticsUpdatePeriod;
 
-  base::TimeDelta media_time =
-      base::TimeDelta::FromMicroseconds(clock_device_->GetTimeMicroseconds());
+  base::TimeDelta media_time = base::TimeDelta::FromMicroseconds(
+      media_pipeline_backend_->GetCurrentPts());
   if (media_time == ::media::kNoTimestamp()) {
     pending_time_update_task_ = true;
     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
diff --git a/chromecast/media/cma/pipeline/media_pipeline_impl.h b/chromecast/media/cma/pipeline/media_pipeline_impl.h
index e2dba4f..92453cd 100644
--- a/chromecast/media/cma/pipeline/media_pipeline_impl.h
+++ b/chromecast/media/cma/pipeline/media_pipeline_impl.h
@@ -12,20 +12,26 @@
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread_checker.h"
 #include "chromecast/media/cma/pipeline/load_type.h"
-#include "chromecast/media/cma/pipeline/media_pipeline.h"
 #include "chromecast/media/cma/pipeline/media_pipeline_client.h"
+#include "chromecast/public/media/media_pipeline_backend.h"
 #include "media/base/serial_runner.h"
 
+namespace media {
+class AudioDecoderConfig;
+class VideoDecoderConfig;
+}  // namespace media
+
 namespace chromecast {
 namespace media {
 class AudioPipelineImpl;
+struct AvPipelineClient;
+struct VideoPipelineClient;
 class BrowserCdmCast;
 class BufferingController;
-class MediaClockDevice;
-class MediaPipelineBackend;
+class CodedFrameProvider;
 class VideoPipelineImpl;
 
-class MediaPipelineImpl : public MediaPipeline {
+class MediaPipelineImpl : public MediaPipelineBackend::Delegate {
  public:
   MediaPipelineImpl();
   ~MediaPipelineImpl() override;
@@ -35,26 +41,30 @@
   void Initialize(LoadType load_type,
                   scoped_ptr<MediaPipelineBackend> media_pipeline_backend);
 
-  // MediaPipeline implementation.
-  void SetClient(const MediaPipelineClient& client) override;
-  void SetCdm(int cdm_id) override;
-  AudioPipeline* GetAudioPipeline() const override;
-  VideoPipeline* GetVideoPipeline() const override;
-  void InitializeAudio(
-      const ::media::AudioDecoderConfig& config,
-      scoped_ptr<CodedFrameProvider> frame_provider,
-      const ::media::PipelineStatusCB& status_cb) override;
-  void InitializeVideo(
-      const std::vector<::media::VideoDecoderConfig>& configs,
-      scoped_ptr<CodedFrameProvider> frame_provider,
-      const ::media::PipelineStatusCB& status_cb) override;
-  void StartPlayingFrom(base::TimeDelta time) override;
-  void Flush(const ::media::PipelineStatusCB& status_cb) override;
-  void Stop() override;
-  void SetPlaybackRate(double playback_rate) override;
+  void SetClient(const MediaPipelineClient& client);
+  void SetCdm(int cdm_id);
 
-  AudioPipelineImpl* GetAudioPipelineImpl() const;
-  VideoPipelineImpl* GetVideoPipelineImpl() const;
+  // MediaPipelineBackendDelegate implementation:
+  void OnVideoResolutionChanged(MediaPipelineBackend::VideoDecoder* decoder,
+                                const Size& size) override;
+  void OnPushBufferComplete(MediaPipelineBackend::Decoder* decoder,
+                            MediaPipelineBackend::BufferStatus status) override;
+  void OnEndOfStream(MediaPipelineBackend::Decoder* decoder) override;
+  void OnDecoderError(MediaPipelineBackend::Decoder* decoder) override;
+
+  void InitializeAudio(const ::media::AudioDecoderConfig& config,
+                       const AvPipelineClient& client,
+                       scoped_ptr<CodedFrameProvider> frame_provider,
+                       const ::media::PipelineStatusCB& status_cb);
+  void InitializeVideo(const std::vector< ::media::VideoDecoderConfig>& configs,
+                       const VideoPipelineClient& client,
+                       scoped_ptr<CodedFrameProvider> frame_provider,
+                       const ::media::PipelineStatusCB& status_cb);
+  void StartPlayingFrom(base::TimeDelta time);
+  void Flush(const ::media::PipelineStatusCB& status_cb);
+  void Stop();
+  void SetPlaybackRate(double playback_rate);
+  void SetVolume(float volume);
 
   void SetCdm(BrowserCdmCast* cdm);
 
@@ -77,20 +87,21 @@
 
   // Interface with the underlying hardware media pipeline.
   scoped_ptr<MediaPipelineBackend> media_pipeline_backend_;
-  MediaClockDevice* clock_device_;
+  MediaPipelineBackend::AudioDecoder* audio_decoder_;
+  MediaPipelineBackend::VideoDecoder* video_decoder_;
 
+  bool backend_initialized_;
   bool has_audio_;
   bool has_video_;
   scoped_ptr<AudioPipelineImpl> audio_pipeline_;
   scoped_ptr<VideoPipelineImpl> video_pipeline_;
   scoped_ptr< ::media::SerialRunner> pending_flush_callbacks_;
 
+  // Whether or not the backend is currently paused.
+  bool paused_;
   // Playback rate set by the upper layer.
   float target_playback_rate_;
 
-  // Indicate a possible re-buffering phase.
-  bool is_buffering_;
-
   // The media time is retrieved at regular intervals.
   // Indicate whether time update is enabled.
   bool enable_time_update_;
diff --git a/chromecast/media/cma/pipeline/video_pipeline.cc b/chromecast/media/cma/pipeline/video_pipeline.cc
deleted file mode 100644
index 6b428b5..0000000
--- a/chromecast/media/cma/pipeline/video_pipeline.cc
+++ /dev/null
@@ -1,17 +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 "chromecast/media/cma/pipeline/video_pipeline.h"
-
-namespace chromecast {
-namespace media {
-
-VideoPipeline::VideoPipeline() {
-}
-
-VideoPipeline::~VideoPipeline() {
-}
-
-}  // namespace media
-}  // namespace chromecast
diff --git a/chromecast/media/cma/pipeline/video_pipeline.h b/chromecast/media/cma/pipeline/video_pipeline.h
deleted file mode 100644
index 68a9b8c..0000000
--- a/chromecast/media/cma/pipeline/video_pipeline.h
+++ /dev/null
@@ -1,28 +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 CHROMECAST_MEDIA_CMA_PIPELINE_VIDEO_PIPELINE_H_
-#define CHROMECAST_MEDIA_CMA_PIPELINE_VIDEO_PIPELINE_H_
-
-#include "base/macros.h"
-
-namespace chromecast {
-namespace media {
-struct VideoPipelineClient;
-
-class VideoPipeline {
- public:
-  VideoPipeline();
-  virtual ~VideoPipeline();
-
-  virtual void SetClient(const VideoPipelineClient& client) = 0;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(VideoPipeline);
-};
-
-}  // namespace media
-}  // namespace chromecast
-
-#endif  // CHROMECAST_MEDIA_CMA_PIPELINE_VIDEO_PIPELINE_H_
diff --git a/chromecast/media/cma/pipeline/video_pipeline_device_client_impl.cc b/chromecast/media/cma/pipeline/video_pipeline_device_client_impl.cc
deleted file mode 100644
index a604be3..0000000
--- a/chromecast/media/cma/pipeline/video_pipeline_device_client_impl.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2015 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 "chromecast/media/cma/pipeline/video_pipeline_device_client_impl.h"
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/single_thread_task_runner.h"
-#include "base/thread_task_runner_handle.h"
-#include "chromecast/public/graphics_types.h"
-
-namespace chromecast {
-namespace media {
-
-VideoPipelineDeviceClientImpl::VideoPipelineDeviceClientImpl(
-    const SizeChangeCB& size_change_cb)
-    : size_change_cb_(size_change_cb),
-      task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
-
-VideoPipelineDeviceClientImpl::~VideoPipelineDeviceClientImpl() {}
-
-void VideoPipelineDeviceClientImpl::OnNaturalSizeChanged(const Size& size) {
-  if (task_runner_->BelongsToCurrentThread()) {
-    if (!size_change_cb_.is_null())
-      size_change_cb_.Run(size);
-  } else {
-    task_runner_->PostTask(FROM_HERE, base::Bind(size_change_cb_, size));
-  }
-}
-
-}  // namespace media
-}  // namespace chromecast
diff --git a/chromecast/media/cma/pipeline/video_pipeline_device_client_impl.h b/chromecast/media/cma/pipeline/video_pipeline_device_client_impl.h
deleted file mode 100644
index e39fdc9..0000000
--- a/chromecast/media/cma/pipeline/video_pipeline_device_client_impl.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2015 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 CHROMECAST_MEDIA_CMA_PIPELINE_VIDEO_PIPELINE_DEVICE_CLIENT_IMPL_H_
-#define CHROMECAST_MEDIA_CMA_PIPELINE_VIDEO_PIPELINE_DEVICE_CLIENT_IMPL_H_
-
-#include "base/callback.h"
-#include "base/memory/ref_counted.h"
-#include "chromecast/public/media/media_component_device.h"
-#include "chromecast/public/media/video_pipeline_device.h"
-
-namespace base {
-class SingleThreadTaskRunner;
-}
-
-namespace chromecast {
-namespace media {
-
-// Helper for implementing VideoPipelineDevice::VideoClient with
-// a base::Callback.
-class VideoPipelineDeviceClientImpl : public VideoPipelineDevice::VideoClient {
- public:
-  typedef base::Callback<void(const Size&)> SizeChangeCB;
-
-  VideoPipelineDeviceClientImpl(const SizeChangeCB& size_change_cb);
-  ~VideoPipelineDeviceClientImpl() override;
-
-  void OnNaturalSizeChanged(const Size& size) override;
-
- private:
-  SizeChangeCB size_change_cb_;
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-};
-
-}  // namespace media
-}  // namespace chromecast
-
-#endif  // CHROMECAST_MEDIA_CMA_PIPELINE_VIDEO_PIPELINE_DEVICE_CLIENT_IMPL_H_
diff --git a/chromecast/media/cma/pipeline/video_pipeline_impl.cc b/chromecast/media/cma/pipeline/video_pipeline_impl.cc
index 89d82cf..e24a7f7d 100644
--- a/chromecast/media/cma/pipeline/video_pipeline_impl.cc
+++ b/chromecast/media/cma/pipeline/video_pipeline_impl.cc
@@ -10,10 +10,8 @@
 #include "chromecast/media/cma/base/coded_frame_provider.h"
 #include "chromecast/media/cma/base/decoder_config_adapter.h"
 #include "chromecast/media/cma/pipeline/av_pipeline_impl.h"
-#include "chromecast/media/cma/pipeline/video_pipeline_device_client_impl.h"
 #include "chromecast/public/graphics_types.h"
 #include "chromecast/public/media/decoder_config.h"
-#include "chromecast/public/media/video_pipeline_device.h"
 #include "media/base/video_decoder_config.h"
 
 namespace chromecast {
@@ -23,12 +21,15 @@
 const size_t kMaxVideoFrameSize = 1024 * 1024;
 }
 
-VideoPipelineImpl::VideoPipelineImpl(VideoPipelineDevice* video_device)
-    : video_device_(video_device),
+VideoPipelineImpl::VideoPipelineImpl(
+    MediaPipelineBackend::VideoDecoder* video_decoder,
+    const VideoPipelineClient& client)
+    : video_decoder_(video_decoder),
+      video_client_(client),
       weak_factory_(this) {
   weak_this_ = weak_factory_.GetWeakPtr();
   av_pipeline_impl_.reset(new AvPipelineImpl(
-      video_device_,
+      video_decoder_,
       base::Bind(&VideoPipelineImpl::OnUpdateConfig, base::Unretained(this))));
 }
 
@@ -44,8 +45,7 @@
 bool VideoPipelineImpl::StartPlayingFrom(
     base::TimeDelta time,
     const scoped_refptr<BufferingState>& buffering_state) {
-  CMALOG(kLogControl) << "VideoPipelineImpl::StartPlayingFrom t0="
-                      << time.InMilliseconds();
+  CMALOG(kLogControl) << __FUNCTION__ << " t0=" << time.InMilliseconds();
 
   // Reset the pipeline statistics.
   previous_stats_ = ::media::PipelineStatistics();
@@ -65,7 +65,7 @@
 }
 
 void VideoPipelineImpl::Flush(const ::media::PipelineStatusCB& status_cb) {
-  CMALOG(kLogControl) << "VideoPipelineImpl::Flush";
+  CMALOG(kLogControl) << __FUNCTION__;
   if (av_pipeline_impl_->GetState() == AvPipelineImpl::kError) {
     status_cb.Run(::media::PIPELINE_ERROR_ABORT);
     return;
@@ -78,7 +78,7 @@
 
 void VideoPipelineImpl::OnFlushDone(
     const ::media::PipelineStatusCB& status_cb) {
-  CMALOG(kLogControl) << "VideoPipelineImpl::OnFlushDone";
+  CMALOG(kLogControl) << __FUNCTION__;
   if (av_pipeline_impl_->GetState() == AvPipelineImpl::kError) {
     status_cb.Run(::media::PIPELINE_ERROR_ABORT);
     return;
@@ -88,7 +88,7 @@
 }
 
 void VideoPipelineImpl::Stop() {
-  CMALOG(kLogControl) << "VideoPipelineImpl::Stop";
+  CMALOG(kLogControl) << __FUNCTION__;
   av_pipeline_impl_->Stop();
   av_pipeline_impl_->TransitionToState(AvPipelineImpl::kStopped);
 }
@@ -97,9 +97,21 @@
   av_pipeline_impl_->SetCdm(media_keys);
 }
 
-void VideoPipelineImpl::SetClient(const VideoPipelineClient& client) {
-  video_client_ = client;
-  av_pipeline_impl_->SetClient(client.av_pipeline_client);
+void VideoPipelineImpl::OnBufferPushed(
+    MediaPipelineBackend::BufferStatus status) {
+  av_pipeline_impl_->OnBufferPushed(status);
+}
+
+void VideoPipelineImpl::OnEndOfStream() {
+  if (!video_client_.av_pipeline_client.eos_cb.is_null())
+    video_client_.av_pipeline_client.eos_cb.Run();
+}
+
+void VideoPipelineImpl::OnError() {
+  if (!video_client_.av_pipeline_client.playback_error_cb.is_null()) {
+    video_client_.av_pipeline_client.playback_error_cb.Run(
+        ::media::PIPELINE_ERROR_COULD_NOT_RENDER);
+  }
 }
 
 void VideoPipelineImpl::Initialize(
@@ -111,8 +123,7 @@
     CMALOG(kLogControl) << __FUNCTION__ << " "
                         << config.AsHumanReadableString();
   }
-  video_device_->SetVideoClient(new VideoPipelineDeviceClientImpl(
-      base::Bind(&VideoPipelineImpl::OnNaturalSizeChanged, weak_this_)));
+
   if (frame_provider)
     SetCodedFrameProvider(frame_provider.Pass());
 
@@ -132,8 +143,7 @@
     video_config.additional_config = &secondary_config;
   }
 
-  if (!video_device_->SetConfig(video_config) ||
-      !av_pipeline_impl_->Initialize()) {
+  if (!video_decoder_->SetConfig(video_config)) {
     status_cb.Run(::media::PIPELINE_ERROR_INITIALIZATION_FAILED);
     return;
   }
@@ -146,10 +156,10 @@
     const ::media::AudioDecoderConfig& audio_config,
     const ::media::VideoDecoderConfig& video_config) {
   if (video_config.IsValidConfig()) {
-    CMALOG(kLogControl) << "VideoPipelineImpl::OnUpdateConfig id:" << id << " "
+    CMALOG(kLogControl) << __FUNCTION__ << " id:" << id << " "
                         << video_config.AsHumanReadableString();
 
-    bool success = video_device_->SetConfig(
+    bool success = video_decoder_->SetConfig(
         DecoderConfigAdapter::ToCastVideoConfig(id, video_config));
     if (!success &&
         !video_client_.av_pipeline_client.playback_error_cb.is_null()) {
@@ -173,9 +183,8 @@
   if (video_client_.av_pipeline_client.statistics_cb.is_null())
     return;
 
-  MediaComponentDevice::Statistics device_stats;
-  if (!video_device_->GetStatistics(&device_stats))
-    return;
+  MediaPipelineBackend::Decoder::Statistics device_stats;
+  video_decoder_->GetStatistics(&device_stats);
 
   ::media::PipelineStatistics current_stats;
   current_stats.video_bytes_decoded = device_stats.decoded_bytes;
diff --git a/chromecast/media/cma/pipeline/video_pipeline_impl.h b/chromecast/media/cma/pipeline/video_pipeline_impl.h
index e488c263..9fd3071 100644
--- a/chromecast/media/cma/pipeline/video_pipeline_impl.h
+++ b/chromecast/media/cma/pipeline/video_pipeline_impl.h
@@ -11,10 +11,9 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread_checker.h"
-#include "chromecast/media/cma/pipeline/video_pipeline.h"
 #include "chromecast/media/cma/pipeline/video_pipeline_client.h"
+#include "chromecast/public/media/media_pipeline_backend.h"
 #include "chromecast/public/media/stream_id.h"
-#include "chromecast/public/media/video_pipeline_device.h"
 
 namespace media {
 class AudioDecoderConfig;
@@ -28,13 +27,12 @@
 class BrowserCdmCast;
 class BufferingState;
 class CodedFrameProvider;
-class VideoPipelineDevice;
 
-class VideoPipelineImpl : public VideoPipeline {
+class VideoPipelineImpl {
  public:
-  // |buffering_controller| can be NULL.
-  explicit VideoPipelineImpl(VideoPipelineDevice* video_device);
-  ~VideoPipelineImpl() override;
+  VideoPipelineImpl(MediaPipelineBackend::VideoDecoder* decoder,
+                    const VideoPipelineClient& client);
+  ~VideoPipelineImpl();
 
   // Input port of the pipeline.
   void SetCodedFrameProvider(scoped_ptr<CodedFrameProvider> frame_provider);
@@ -55,8 +53,10 @@
   // Update the playback statistics for this video stream.
   void UpdateStatistics();
 
-  // VideoPipeline implementation.
-  void SetClient(const VideoPipelineClient& client) override;
+  void OnBufferPushed(MediaPipelineBackend::BufferStatus status);
+  void OnEndOfStream();
+  void OnError();
+  void OnNaturalSizeChanged(const Size& size);
 
  private:
   class DeviceClientImpl;
@@ -66,9 +66,8 @@
   void OnUpdateConfig(StreamId id,
                       const ::media::AudioDecoderConfig& audio_config,
                       const ::media::VideoDecoderConfig& video_config);
-  void OnNaturalSizeChanged(const Size& size);
 
-  VideoPipelineDevice* video_device_;
+  MediaPipelineBackend::VideoDecoder* video_decoder_;
 
   scoped_ptr<AvPipelineImpl> av_pipeline_impl_;
   VideoPipelineClient video_client_;
diff --git a/chromecast/media/cma/test/cma_end_to_end_test.cc b/chromecast/media/cma/test/cma_end_to_end_test.cc
deleted file mode 100644
index 70483e6..0000000
--- a/chromecast/media/cma/test/cma_end_to_end_test.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2015 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 "base/bind.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/time/time.h"
-#include "chromecast/base/task_runner_impl.h"
-#include "chromecast/media/cma/backend/media_pipeline_backend_default.h"
-#include "chromecast/media/cma/base/buffering_defs.h"
-#include "chromecast/media/cma/filters/cma_renderer.h"
-#include "chromecast/media/cma/pipeline/media_pipeline_impl.h"
-#include "gpu/command_buffer/client/gles2_interface_stub.h"
-#include "media/base/demuxer_stream_provider.h"
-#include "media/base/fake_demuxer_stream.h"
-#include "media/base/null_video_sink.h"
-#include "media/renderers/mock_gpu_video_accelerator_factories.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace chromecast {
-namespace media {
-
-namespace {
-
-class CmaEndToEndTest : public testing::Test {
- public:
-  CmaEndToEndTest() {}
-
-  void SetUp() override {
-    demuxer_stream_provider_.reset(
-        new ::media::FakeDemuxerStreamProvider(1, 1, false));
-    null_sink_.reset(new ::media::NullVideoSink(
-        false, base::TimeDelta::FromSecondsD(1.0 / 60),
-        base::Bind(&MockCB::OnFrameReceived, base::Unretained(&mock_)),
-        message_loop_.task_runner()));
-
-    scoped_ptr<MediaPipelineImpl> media_pipeline(new MediaPipelineImpl());
-    task_runner_.reset(new TaskRunnerImpl());
-    MediaPipelineDeviceParams params(task_runner_.get());
-    scoped_ptr<MediaPipelineBackend> backend =
-        make_scoped_ptr(new MediaPipelineBackendDefault(params));
-
-    gles2_.reset(new gpu::gles2::GLES2InterfaceStub());
-    mock_gpu_factories_ = new ::media::MockGpuVideoAcceleratorFactories();
-
-    EXPECT_CALL(*mock_gpu_factories_.get(), GetGLES2Interface())
-        .WillRepeatedly(testing::Return(gles2_.get()));
-
-    media_pipeline->Initialize(kLoadTypeMediaSource, backend.Pass());
-
-    renderer_.reset(new CmaRenderer(media_pipeline.Pass(), null_sink_.get(),
-                                    mock_gpu_factories_));
-  }
-  void TearDown() override { message_loop_.RunUntilIdle(); }
-
-  ~CmaEndToEndTest() override {}
-
- protected:
-  base::MessageLoop message_loop_;
-  scoped_ptr<TaskRunnerImpl> task_runner_;
-  scoped_ptr<::media::FakeDemuxerStreamProvider> demuxer_stream_provider_;
-  scoped_ptr<CmaRenderer> renderer_;
-  scoped_refptr<::media::MockGpuVideoAcceleratorFactories> mock_gpu_factories_;
-  scoped_ptr<gpu::gles2::GLES2Interface> gles2_;
-
-  class MockCB {
-   public:
-    MOCK_METHOD1(OnInitialized, void(::media::PipelineStatus));
-    MOCK_METHOD1(OnFrameReceived,
-                 void(const scoped_refptr<::media::VideoFrame>&));
-    MOCK_METHOD1(OnStatistics, void(const ::media::PipelineStatistics&));
-    MOCK_METHOD1(OnBufferingState, void(::media::BufferingState));
-    MOCK_METHOD0(OnEnded, void());
-    MOCK_METHOD1(OnError, void(::media::PipelineStatus));
-    MOCK_METHOD0(OnWaitingForDecryptionKey, void());
-  };
-  MockCB mock_;
-
- private:
-  scoped_ptr<::media::NullVideoSink> null_sink_;
-
-  DISALLOW_COPY_AND_ASSIGN(CmaEndToEndTest);
-};
-
-}  // namespace
-
-TEST_F(CmaEndToEndTest, TestInitialization) {
-  renderer_->Initialize(
-      demuxer_stream_provider_.get(),
-      base::Bind(&MockCB::OnInitialized, base::Unretained(&mock_)),
-      base::Bind(&MockCB::OnStatistics, base::Unretained(&mock_)),
-      base::Bind(&MockCB::OnBufferingState, base::Unretained(&mock_)),
-      base::Bind(&MockCB::OnEnded, base::Unretained(&mock_)),
-      base::Bind(&MockCB::OnError, base::Unretained(&mock_)),
-      base::Bind(&MockCB::OnWaitingForDecryptionKey, base::Unretained(&mock_)));
-
-  EXPECT_CALL(mock_, OnInitialized(::media::PIPELINE_OK));
-}
-
-
-}  // namespace media
-}  // namespace chromecast
diff --git a/chromecast/media/cma/test/media_component_device_feeder_for_test.cc b/chromecast/media/cma/test/media_component_device_feeder_for_test.cc
deleted file mode 100644
index 96ec02c..0000000
--- a/chromecast/media/cma/test/media_component_device_feeder_for_test.cc
+++ /dev/null
@@ -1,130 +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 "chromecast/media/cma/test/media_component_device_feeder_for_test.h"
-
-#include <list>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "chromecast/media/cma/base/cast_decoder_buffer_impl.h"
-#include "chromecast/media/cma/base/decoder_buffer_adapter.h"
-#include "chromecast/media/cma/pipeline/frame_status_cb_impl.h"
-#include "chromecast/media/cma/pipeline/media_component_device_client_impl.h"
-#include "chromecast/media/cma/test/frame_segmenter_for_test.h"
-#include "chromecast/public/media/audio_pipeline_device.h"
-#include "chromecast/public/media/cast_decoder_buffer.h"
-#include "chromecast/public/media/decrypt_context.h"
-#include "chromecast/public/media/media_clock_device.h"
-#include "chromecast/public/media/video_pipeline_device.h"
-#include "media/base/audio_decoder_config.h"
-#include "media/base/decoder_buffer.h"
-#include "media/base/video_decoder_config.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace chromecast {
-namespace media {
-
-MediaComponentDeviceFeederForTest::MediaComponentDeviceFeederForTest(
-    MediaComponentDevice *device,
-    const BufferList& frames)
-    : media_component_device_(device),
-      rendering_frame_idx_(1),
-      clock_frame_idx_(1),
-      feeding_completed_(false) {
-  frames_ = frames;
-}
-
-MediaComponentDeviceFeederForTest::~MediaComponentDeviceFeederForTest() {
-}
-
-void MediaComponentDeviceFeederForTest::Initialize(
-    const base::Closure& eos_cb) {
-  eos_cb_ = eos_cb;
-
-  media_component_device_->SetClient(
-      new MediaComponentDeviceClientImpl(base::Bind(
-          &MediaComponentDeviceFeederForTest::OnEos, base::Unretained(this))));
-
-  bool success =
-      media_component_device_->SetState(MediaComponentDevice::kStateIdle);
-  ASSERT_TRUE(success);
-  success = media_component_device_->SetStartPts(0);
-  ASSERT_TRUE(success);
-  success =
-      media_component_device_->SetState(MediaComponentDevice::kStatePaused);
-  ASSERT_TRUE(success);
-}
-
-void MediaComponentDeviceFeederForTest::Feed() {
-  // Start rendering if needed.
-  if (rendering_frame_idx_ == 0) {
-    media_component_device_->SetState(MediaComponentDevice::kStateRunning);
-  } else {
-    rendering_frame_idx_--;
-  }
-
-  // Possibly feed one frame
-  DCHECK(!frames_.empty());
-  scoped_refptr<DecoderBufferBase> buffer = frames_.front();
-
-  MediaComponentDevice::FrameStatus status = media_component_device_->PushFrame(
-      nullptr, // decrypt_context
-      new CastDecoderBufferImpl(buffer),
-      new FrameStatusCBImpl(
-          base::Bind(&MediaComponentDeviceFeederForTest::OnFramePushed,
-                     base::Unretained(this))));
-  EXPECT_NE(status, MediaComponentDevice::kFrameFailed);
-  frames_.pop_front();
-
-  // Feeding is done, just wait for the end of stream callback.
-  if (buffer->end_of_stream() || frames_.empty()) {
-    if (frames_.empty() && !buffer->end_of_stream()) {
-      LOG(WARNING) << "Stream emptied without feeding EOS frame";
-    }
-
-    feeding_completed_ = true;
-    return;
-  }
-
-  if (status == MediaComponentDevice::kFramePending)
-    return;
-
-  OnFramePushed(MediaComponentDevice::kFrameSuccess);
-}
-
-void MediaComponentDeviceFeederForTest::OnFramePushed(
-    MediaComponentDevice::FrameStatus status) {
-  EXPECT_NE(status, MediaComponentDevice::kFrameFailed);
-  if (feeding_completed_)
-    return;
-
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(&MediaComponentDeviceFeederForTest::Feed,
-                            base::Unretained(this)));
-}
-
-void MediaComponentDeviceFeederForTest::OnEos() {
-  bool success = media_component_device_->SetState(
-      MediaComponentDevice::kStateIdle);
-  ASSERT_TRUE(success);
-  success = media_component_device_->SetState(
-      MediaComponentDevice::kStateUninitialized);
-  ASSERT_TRUE(success);
-
-  if (!eos_cb_.is_null()) {
-    eos_cb_.Run();
-  }
-}
-
-}  // namespace media
-}  // namespace chromecast
diff --git a/chromecast/media/cma/test/media_component_device_feeder_for_test.h b/chromecast/media/cma/test/media_component_device_feeder_for_test.h
deleted file mode 100644
index cd28eb4..0000000
--- a/chromecast/media/cma/test/media_component_device_feeder_for_test.h
+++ /dev/null
@@ -1,68 +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 CHROMECAST_MEDIA_CMA_TEST_MEDIA_COMPONENT_DEVICE_FEEDER_FOR_TEST_H_
-#define CHROMECAST_MEDIA_CMA_TEST_MEDIA_COMPONENT_DEVICE_FEEDER_FOR_TEST_H_
-
-#include <list>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/callback.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/time/time.h"
-#include "chromecast/public/media/audio_pipeline_device.h"
-#include "chromecast/public/media/cast_decoder_buffer.h"
-#include "chromecast/public/media/media_clock_device.h"
-#include "chromecast/public/media/video_pipeline_device.h"
-
-namespace chromecast {
-namespace media {
-class DecoderBufferBase;
-
-typedef std::list<scoped_refptr<DecoderBufferBase> > BufferList;
-
-class MediaComponentDeviceFeederForTest {
- public:
-  MediaComponentDeviceFeederForTest(
-      MediaComponentDevice *device,
-      const BufferList& frames);
-
-  virtual ~MediaComponentDeviceFeederForTest();
-
-  void Initialize(const base::Closure& eos_cb);
-
-  // Feeds one frame into the pipeline.
-  void Feed();
-
- private:
-  void OnFramePushed(MediaComponentDevice::FrameStatus status);
-
-  void OnEos();
-
-  MediaComponentDevice *media_component_device_;
-  BufferList frames_;
-
-  // Frame index where the audio device is switching to the kStateRunning.
-  int rendering_frame_idx_;
-
-  // Frame index where the clock device is switching to the kStateRunning.
-  int clock_frame_idx_;
-
-  // Timing pattern to feed the pipeline.
-  std::vector<base::TimeDelta> delayed_feed_pattern_;
-  size_t delayed_feed_pattern_idx_;
-
-  base::Closure eos_cb_;
-
-  bool feeding_completed_;
-
-  DISALLOW_COPY_AND_ASSIGN(MediaComponentDeviceFeederForTest);
-};
-
-}  // namespace media
-}  // namespace chromecast
-
-#endif  // CHROMECAST_MEDIA_CMA_TEST_MEDIA_COMPONENT_DEVICE_FEEDER_FOR_TEST_H_
diff --git a/chromecast/media/media.gyp b/chromecast/media/media.gyp
index ad08911c..fe0fd7c 100644
--- a/chromecast/media/media.gyp
+++ b/chromecast/media/media.gyp
@@ -147,16 +147,8 @@
         '../..',
       ],
       'sources': [
-        'cma/backend/audio_pipeline_device_default.cc',
-        'cma/backend/audio_pipeline_device_default.h',
-        'cma/backend/media_clock_device_default.cc',
-        'cma/backend/media_clock_device_default.h',
-        'cma/backend/media_component_device_default.cc',
-        'cma/backend/media_component_device_default.h',
         'cma/backend/media_pipeline_backend_default.cc',
         'cma/backend/media_pipeline_backend_default.h',
-        'cma/backend/video_pipeline_device_default.cc',
-        'cma/backend/video_pipeline_device_default.h',
       ],
     },
     {
@@ -210,8 +202,6 @@
         '../../third_party/boringssl/boringssl.gyp:boringssl',
       ],
       'sources': [
-        'cma/pipeline/audio_pipeline.cc',
-        'cma/pipeline/audio_pipeline.h',
         'cma/pipeline/audio_pipeline_impl.cc',
         'cma/pipeline/audio_pipeline_impl.h',
         'cma/pipeline/av_pipeline_client.cc',
@@ -220,49 +210,22 @@
         'cma/pipeline/av_pipeline_impl.h',
         'cma/pipeline/decrypt_util.cc',
         'cma/pipeline/decrypt_util.h',
-        'cma/pipeline/frame_status_cb_impl.cc',
-        'cma/pipeline/frame_status_cb_impl.h',
         'cma/pipeline/load_type.h',
-        'cma/pipeline/media_component_device_client_impl.cc',
-        'cma/pipeline/media_component_device_client_impl.h',
-        'cma/pipeline/media_pipeline.h',
         'cma/pipeline/media_pipeline_client.cc',
         'cma/pipeline/media_pipeline_client.h',
         'cma/pipeline/media_pipeline_impl.cc',
         'cma/pipeline/media_pipeline_impl.h',
-        'cma/pipeline/video_pipeline.cc',
-        'cma/pipeline/video_pipeline.h',
         'cma/pipeline/video_pipeline_client.cc',
         'cma/pipeline/video_pipeline_client.h',
-        'cma/pipeline/video_pipeline_device_client_impl.cc',
-        'cma/pipeline/video_pipeline_device_client_impl.h',
         'cma/pipeline/video_pipeline_impl.cc',
         'cma/pipeline/video_pipeline_impl.h',
       ],
     },
     {
-      'target_name': 'cma_filters',
-      'type': '<(component)',
-      'dependencies': [
-        '../../base/base.gyp:base',
-        '../../media/media.gyp:media',
-        'cma_base',
-      ],
-      'sources': [
-        'cma/filters/cma_renderer.cc',
-        'cma/filters/cma_renderer.h',
-        'cma/filters/demuxer_stream_adapter.cc',
-        'cma/filters/demuxer_stream_adapter.h',
-        'cma/filters/hole_frame_factory.cc',
-        'cma/filters/hole_frame_factory.h',
-      ],
-    },
-    {
       'target_name': 'cast_media',
       'type': 'none',
       'dependencies': [
         'cma_base',
-        'cma_filters',
         'cma_ipc',
         'cma_ipc_streamer',
         'cma_pipeline',
@@ -294,21 +257,14 @@
         'cma/base/balanced_media_task_runner_unittest.cc',
         'cma/base/buffering_controller_unittest.cc',
         'cma/base/buffering_frame_provider_unittest.cc',
-        'cma/filters/demuxer_stream_adapter_unittest.cc',
-        'cma/filters/multi_demuxer_stream_adapter_unittest.cc',
         'cma/ipc/media_message_fifo_unittest.cc',
         'cma/ipc/media_message_unittest.cc',
         'cma/ipc_streamer/av_streamer_unittest.cc',
         'cma/pipeline/audio_video_pipeline_impl_unittest.cc',
-        'cma/test/cma_end_to_end_test.cc',
-        'cma/test/demuxer_stream_for_test.cc',
-        'cma/test/demuxer_stream_for_test.h',
         'cma/test/frame_generator_for_test.cc',
         'cma/test/frame_generator_for_test.h',
         'cma/test/frame_segmenter_for_test.cc',
         'cma/test/frame_segmenter_for_test.h',
-        'cma/test/media_component_device_feeder_for_test.cc',
-        'cma/test/media_component_device_feeder_for_test.h',
         'cma/test/mock_frame_consumer.cc',
         'cma/test/mock_frame_consumer.h',
         'cma/test/mock_frame_provider.cc',
diff --git a/chromecast/public/cast_media_shlib.h b/chromecast/public/cast_media_shlib.h
index d523db88..6360aab 100644
--- a/chromecast/public/cast_media_shlib.h
+++ b/chromecast/public/cast_media_shlib.h
@@ -42,9 +42,9 @@
   // called at any time.  The VideoPlane object must be destroyed in Finalize.
   static VideoPlane* GetVideoPlane();
 
-  // Creates a factory object for a media pipeline backend.  Called in the
-  // browser process, any number of times (once per media pipeline).  Each call
-  // must instantiate a new factory object
+  // Creates a media pipeline backend.  Called in the browser process for each
+  // media pipeline and raw audio stream. The caller owns the returned
+  // MediaPipelineBackend instance.
   static MediaPipelineBackend* CreateMediaPipelineBackend(
       const MediaPipelineDeviceParams& params);
 };
diff --git a/chromecast/public/media/BUILD.gn b/chromecast/public/media/BUILD.gn
index b6f699f1..3db81e0 100644
--- a/chromecast/public/media/BUILD.gn
+++ b/chromecast/public/media/BUILD.gn
@@ -4,17 +4,13 @@
 
 source_set("media") {
   sources = [
-    "audio_pipeline_device.h",
     "cast_decoder_buffer.h",
     "cast_decrypt_config.h",
     "cast_key_system.h",
     "decoder_config.h",
-    "media_clock_device.h",
-    "media_component_device.h",
     "media_pipeline_backend.h",
     "media_pipeline_device_params.h",
     "stream_id.h",
-    "video_pipeline_device.h",
   ]
 
   public_configs = [ ":public_headers" ]
diff --git a/chromecast/public/media/audio_pipeline_device.h b/chromecast/public/media/audio_pipeline_device.h
deleted file mode 100644
index 02fadeba2..0000000
--- a/chromecast/public/media/audio_pipeline_device.h
+++ /dev/null
@@ -1,35 +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 CHROMECAST_PUBLIC_MEDIA_AUDIO_PIPELINE_DEVICE_H_
-#define CHROMECAST_PUBLIC_MEDIA_AUDIO_PIPELINE_DEVICE_H_
-
-#include "media_component_device.h"
-
-namespace chromecast {
-namespace media {
-class AudioPipelineDeviceClient;
-struct AudioConfig;
-
-// Interface for platform-specific audio pipeline backend.
-// See comments on MediaComponentDevice.
-class AudioPipelineDevice : public MediaComponentDevice {
- public:
-  ~AudioPipelineDevice() override {}
-
-  // Provides the audio configuration.
-  // Will be called before switching from |kStateUninitialized| to |kStateIdle|.
-  // Afterwards, this can be invoked any time the configuration changes.
-  // Returns true if the configuration is a supported configuration.
-  virtual bool SetConfig(const AudioConfig& config) = 0;
-
-  // Sets the volume multiplier.
-  // The multiplier is in the range [0.0, 1.0].
-  virtual void SetStreamVolumeMultiplier(float multiplier) = 0;
-};
-
-}  // namespace media
-}  // namespace chromecast
-
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_AUDIO_PIPELINE_DEVICE_H_
diff --git a/chromecast/public/media/media_clock_device.h b/chromecast/public/media/media_clock_device.h
deleted file mode 100644
index 7bb945ef..0000000
--- a/chromecast/public/media/media_clock_device.h
+++ /dev/null
@@ -1,63 +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 CHROMECAST_PUBLIC_MEDIA_MEDIA_CLOCK_DEVICE_H_
-#define CHROMECAST_PUBLIC_MEDIA_MEDIA_CLOCK_DEVICE_H_
-
-#include <string>
-
-namespace chromecast {
-namespace media {
-
-// Interface for platform-specific pipeline clock.
-// Pipeline clocks follow this state machine:
-//                      -------------------
-//                      |                 |
-//                      v                 |
-// kUninitialized --> kIdle  --------- kRunning
-//
-// {any state} --> kError
-//
-// Notes:
-// - Hardware resources should be acquired when transitioning from the
-//   |kUninitialized| state to the |kIdle| state.
-// - The initial value of the timeline will only be set in the kIdle state.
-class MediaClockDevice {
- public:
-  enum State {
-    kStateUninitialized,
-    kStateIdle,
-    kStateRunning,
-    kStateError,
-  };
-
-  virtual ~MediaClockDevice() {}
-
-  // Returns the current state of the media clock.
-  virtual State GetState() const = 0;
-
-  // Changes the state and performs any necessary transitions.
-  // Returns true when successful.
-  virtual bool SetState(State new_state) = 0;
-
-  // Sets the initial value of the timeline in microseconds.
-  // Will only be invoked in state kStateIdle.
-  // Returns true when successful.
-  virtual bool ResetTimeline(int64_t time_microseconds) = 0;
-
-  // Sets the clock rate.
-  // |rate| == 0 means the clock is not progressing and that the renderer
-  // tied to this media clock should pause rendering.
-  // Will only be invoked in states kStateIdle or kStateRunning.
-  virtual bool SetRate(float rate) = 0;
-
-  // Retrieves the media clock time in microseconds.
-  // Will only be invoked in states kStateIdle or kStateRunning.
-  virtual int64_t GetTimeMicroseconds() = 0;
-};
-
-}  // namespace media
-}  // namespace chromecast
-
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_CLOCK_DEVICE_H_
diff --git a/chromecast/public/media/media_component_device.h b/chromecast/public/media/media_component_device.h
deleted file mode 100644
index b6f6255..0000000
--- a/chromecast/public/media/media_component_device.h
+++ /dev/null
@@ -1,142 +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 CHROMECAST_PUBLIC_MEDIA_MEDIA_COMPONENT_DEVICE_H_
-#define CHROMECAST_PUBLIC_MEDIA_MEDIA_COMPONENT_DEVICE_H_
-
-#include <stdint.h>
-#include <string>
-
-#include "cast_key_system.h"
-
-namespace chromecast {
-namespace media {
-class CastDecoderBuffer;
-class DecryptContext;
-
-// Common base interface for both platform-specific audio and video pipeline
-// backends.  Both follow this state machine:
-//                       +------------- kRunning <--+
-//                       |                 ^        |
-//                       v                 |        |
-// kUninitialized <--> kIdle  -------------+        |
-//                       ^                 |        |
-//                       |                 v        |
-//                       +------------- kPaused <---+
-// {any state} --> kError
-// kError --> kUninitialized
-//
-// Notes:
-// - Hardware resources should be acquired when transitioning from the
-//   |kUninitialized| state to the |kIdle| state.
-// - Buffers will be pushed only in the kRunning or kPaused states.
-// - The end of stream is signaled through a special buffer.
-//   Once the end of stream buffer is fed, no other buffer
-//   will be fed until the FSM goes through the kIdle state again.
-// - In both kPaused and kRunning states, frames can be fed.
-//   However, frames are possibly rendered only in the kRunning state.
-// - In the kRunning state, frames are rendered according to the clock rate.
-// - All the hardware resources must be released in the |kError| state.
-class MediaComponentDevice {
- public:
-  enum State {
-    kStateUninitialized,
-    kStateIdle,
-    kStateRunning,
-    kStatePaused,
-    kStateError,
-  };
-
-  enum FrameStatus {
-    kFrameSuccess,
-    kFrameFailed,
-    kFramePending,
-  };
-
-  // Interface for receiving status when PushFrame has completed.
-  class FrameStatusCB {
-   public:
-    virtual ~FrameStatusCB() {}
-    virtual void Run(FrameStatus status) = 0;
-  };
-
-  // Client callbacks interface
-  class Client {
-   public:
-    virtual ~Client() {}
-    virtual void OnEndOfStream() = 0;
-  };
-
-  // The statistics are computed since the media component left the idle state.
-  // For video, a sample is defined as a frame.
-  struct Statistics {
-    uint64_t decoded_bytes;
-    uint64_t decoded_samples;
-    uint64_t dropped_samples;
-  };
-
-  // Info on pipeline latency: amount of data in pipeline not rendered yet,
-  // and timestamp of system clock (must be CLOCK_MONOTONIC) at which delay
-  // measurement was taken.  Both times in microseconds.
-  struct RenderingDelay {
-    RenderingDelay()
-        : delay_microseconds(INT64_MIN), timestamp_microseconds(INT64_MIN) {}
-    RenderingDelay(int64_t delay_microseconds_in,
-                   int64_t timestamp_microseconds_in)
-        : delay_microseconds(delay_microseconds_in),
-          timestamp_microseconds(timestamp_microseconds_in) {}
-    int64_t delay_microseconds;
-    int64_t timestamp_microseconds;
-  };
-
-  virtual ~MediaComponentDevice() {}
-
-  // Registers |client| as the media event handler.  Implementation
-  // takes ownership of |client| and call OnEndOfStream when an end-of-stream
-  // buffer is processed.
-  virtual void SetClient(Client* client) = 0;
-
-  // Changes the state and performs any necessary transitions.
-  // Returns true when successful.
-  virtual bool SetState(State new_state) = 0;
-
-  // Returns the current state of the media component.
-  virtual State GetState() const = 0;
-
-  // Sets the time where rendering should start.
-  // Return true when successful.
-  // Will only be invoked in state kStateIdle.
-  virtual bool SetStartPts(int64_t microseconds) = 0;
-
-  // Pushes a frame.  If the implementation cannot push the buffer
-  // now, it must store the buffer, return |kFramePending| and execute the push
-  // at a later time when it becomes possible to do so.  The implementation must
-  // then invoke |completion_cb|.  Pushing a pending frame should be aborted if
-  // the state returns to kStateIdle, and |completion_cb| need not be invoked.
-  // If |kFramePending| is returned, the pipeline will stop pushing any further
-  // buffers until the |completion_cb| is invoked.
-  // Ownership: |decrypt_context|, |buffer|, |completion_cb| are all owned by
-  // the implementation and must be deleted once no longer needed (even in the
-  // case where |completion_cb| is not called).
-  // |completion_cb| should be only be invoked to indicate completion of a
-  // pending buffer push - not for the immediate |kFrameSuccess| return case.
-  virtual FrameStatus PushFrame(DecryptContext* decrypt_context,
-                                CastDecoderBuffer* buffer,
-                                FrameStatusCB* completion_cb) = 0;
-
-  // Returns the pipeline latency: i.e. the amount of data
-  // in the pipeline that have not been rendered yet, in microseconds.
-  // Returns delay = INT64_MIN if the latency is not available.
-  virtual RenderingDelay GetRenderingDelay() const = 0;
-
-  // Returns the playback statistics since the last transition from idle state.
-  // Returns true when successful.
-  // Is only invoked in state kStateRunning.
-  virtual bool GetStatistics(Statistics* stats) const = 0;
-};
-
-}  // namespace media
-}  // namespace chromecast
-
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_COMPONENT_DEVICE_H_
diff --git a/chromecast/public/media/media_pipeline_backend.h b/chromecast/public/media/media_pipeline_backend.h
index cf64acce..741c2b7 100644
--- a/chromecast/public/media/media_pipeline_backend.h
+++ b/chromecast/public/media/media_pipeline_backend.h
@@ -5,35 +5,195 @@
 #ifndef CHROMECAST_PUBLIC_MEDIA_MEDIA_PIPELINE_BACKEND_H_
 #define CHROMECAST_PUBLIC_MEDIA_MEDIA_PIPELINE_BACKEND_H_
 
+#include "decoder_config.h"
+
 namespace chromecast {
+struct Size;
+
 namespace media {
+class CastDecoderBuffer;
+class DecryptContext;
 
-class AudioPipelineDevice;
-class MediaClockDevice;
-struct MediaPipelineDeviceParams;
-class VideoPipelineDevice;
-
-// Interface for creating and managing ownership of platform-specific clock,
-// audio and video devices.  cast_shell owns the MediaPipelineBackend for
-// as long as it is needed; the implementation is responsible for
-// tearing down the individual components correctly when it is destroyed.
+// Interface for platform-specific output of media.
 // A new MediaPipelineBackend will be instantiated for each media player
-// instance.
+// instance and raw audio stream.  If a backend has both video and audio
+// decoders, they must be synchronized.
+// If more backends are requested than the platform supports, the unsupported
+// extra backends may return nullptr for CreateAudioDecoder/CreateVideoDecoder.
+// The basic usage pattern is:
+//   * Decoder objects created, then Initialize called
+//   * Start/Stop/Pause/Resume used to manage playback state
+//   * Decoder objects are used to pass actual stream data buffers
+//   * Backend must make appropriate callbacks on the provided Delegate
+// All functions will be called on the media thread.  Delegate callbacks
+// must be made on this thread also (using provided TaskRunner if necessary).
 class MediaPipelineBackend {
  public:
+  // Return code for PushBuffer
+  enum BufferStatus {
+    kBufferSuccess,
+    kBufferFailed,
+    kBufferPending,
+  };
+
+  class Decoder {
+   public:
+    typedef MediaPipelineBackend::BufferStatus BufferStatus;
+
+    // Statistics (computed since pipeline last started playing).
+    // For video, a sample is defined as a frame.
+    struct Statistics {
+      uint64_t decoded_bytes;
+      uint64_t decoded_samples;
+      uint64_t dropped_samples;
+    };
+
+    // Pushes a buffer of data for decoding and output.  If the implementation
+    // cannot push the buffer now, it must store the buffer, return
+    // |kBufferPending| and execute the push at a later time when it becomes
+    // possible to do so.  The implementation must then invoke
+    // Client::OnPushComplete.  Pushing a pending buffer should be aborted if
+    // Stop is called; OnPushAudioComplete need not be invoked in this case.
+    // If |kBufferPending| is returned, the pipeline will stop pushing any
+    // further buffers until OnPushComplete is invoked.
+    // OnPushComplete should be only be invoked to indicate completion of a
+    // pending buffer push - not for the immediate |kBufferSuccess| return case.
+    // The decrypt_context and buffer's lifetimes are managed by the caller code
+    // - they MUST NOT be deleted by the MediaPipelineBackend implementation,
+    // and MUST NOT be dereferenced after completion of buffer push (i.e.
+    // kBufferSuccess/kBufferFailure for synchronous completion, OnPushComplete
+    // for kBufferPending case).
+    virtual BufferStatus PushBuffer(DecryptContext* decrypt_context,
+                                    CastDecoderBuffer* buffer) = 0;
+
+    // Returns the playback statistics since this decoder's creation.  Only
+    // called when playing or paused.
+    virtual void GetStatistics(Statistics* statistics) = 0;
+
+   protected:
+    virtual ~Decoder() {}
+  };
+
+  class AudioDecoder : public Decoder {
+   public:
+    // Info on pipeline latency: amount of data in pipeline not rendered yet,
+    // and timestamp of system clock (must be CLOCK_MONOTONIC) at which delay
+    // measurement was taken.  Both times in microseconds.
+    struct RenderingDelay {
+      RenderingDelay()
+          : delay_microseconds(INT64_MIN), timestamp_microseconds(INT64_MIN) {}
+      RenderingDelay(int64_t delay_microseconds_in,
+                     int64_t timestamp_microseconds_in)
+          : delay_microseconds(delay_microseconds_in),
+            timestamp_microseconds(timestamp_microseconds_in) {}
+      int64_t delay_microseconds;
+      int64_t timestamp_microseconds;
+    };
+
+    // Provides the audio configuration.  Called once before the backend is
+    // initialized, and again any time the configuration changes (in any state).
+    // Returns true if the configuration is a supported configuration.
+    virtual bool SetConfig(const AudioConfig& config) = 0;
+
+    // Sets the volume multiplier for this audio stream.
+    // The multiplier is in the range [0.0, 1.0].  If not called, a default
+    // multiplier of 1.0 is assumed. Returns true if successful.
+    // Only called after the backend has been initialized.
+    virtual bool SetVolume(float multiplier) = 0;
+
+    // Returns the pipeline latency: i.e. the amount of data
+    // in the pipeline that have not been rendered yet, in microseconds.
+    // Returns delay = INT64_MIN if the latency is not available.
+    // Only called when the backend is playing.
+    virtual RenderingDelay GetRenderingDelay() = 0;
+
+   protected:
+    ~AudioDecoder() override {}
+  };
+
+  class VideoDecoder : public Decoder {
+   public:
+    // Provides the video configuration.  Called once before the backend is
+    // initialized, and again any time the configuration changes (in any state).
+    // Returns true if the configuration is a supported configuration.
+    virtual bool SetConfig(const VideoConfig& config) = 0;
+
+   protected:
+    ~VideoDecoder() override {}
+  };
+
+  // Delegate methods must be called on the main CMA thread.
+  class Delegate {
+   public:
+    // Must be called when video resolution change is detected by decoder.
+    virtual void OnVideoResolutionChanged(VideoDecoder* decoder,
+                                          const Size& size) = 0;
+
+    // See comments on PushBuffer.  Must not be called with kBufferPending.
+    virtual void OnPushBufferComplete(Decoder* decoder,
+                                      BufferStatus status) = 0;
+
+    // Must be called after an end-of-stream buffer has been rendered (ie, the
+    // last real buffer has been sent to the output hardware).
+    virtual void OnEndOfStream(Decoder* decoder) = 0;
+
+    // May be called if a decoder error occurs. No more calls to PushBuffer()
+    // will be made after this is called.
+    virtual void OnDecoderError(Decoder* decoder) = 0;
+
+   protected:
+    virtual ~Delegate() {}
+  };
+
   virtual ~MediaPipelineBackend() {}
 
-  // Returns the platform-specific pipeline clock.
-  virtual MediaClockDevice* GetClock() = 0;
+  // Creates a new AudioDecoder attached to this pipeline.  MediaPipelineBackend
+  // maintains ownership of the decoder object (and must not delete before it's
+  // destroyed).  Will be called zero or more times, all calls made before
+  // Initialize. May return nullptr if the platform implementation cannot
+  // support any additional simultaneous playback at this time.
+  virtual AudioDecoder* CreateAudioDecoder() = 0;
 
-  // Returns the platform-specific audio backend.
-  virtual AudioPipelineDevice* GetAudio() = 0;
+  // Creates a new VideoDecoder attached to this pipeline.  MediaPipelineBackend
+  // maintains ownership of the decoder object (and must not delete before it's
+  // destroyed).  Will be called zero or more times, all calls made before
+  // Initialize. Note: Even if your backend only supports audio, you must
+  // provide a default implementation of VideoDecoder; one way to do this is to
+  // inherit from MediaPipelineBackendDefault. May return nullptr if the
+  // platform implementation cannot support any additional simultaneous playback
+  // at this time.
+  virtual VideoDecoder* CreateVideoDecoder() = 0;
 
-  // Returns the platform-specific video backend.
-  virtual VideoPipelineDevice* GetVideo() = 0;
+  // Initializes the backend.  This will be called once, after Decoder creation
+  // but before all other functions.  Hardware resources for all decoders should
+  // be acquired here.  Backend is then considered in Initialized state.
+  // Returns false for failure.
+  virtual bool Initialize(Delegate* delegate) = 0;
+
+  // Places pipeline into playing state.  Playback will start at given time once
+  // buffers are pushed.  Called only when in Initialized state. |start_pts| is
+  // the start playback timestamp in microseconds.
+  virtual bool Start(int64_t start_pts) = 0;
+
+  // Returns pipeline to 'Initialized' state.  May be called while playing or
+  // paused.  Buffers cannot be pushed in Initialized state.
+  virtual bool Stop() = 0;
+
+  // Pauses media playback.  Called only when in playing state.
+  virtual bool Pause() = 0;
+
+  // Resumes media playback.  Called only when in paused state.
+  virtual bool Resume() = 0;
+
+  // Gets the current playback timestamp in microseconds.
+  virtual int64_t GetCurrentPts() = 0;
+
+  // Sets the playback rate.  |rate| > 0.  If this is not called, a default rate
+  // of 1.0 is assumed. Returns true if successful.
+  virtual bool SetPlaybackRate(float rate) = 0;
 };
 
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_PIPELINE_DEVICE_FACTORY_H_
+#endif  // CHROMECAST_PUBLIC_MEDIA_MEDIA_PIPELINE_BACKEND_H_
diff --git a/chromecast/public/media/media_pipeline_device_params.h b/chromecast/public/media/media_pipeline_device_params.h
index fa7779b..b307dc4 100644
--- a/chromecast/public/media/media_pipeline_device_params.h
+++ b/chromecast/public/media/media_pipeline_device_params.h
@@ -5,9 +5,9 @@
 #ifndef CHROMECAST_PUBLIC_MEDIA_MEDIA_PIPELINE_DEVICE_PARAMS_H_
 #define CHROMECAST_PUBLIC_MEDIA_MEDIA_PIPELINE_DEVICE_PARAMS_H_
 
-#include "task_runner.h"
-
 namespace chromecast {
+class TaskRunner;
+
 namespace media {
 
 // Supplies creation parameters to platform-specific pipeline backend.
diff --git a/chromecast/public/media/video_pipeline_device.h b/chromecast/public/media/video_pipeline_device.h
deleted file mode 100644
index 1019ec3..0000000
--- a/chromecast/public/media/video_pipeline_device.h
+++ /dev/null
@@ -1,50 +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 CHROMECAST_PUBLIC_MEDIA_VIDEO_PIPELINE_DEVICE_H_
-#define CHROMECAST_PUBLIC_MEDIA_VIDEO_PIPELINE_DEVICE_H_
-
-#include "media_component_device.h"
-
-namespace chromecast {
-struct Size;
-
-namespace media {
-struct VideoConfig;
-
-// Interface for platform-specific video pipeline backend.
-// See comments on MediaComponentDevice.
-//
-// Notes:
-// - Like a regular MediaComponentDevice, frames are possibly rendered only
-//   in the kRunning state.
-//   However, the first frame must be rendered regardless of the clock state:
-//   - no synchronization needed to display the first frame,
-//   - the clock rate has no impact on the presentation of the first frame.
-class VideoPipelineDevice : public MediaComponentDevice {
- public:
-  // Callback interface for natural size of video changing.
-  class VideoClient {
-   public:
-    virtual ~VideoClient() {}
-    virtual void OnNaturalSizeChanged(const Size& size) = 0;
-  };
-
-  ~VideoPipelineDevice() override {}
-
-  // Registers |client| as the video specific event handler.
-  // Implementation takes ownership of |client|.
-  virtual void SetVideoClient(VideoClient* client) = 0;
-
-  // Provides the video configuration.
-  // Called before switching from |kStateUninitialized| to |kStateIdle|.
-  // Afterwards, this can be invoked any time the configuration changes.
-  // Returns true if the configuration is a supported configuration.
-  virtual bool SetConfig(const VideoConfig& config) = 0;
-};
-
-}  // namespace media
-}  // namespace chromecast
-
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_VIDEO_PIPELINE_DEVICE_H_
diff --git a/chromecast/renderer/media/BUILD.gn b/chromecast/renderer/media/BUILD.gn
index 6bbba52..38efe6a 100644
--- a/chromecast/renderer/media/BUILD.gn
+++ b/chromecast/renderer/media/BUILD.gn
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//testing/test.gni")
+
 source_set("media") {
   sources = [
     "audio_pipeline_proxy.cc",
@@ -12,6 +14,12 @@
     "chromecast_media_renderer_factory.h",
     "cma_message_filter_proxy.cc",
     "cma_message_filter_proxy.h",
+    "cma_renderer.cc",
+    "cma_renderer.h",
+    "demuxer_stream_adapter.cc",
+    "demuxer_stream_adapter.h",
+    "hole_frame_factory.cc",
+    "hole_frame_factory.h",
     "media_channel_proxy.cc",
     "media_channel_proxy.h",
     "media_pipeline_proxy.cc",
@@ -29,3 +37,24 @@
     "//media",
   ]
 }
+
+# GYP target: chromecast_tests.gypi:cast_renderer_media_unittests
+test("cast_renderer_media_unittests") {
+  sources = [
+    "demuxer_stream_adapter_unittest.cc",
+    "demuxer_stream_for_test.cc",
+    "demuxer_stream_for_test.h",
+    "multi_demuxer_stream_adapter_unittest.cc",
+  ]
+
+  deps = [
+    ":media",
+    "//base",
+    "//base/test:run_all_unittests",
+    "//base/test:test_support",
+    "//chromecast/media/cma/base",
+    "//chromecast/public/media",
+    "//media",
+    "//testing/gtest:gtest",
+  ]
+}
diff --git a/chromecast/renderer/media/DEPS b/chromecast/renderer/media/DEPS
new file mode 100644
index 0000000..9be0bc0
--- /dev/null
+++ b/chromecast/renderer/media/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+gpu",
+]
diff --git a/chromecast/renderer/media/audio_pipeline_proxy.cc b/chromecast/renderer/media/audio_pipeline_proxy.cc
index 0193232..ed76855 100644
--- a/chromecast/renderer/media/audio_pipeline_proxy.cc
+++ b/chromecast/renderer/media/audio_pipeline_proxy.cc
@@ -118,9 +118,8 @@
   VLOG_IF(4, !success) << "Sending msg failed";
 }
 
-void AudioPipelineProxyInternal::SetClient(
-    const base::Closure& pipe_read_cb,
-    const AvPipelineClient& client) {
+void AudioPipelineProxyInternal::SetClient(const base::Closure& pipe_read_cb,
+                                           const AvPipelineClient& client) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   CmaMessageFilterProxy::AudioDelegate delegate;
@@ -221,8 +220,7 @@
       base::Bind(&AudioPipelineProxyInternal::Release, base::Passed(&proxy_)));
 }
 
-void AudioPipelineProxy::SetClient(
-    const AvPipelineClient& client) {
+void AudioPipelineProxy::SetClient(const AvPipelineClient& client) {
   DCHECK(thread_checker_.CalledOnValidThread());
   base::Closure pipe_read_cb = ::media::BindToCurrentLoop(
       base::Bind(&AudioPipelineProxy::OnPipeRead, weak_this_));
@@ -306,4 +304,4 @@
 }
 
 }  // namespace cma
-}  // namespace chromecast
\ No newline at end of file
+}  // namespace chromecast
diff --git a/chromecast/renderer/media/audio_pipeline_proxy.h b/chromecast/renderer/media/audio_pipeline_proxy.h
index 7bcc685..87e0d18 100644
--- a/chromecast/renderer/media/audio_pipeline_proxy.h
+++ b/chromecast/renderer/media/audio_pipeline_proxy.h
@@ -11,7 +11,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread_checker.h"
 #include "chromecast/common/media/cma_ipc_common.h"
-#include "chromecast/media/cma/pipeline/audio_pipeline.h"
 #include "media/base/pipeline_status.h"
 
 namespace base {
@@ -26,16 +25,16 @@
 namespace chromecast {
 namespace media {
 class AudioPipelineProxyInternal;
-struct AvPipelineClient;
 class AvStreamerProxy;
 class CodedFrameProvider;
 class MediaChannelProxy;
+struct AvPipelineClient;
 
-class AudioPipelineProxy : public AudioPipeline {
+class AudioPipelineProxy {
  public:
   AudioPipelineProxy(scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
                      scoped_refptr<MediaChannelProxy> media_channel_proxy);
-  ~AudioPipelineProxy() override;
+  ~AudioPipelineProxy();
 
   void Initialize(
       const ::media::AudioDecoderConfig& config,
@@ -45,9 +44,8 @@
   void Flush(const base::Closure& done_cb);
   void Stop();
 
-  // AudioPipeline implementation.
-  void SetClient(const AvPipelineClient& client) override;
-  void SetVolume(float volume) override;
+  void SetClient(const AvPipelineClient& client);
+  void SetVolume(float volume);
 
  private:
   base::ThreadChecker thread_checker_;
@@ -75,4 +73,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_RENDERER_MEDIA_AUDIO_PIPELINE_PROXY_H_
\ No newline at end of file
+#endif  // CHROMECAST_RENDERER_MEDIA_AUDIO_PIPELINE_PROXY_H_
diff --git a/chromecast/renderer/media/chromecast_media_renderer_factory.cc b/chromecast/renderer/media/chromecast_media_renderer_factory.cc
index 3a43e91..5dc6b35 100644
--- a/chromecast/renderer/media/chromecast_media_renderer_factory.cc
+++ b/chromecast/renderer/media/chromecast_media_renderer_factory.cc
@@ -6,7 +6,7 @@
 
 #include "base/command_line.h"
 #include "chromecast/media/base/switching_media_renderer.h"
-#include "chromecast/media/cma/filters/cma_renderer.h"
+#include "chromecast/renderer/media/cma_renderer.h"
 #include "chromecast/renderer/media/media_pipeline_proxy.h"
 #include "content/public/renderer/render_thread.h"
 #include "media/base/audio_hardware_config.h"
@@ -34,7 +34,7 @@
     const scoped_refptr<base::TaskRunner>& worker_task_runner,
     ::media::AudioRendererSink* audio_renderer_sink,
     ::media::VideoRendererSink* video_renderer_sink) {
-  if (!default_render_factory_) {
+  if (!default_renderer_factory_) {
     // Chromecast doesn't have input audio devices, so leave this uninitialized
     ::media::AudioParameters input_audio_params;
     // TODO(servolk): Audio parameters are hardcoded for now, but in the future
@@ -52,26 +52,26 @@
     audio_config_.reset(new ::media::AudioHardwareConfig(input_audio_params,
                                                          output_audio_params));
 
-    default_render_factory_.reset(new ::media::DefaultRendererFactory(
+    default_renderer_factory_.reset(new ::media::DefaultRendererFactory(
         media_log_, /*gpu_factories*/ nullptr, *audio_config_));
   }
 
-  DCHECK(default_render_factory_);
+  DCHECK(default_renderer_factory_);
   // TODO(erickung): crbug.com/443956. Need to provide right LoadType.
   LoadType cma_load_type = kLoadTypeMediaSource;
-  scoped_ptr<MediaPipeline> cma_media_pipeline(
-      new MediaPipelineProxy(
-          render_frame_id_,
-          content::RenderThread::Get()->GetIOMessageLoopProxy(),
-          cma_load_type));
+  scoped_ptr<MediaPipelineProxy> cma_media_pipeline(new MediaPipelineProxy(
+      render_frame_id_,
+      content::RenderThread::Get()->GetIOMessageLoopProxy(),
+      cma_load_type));
   scoped_ptr<CmaRenderer> cma_renderer(new CmaRenderer(
       cma_media_pipeline.Pass(), video_renderer_sink, gpu_factories_));
-  scoped_ptr<::media::Renderer> default_media_render(
-      default_render_factory_->CreateRenderer(
-          media_task_runner, media_task_runner, audio_renderer_sink,
-          video_renderer_sink));
+  scoped_ptr<::media::Renderer> default_media_renderer(
+      default_renderer_factory_->CreateRenderer(media_task_runner,
+                                                media_task_runner,
+                                                audio_renderer_sink,
+                                                video_renderer_sink));
   scoped_ptr<SwitchingMediaRenderer> media_renderer(new SwitchingMediaRenderer(
-      default_media_render.Pass(), cma_renderer.Pass()));
+      default_media_renderer.Pass(), cma_renderer.Pass()));
   return media_renderer.Pass();
 }
 
diff --git a/chromecast/renderer/media/chromecast_media_renderer_factory.h b/chromecast/renderer/media/chromecast_media_renderer_factory.h
index d4da5127..76c884fe 100644
--- a/chromecast/renderer/media/chromecast_media_renderer_factory.h
+++ b/chromecast/renderer/media/chromecast_media_renderer_factory.h
@@ -38,7 +38,7 @@
   int render_frame_id_;
   scoped_refptr<::media::GpuVideoAcceleratorFactories> gpu_factories_;
   scoped_refptr<::media::MediaLog> media_log_;
-  scoped_ptr<::media::DefaultRendererFactory> default_render_factory_;
+  scoped_ptr<::media::DefaultRendererFactory> default_renderer_factory_;
 
   // Audio config for the default media renderer.
   scoped_ptr<::media::AudioHardwareConfig> audio_config_;
diff --git a/chromecast/media/cma/filters/cma_renderer.cc b/chromecast/renderer/media/cma_renderer.cc
similarity index 91%
rename from chromecast/media/cma/filters/cma_renderer.cc
rename to chromecast/renderer/media/cma_renderer.cc
index 1d9dadd..922f5c9 100644
--- a/chromecast/media/cma/filters/cma_renderer.cc
+++ b/chromecast/renderer/media/cma_renderer.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromecast/media/cma/filters/cma_renderer.h"
+#include "chromecast/renderer/media/cma_renderer.h"
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
@@ -11,14 +11,14 @@
 #include "base/thread_task_runner_handle.h"
 #include "chromecast/media/cma/base/balanced_media_task_runner_factory.h"
 #include "chromecast/media/cma/base/cma_logging.h"
-#include "chromecast/media/cma/filters/demuxer_stream_adapter.h"
-#include "chromecast/media/cma/filters/hole_frame_factory.h"
-#include "chromecast/media/cma/pipeline/audio_pipeline.h"
 #include "chromecast/media/cma/pipeline/av_pipeline_client.h"
-#include "chromecast/media/cma/pipeline/media_pipeline.h"
 #include "chromecast/media/cma/pipeline/media_pipeline_client.h"
-#include "chromecast/media/cma/pipeline/video_pipeline.h"
 #include "chromecast/media/cma/pipeline/video_pipeline_client.h"
+#include "chromecast/renderer/media/audio_pipeline_proxy.h"
+#include "chromecast/renderer/media/demuxer_stream_adapter.h"
+#include "chromecast/renderer/media/hole_frame_factory.h"
+#include "chromecast/renderer/media/media_pipeline_proxy.h"
+#include "chromecast/renderer/media/video_pipeline_proxy.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/demuxer_stream_provider.h"
 #include "media/base/pipeline_status.h"
@@ -34,15 +34,15 @@
 
 // Maximum difference between audio frame PTS and video frame PTS
 // for frames read from the DemuxerStream.
-const base::TimeDelta kMaxDeltaFetcher(
-    base::TimeDelta::FromMilliseconds(2000));
+const base::TimeDelta kMaxDeltaFetcher(base::TimeDelta::FromMilliseconds(2000));
 
-void MediaPipelineClientDummyCallback() {}
+void MediaPipelineClientDummyCallback() {
+}
 
 }  // namespace
 
 CmaRenderer::CmaRenderer(
-    scoped_ptr<MediaPipeline> media_pipeline,
+    scoped_ptr<MediaPipelineProxy> media_pipeline,
     ::media::VideoRendererSink* video_renderer_sink,
     const scoped_refptr<::media::GpuVideoAcceleratorFactories>& gpu_factories)
     : media_task_runner_factory_(
@@ -122,8 +122,8 @@
       base::Bind(&CmaRenderer::OnPlaybackTimeUpdated, weak_this_));
   media_pipeline_client.pipeline_backend_created_cb =
       base::Bind(&MediaPipelineClientDummyCallback);
-  media_pipeline_client.pipeline_backend_destroyed_cb
-      = base::Bind(&MediaPipelineClientDummyCallback);
+  media_pipeline_client.pipeline_backend_destroyed_cb =
+      base::Bind(&MediaPipelineClientDummyCallback);
   media_pipeline_->SetClient(media_pipeline_client);
 
   init_cb_ = init_cb;
@@ -144,9 +144,8 @@
   }
 
   DCHECK_EQ(state_, kPlaying) << state_;
-  media_pipeline_->Flush(
-      ::media::BindToCurrentLoop(
-          base::Bind(&CmaRenderer::OnFlushDone, weak_this_)));
+  media_pipeline_->Flush(::media::BindToCurrentLoop(
+      base::Bind(&CmaRenderer::OnFlushDone, weak_this_)));
 
   {
     base::AutoLock auto_lock(time_interpolator_lock_);
@@ -248,7 +247,8 @@
       demuxer_stream_provider_->GetStream(::media::DemuxerStream::AUDIO);
   ::media::PipelineStatusCB audio_initialization_done_cb =
       ::media::BindToCurrentLoop(
-          base::Bind(&CmaRenderer::OnAudioPipelineInitializeDone, weak_this_,
+          base::Bind(&CmaRenderer::OnAudioPipelineInitializeDone,
+                     weak_this_,
                      stream != nullptr));
   if (!stream) {
     CMALOG(kLogControl) << __FUNCTION__ << ": no audio stream, skipping init.";
@@ -260,8 +260,8 @@
   AvPipelineClient av_pipeline_client;
   av_pipeline_client.eos_cb = ::media::BindToCurrentLoop(
       base::Bind(&CmaRenderer::OnEosReached, weak_this_, true));
-  av_pipeline_client.playback_error_cb = ::media::BindToCurrentLoop(
-      base::Bind(&CmaRenderer::OnError, weak_this_));
+  av_pipeline_client.playback_error_cb =
+      ::media::BindToCurrentLoop(base::Bind(&CmaRenderer::OnError, weak_this_));
   av_pipeline_client.statistics_cb = ::media::BindToCurrentLoop(
       base::Bind(&CmaRenderer::OnStatisticsUpdated, weak_this_));
   audio_pipeline_->SetClient(av_pipeline_client);
@@ -307,7 +307,8 @@
       demuxer_stream_provider_->GetStream(::media::DemuxerStream::VIDEO);
   ::media::PipelineStatusCB video_initialization_done_cb =
       ::media::BindToCurrentLoop(
-          base::Bind(&CmaRenderer::OnVideoPipelineInitializeDone, weak_this_,
+          base::Bind(&CmaRenderer::OnVideoPipelineInitializeDone,
+                     weak_this_,
                      stream != nullptr));
   if (!stream) {
     CMALOG(kLogControl) << __FUNCTION__ << ": no video stream, skipping init.";
@@ -319,8 +320,8 @@
   VideoPipelineClient client;
   client.av_pipeline_client.eos_cb = ::media::BindToCurrentLoop(
       base::Bind(&CmaRenderer::OnEosReached, weak_this_, false));
-  client.av_pipeline_client.playback_error_cb = ::media::BindToCurrentLoop(
-      base::Bind(&CmaRenderer::OnError, weak_this_));
+  client.av_pipeline_client.playback_error_cb =
+      ::media::BindToCurrentLoop(base::Bind(&CmaRenderer::OnError, weak_this_));
   client.av_pipeline_client.statistics_cb = ::media::BindToCurrentLoop(
       base::Bind(&CmaRenderer::OnStatisticsUpdated, weak_this_));
   client.natural_size_changed_cb = ::media::BindToCurrentLoop(
@@ -339,9 +340,7 @@
   std::vector<::media::VideoDecoderConfig> configs;
   configs.push_back(config);
   media_pipeline_->InitializeVideo(
-      configs,
-      frame_provider.Pass(),
-      video_initialization_done_cb);
+      configs, frame_provider.Pass(), video_initialization_done_cb);
 }
 
 void CmaRenderer::OnVideoPipelineInitializeDone(
@@ -383,8 +382,7 @@
 
   bool audio_finished = !has_audio_ || received_audio_eos_;
   bool video_finished = !has_video_ || received_video_eos_;
-  CMALOG(kLogControl) << __FUNCTION__
-                      << " audio_finished=" << audio_finished
+  CMALOG(kLogControl) << __FUNCTION__ << " audio_finished=" << audio_finished
                       << " video_finished=" << video_finished;
   if (audio_finished && video_finished)
     ended_cb_.Run();
@@ -402,10 +400,9 @@
       hole_frame_factory_->CreateHoleFrame(size));
 }
 
-void CmaRenderer::OnPlaybackTimeUpdated(
-    base::TimeDelta time,
-    base::TimeDelta max_time,
-    base::TimeTicks capture_time) {
+void CmaRenderer::OnPlaybackTimeUpdated(base::TimeDelta time,
+                                        base::TimeDelta max_time,
+                                        base::TimeTicks capture_time) {
   DCHECK(thread_checker_.CalledOnValidThread());
   if (state_ != kPlaying) {
     LOG(WARNING) << "Ignoring a late time update";
diff --git a/chromecast/media/cma/filters/cma_renderer.h b/chromecast/renderer/media/cma_renderer.h
similarity index 82%
rename from chromecast/media/cma/filters/cma_renderer.h
rename to chromecast/renderer/media/cma_renderer.h
index f76226bd..85ad3687 100644
--- a/chromecast/media/cma/filters/cma_renderer.h
+++ b/chromecast/renderer/media/cma_renderer.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMECAST_MEDIA_CMA_FILTERS_CMA_RENDERER_H_
-#define CHROMECAST_MEDIA_CMA_FILTERS_CMA_RENDERER_H_
+#ifndef CHROMECAST_RENDERER_MEDIA_CMA_RENDERER_H_
+#define CHROMECAST_RENDERER_MEDIA_CMA_RENDERER_H_
 
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
@@ -29,29 +29,28 @@
 
 namespace chromecast {
 namespace media {
-class AudioPipeline;
+class AudioPipelineProxy;
 class BalancedMediaTaskRunnerFactory;
 class HoleFrameFactory;
-class MediaPipeline;
-class VideoPipeline;
+class MediaPipelineProxy;
+class VideoPipelineProxy;
 
 class CmaRenderer : public ::media::Renderer {
  public:
-  CmaRenderer(scoped_ptr<MediaPipeline> media_pipeline,
+  CmaRenderer(scoped_ptr<MediaPipelineProxy> media_pipeline,
               ::media::VideoRendererSink* video_renderer_sink,
               const scoped_refptr<::media::GpuVideoAcceleratorFactories>&
                   gpu_factories);
   ~CmaRenderer() override;
 
   // ::media::Renderer implementation:
-  void Initialize(
-      ::media::DemuxerStreamProvider* demuxer_stream_provider,
-      const ::media::PipelineStatusCB& init_cb,
-      const ::media::StatisticsCB& statistics_cb,
-      const ::media::BufferingStateCB& buffering_state_cb,
-      const base::Closure& ended_cb,
-      const ::media::PipelineStatusCB& error_cb,
-      const base::Closure& waiting_for_decryption_key_cb) override;
+  void Initialize(::media::DemuxerStreamProvider* demuxer_stream_provider,
+                  const ::media::PipelineStatusCB& init_cb,
+                  const ::media::StatisticsCB& statistics_cb,
+                  const ::media::BufferingStateCB& buffering_state_cb,
+                  const base::Closure& ended_cb,
+                  const ::media::PipelineStatusCB& error_cb,
+                  const base::Closure& waiting_for_decryption_key_cb) override;
   void Flush(const base::Closure& flush_cb) override;
   void StartPlayingFrom(base::TimeDelta time) override;
   void SetPlaybackRate(double playback_rate) override;
@@ -102,9 +101,9 @@
   base::ThreadChecker thread_checker_;
 
   scoped_refptr<BalancedMediaTaskRunnerFactory> media_task_runner_factory_;
-  scoped_ptr<MediaPipeline> media_pipeline_;
-  AudioPipeline* audio_pipeline_;
-  VideoPipeline* video_pipeline_;
+  scoped_ptr<MediaPipelineProxy> media_pipeline_;
+  AudioPipelineProxy* audio_pipeline_;
+  VideoPipelineProxy* video_pipeline_;
   ::media::VideoRendererSink* video_renderer_sink_;
 
   ::media::DemuxerStreamProvider* demuxer_stream_provider_;
@@ -143,7 +142,7 @@
 
   // Tracks the most recent media time update and provides interpolated values
   // as playback progresses.
-  scoped_ptr< ::media::TimeDeltaInterpolator> time_interpolator_;
+  scoped_ptr<::media::TimeDeltaInterpolator> time_interpolator_;
 
   double playback_rate_;
 
@@ -156,4 +155,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_FILTERS_CMA_RENDERER_H_
+#endif  // CHROMECAST_RENDERER_MEDIA_CMA_RENDERER_H_
diff --git a/chromecast/media/cma/filters/demuxer_stream_adapter.cc b/chromecast/renderer/media/demuxer_stream_adapter.cc
similarity index 98%
rename from chromecast/media/cma/filters/demuxer_stream_adapter.cc
rename to chromecast/renderer/media/demuxer_stream_adapter.cc
index 6c98da3..789827d3 100644
--- a/chromecast/media/cma/filters/demuxer_stream_adapter.cc
+++ b/chromecast/renderer/media/demuxer_stream_adapter.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromecast/media/cma/filters/demuxer_stream_adapter.h"
+#include "chromecast/renderer/media/demuxer_stream_adapter.h"
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
diff --git a/chromecast/media/cma/filters/demuxer_stream_adapter.h b/chromecast/renderer/media/demuxer_stream_adapter.h
similarity index 89%
rename from chromecast/media/cma/filters/demuxer_stream_adapter.h
rename to chromecast/renderer/media/demuxer_stream_adapter.h
index 5e8d817..7fbc7cdf 100644
--- a/chromecast/media/cma/filters/demuxer_stream_adapter.h
+++ b/chromecast/renderer/media/demuxer_stream_adapter.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMECAST_MEDIA_CMA_FILTERS_DEMUXER_STREAM_ADAPTER_H_
-#define CHROMECAST_MEDIA_CMA_FILTERS_DEMUXER_STREAM_ADAPTER_H_
+#ifndef CHROMECAST_RENDERER_MEDIA_DEMUXER_STREAM_ADAPTER_H_
+#define CHROMECAST_RENDERER_MEDIA_DEMUXER_STREAM_ADAPTER_H_
 
 #include "base/callback.h"
 #include "base/memory/scoped_ptr.h"
@@ -34,7 +34,7 @@
   DemuxerStreamAdapter(
       const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
       const scoped_refptr<BalancedMediaTaskRunnerFactory>&
-      media_task_runner_factory,
+          media_task_runner_factory,
       ::media::DemuxerStream* demuxer_stream);
   ~DemuxerStreamAdapter() override;
 
@@ -51,7 +51,7 @@
   // Callback invoked from the demuxer stream to signal a buffer is ready.
   void OnNewBuffer(const ReadCB& read_cb,
                    ::media::DemuxerStream::Status status,
-                   const scoped_refptr< ::media::DecoderBuffer>& input);
+                   const scoped_refptr<::media::DecoderBuffer>& input);
 
   base::ThreadChecker thread_checker_;
 
@@ -90,4 +90,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_FILTERS_DEMUXER_STREAM_ADAPTER_H_
+#endif  // CHROMECAST_RENDERER_MEDIA_DEMUXER_STREAM_ADAPTER_H_
diff --git a/chromecast/media/cma/filters/demuxer_stream_adapter_unittest.cc b/chromecast/renderer/media/demuxer_stream_adapter_unittest.cc
similarity index 85%
rename from chromecast/media/cma/filters/demuxer_stream_adapter_unittest.cc
rename to chromecast/renderer/media/demuxer_stream_adapter_unittest.cc
index 4657244..cc743084 100644
--- a/chromecast/media/cma/filters/demuxer_stream_adapter_unittest.cc
+++ b/chromecast/renderer/media/demuxer_stream_adapter_unittest.cc
@@ -13,9 +13,9 @@
 #include "base/time/time.h"
 #include "chromecast/media/cma/base/balanced_media_task_runner_factory.h"
 #include "chromecast/media/cma/base/decoder_buffer_base.h"
-#include "chromecast/media/cma/filters/demuxer_stream_adapter.h"
-#include "chromecast/media/cma/test/demuxer_stream_for_test.h"
 #include "chromecast/public/media/cast_decoder_buffer.h"
+#include "chromecast/renderer/media/demuxer_stream_adapter.h"
+#include "chromecast/renderer/media/demuxer_stream_for_test.h"
 #include "media/base/audio_decoder_config.h"
 #include "media/base/decoder_buffer.h"
 #include "media/base/demuxer_stream.h"
@@ -72,9 +72,10 @@
 
 void DemuxerStreamAdapterTest::Initialize(
     ::media::DemuxerStream* demuxer_stream) {
-  coded_frame_provider_.reset(new DemuxerStreamAdapter(
-      base::ThreadTaskRunnerHandle::Get(),
-      scoped_refptr<BalancedMediaTaskRunnerFactory>(), demuxer_stream));
+  coded_frame_provider_.reset(
+      new DemuxerStreamAdapter(base::ThreadTaskRunnerHandle::Get(),
+                               scoped_refptr<BalancedMediaTaskRunnerFactory>(),
+                               demuxer_stream));
 }
 
 void DemuxerStreamAdapterTest::Start() {
@@ -89,9 +90,8 @@
                  base::Unretained(this)),
       base::TimeDelta::FromSeconds(5));
 
-  coded_frame_provider_->Read(
-      base::Bind(&DemuxerStreamAdapterTest::OnNewFrame,
-                 base::Unretained(this)));
+  coded_frame_provider_->Read(base::Bind(&DemuxerStreamAdapterTest::OnNewFrame,
+                                         base::Unretained(this)));
 }
 
 void DemuxerStreamAdapterTest::OnTestTimeout() {
@@ -116,21 +116,18 @@
   frame_received_count_++;
 
   if (frame_received_count_ >= total_frames_) {
-    coded_frame_provider_->Flush(
-        base::Bind(&DemuxerStreamAdapterTest::OnFlushCompleted,
-                   base::Unretained(this)));
+    coded_frame_provider_->Flush(base::Bind(
+        &DemuxerStreamAdapterTest::OnFlushCompleted, base::Unretained(this)));
     return;
   }
 
-  coded_frame_provider_->Read(
-      base::Bind(&DemuxerStreamAdapterTest::OnNewFrame,
-                 base::Unretained(this)));
+  coded_frame_provider_->Read(base::Bind(&DemuxerStreamAdapterTest::OnNewFrame,
+                                         base::Unretained(this)));
 
   ASSERT_LE(frame_received_count_, early_flush_idx_);
   if (frame_received_count_ == early_flush_idx_) {
-    base::Closure flush_cb =
-        base::Bind(&DemuxerStreamAdapterTest::OnFlushCompleted,
-                   base::Unretained(this));
+    base::Closure flush_cb = base::Bind(
+        &DemuxerStreamAdapterTest::OnFlushCompleted, base::Unretained(this));
     if (use_post_task_for_flush_) {
       base::MessageLoop::current()->PostTask(
           FROM_HERE,
@@ -152,7 +149,7 @@
 
 TEST_F(DemuxerStreamAdapterTest, NoDelay) {
   total_frames_ = 10;
-  early_flush_idx_ = total_frames_;   // No early flush.
+  early_flush_idx_ = total_frames_;  // No early flush.
   total_expected_frames_ = 10;
   config_idx_.push_back(0);
   config_idx_.push_back(5);
@@ -172,7 +169,7 @@
 
 TEST_F(DemuxerStreamAdapterTest, AllDelayed) {
   total_frames_ = 10;
-  early_flush_idx_ = total_frames_;   // No early flush.
+  early_flush_idx_ = total_frames_;  // No early flush.
   total_expected_frames_ = 10;
   config_idx_.push_back(0);
   config_idx_.push_back(5);
diff --git a/chromecast/media/cma/test/demuxer_stream_for_test.cc b/chromecast/renderer/media/demuxer_stream_for_test.cc
similarity index 77%
rename from chromecast/media/cma/test/demuxer_stream_for_test.cc
rename to chromecast/renderer/media/demuxer_stream_for_test.cc
index 74e28ce..228f1de7 100644
--- a/chromecast/media/cma/test/demuxer_stream_for_test.cc
+++ b/chromecast/renderer/media/demuxer_stream_for_test.cc
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/threading/thread.h"
-#include "chromecast/media/cma/test/demuxer_stream_for_test.h"
+#include "chromecast/renderer/media/demuxer_stream_for_test.h"
 
 namespace chromecast {
 namespace media {
@@ -35,8 +35,9 @@
 
   if ((frame_count_ % cycle_count_) < delayed_frame_count_) {
     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-        FROM_HERE, base::Bind(&DemuxerStreamForTest::DoRead,
-                              base::Unretained(this), read_cb),
+        FROM_HERE,
+        base::Bind(
+            &DemuxerStreamForTest::DoRead, base::Unretained(this), read_cb),
         base::TimeDelta::FromMilliseconds(20));
     return;
   }
@@ -52,10 +53,16 @@
   gfx::Size coded_size(640, 480);
   gfx::Rect visible_rect(640, 480);
   gfx::Size natural_size(640, 480);
-  return ::media::VideoDecoderConfig(
-      ::media::kCodecH264, ::media::VIDEO_CODEC_PROFILE_UNKNOWN,
-      ::media::PIXEL_FORMAT_YV12, ::media::COLOR_SPACE_UNSPECIFIED, coded_size,
-      visible_rect, natural_size, NULL, 0, false);
+  return ::media::VideoDecoderConfig(::media::kCodecH264,
+                                     ::media::VIDEO_CODEC_PROFILE_UNKNOWN,
+                                     ::media::PIXEL_FORMAT_YV12,
+                                     ::media::COLOR_SPACE_UNSPECIFIED,
+                                     coded_size,
+                                     visible_rect,
+                                     natural_size,
+                                     NULL,
+                                     0,
+                                     false);
 }
 
 ::media::DemuxerStream::Type DemuxerStreamForTest::type() const {
diff --git a/chromecast/media/cma/test/demuxer_stream_for_test.h b/chromecast/renderer/media/demuxer_stream_for_test.h
similarity index 89%
rename from chromecast/media/cma/test/demuxer_stream_for_test.h
rename to chromecast/renderer/media/demuxer_stream_for_test.h
index afa7aae..20d8d41 100644
--- a/chromecast/media/cma/test/demuxer_stream_for_test.h
+++ b/chromecast/renderer/media/demuxer_stream_for_test.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMECAST_MEDIA_CMA_TEST_DUMMY_DEMUXER_STREAM_H_
-#define CHROMECAST_MEDIA_CMA_TEST_DUMMY_DEMUXER_STREAM_H_
+#ifndef CHROMECAST_RENDERER_MEDIA_DEMUXER_STREAM_FOR_TEST_H_
+#define CHROMECAST_RENDERER_MEDIA_DEMUXER_STREAM_FOR_TEST_H_
 
 #include <list>
 
 #include "base/bind.h"
 #include "base/thread_task_runner_handle.h"
-#include "chromecast/media/cma/filters/demuxer_stream_adapter.h"
+#include "chromecast/renderer/media/demuxer_stream_adapter.h"
 #include "media/base/decoder_buffer.h"
 #include "media/base/demuxer_stream.h"
 
@@ -71,4 +71,5 @@
 
 }  // namespace media
 }  // namespace chromecast
-#endif
+
+#endif  // CHROMECAST_RENDERER_MEDIA_DEMUXER_STREAM_FOR_TEST_H_
diff --git a/chromecast/media/cma/filters/hole_frame_factory.cc b/chromecast/renderer/media/hole_frame_factory.cc
similarity index 87%
rename from chromecast/media/cma/filters/hole_frame_factory.cc
rename to chromecast/renderer/media/hole_frame_factory.cc
index 4d4b333..6012439 100644
--- a/chromecast/media/cma/filters/hole_frame_factory.cc
+++ b/chromecast/renderer/media/hole_frame_factory.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromecast/media/cma/filters/hole_frame_factory.h"
+#include "chromecast/renderer/media/hole_frame_factory.h"
 
 #include "base/bind.h"
 #include "base/location.h"
@@ -16,18 +16,15 @@
 
 HoleFrameFactory::HoleFrameFactory(
     const scoped_refptr<::media::GpuVideoAcceleratorFactories>& gpu_factories)
-    : gpu_factories_(gpu_factories),
-      texture_(0),
-      image_id_(0),
-      sync_point_(0) {
+    : gpu_factories_(gpu_factories), texture_(0), image_id_(0), sync_point_(0) {
   if (gpu_factories_) {
     gpu::gles2::GLES2Interface* gl = gpu_factories_->GetGLES2Interface();
     CHECK(gl);
 
     gl->GenTextures(1, &texture_);
     gl->BindTexture(GL_TEXTURE_2D, texture_);
-    image_id_ = gl->CreateGpuMemoryBufferImageCHROMIUM(1, 1, GL_RGBA,
-                                                       GL_SCANOUT_CHROMIUM);
+    image_id_ = gl->CreateGpuMemoryBufferImageCHROMIUM(
+        1, 1, GL_RGBA, GL_SCANOUT_CHROMIUM);
     gl->BindTexImage2DCHROMIUM(GL_TEXTURE_2D, image_id_);
 
     gl->GenMailboxCHROMIUM(mailbox_.name);
diff --git a/chromecast/media/cma/filters/hole_frame_factory.h b/chromecast/renderer/media/hole_frame_factory.h
similarity index 86%
rename from chromecast/media/cma/filters/hole_frame_factory.h
rename to chromecast/renderer/media/hole_frame_factory.h
index c77fb6b..a937a58 100644
--- a/chromecast/media/cma/filters/hole_frame_factory.h
+++ b/chromecast/renderer/media/hole_frame_factory.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMECAST_MEDIA_CMA_FILTERS_HOLE_FRAME_FACTORY_H_
-#define CHROMECAST_MEDIA_CMA_FILTERS_HOLE_FRAME_FACTORY_H_
+#ifndef CHROMECAST_RENDERER_MEDIA_HOLE_FRAME_FACTORY_H_
+#define CHROMECAST_RENDERER_MEDIA_HOLE_FRAME_FACTORY_H_
 
 #include <GLES2/gl2.h>
 
@@ -46,4 +46,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_FILTERS_HOLE_FRAME_FACTORY_H_
+#endif  // CHROMECAST_RENDERER_MEDIA_HOLE_FRAME_FACTORY_H_
diff --git a/chromecast/renderer/media/media_pipeline_proxy.cc b/chromecast/renderer/media/media_pipeline_proxy.cc
index 38a69980..681d9eb 100644
--- a/chromecast/renderer/media/media_pipeline_proxy.cc
+++ b/chromecast/renderer/media/media_pipeline_proxy.cc
@@ -80,8 +80,7 @@
       CmaMessageFilterProxy::MediaDelegate());
 }
 
-void MediaPipelineProxyInternal::SetClient(
-    const MediaPipelineClient& client) {
+void MediaPipelineProxyInternal::SetClient(const MediaPipelineClient& client) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!client.error_cb.is_null());
   DCHECK(!client.buffering_state_cb.is_null());
@@ -185,8 +184,7 @@
       FROM_HERE, base::Bind(&MediaChannelProxy::Close, media_channel_proxy_));
 }
 
-void MediaPipelineProxy::SetClient(
-    const MediaPipelineClient& client) {
+void MediaPipelineProxy::SetClient(const MediaPipelineClient& client) {
   DCHECK(thread_checker_.CalledOnValidThread());
   FORWARD_ON_IO_THREAD(SetClient, client);
 }
@@ -196,11 +194,11 @@
   FORWARD_ON_IO_THREAD(SetCdm, render_frame_id_, cdm_id);
 }
 
-AudioPipeline* MediaPipelineProxy::GetAudioPipeline() const {
+AudioPipelineProxy* MediaPipelineProxy::GetAudioPipeline() const {
   return audio_pipeline_.get();
 }
 
-VideoPipeline* MediaPipelineProxy::GetVideoPipeline() const {
+VideoPipelineProxy* MediaPipelineProxy::GetVideoPipeline() const {
   return video_pipeline_.get();
 }
 
diff --git a/chromecast/renderer/media/media_pipeline_proxy.h b/chromecast/renderer/media/media_pipeline_proxy.h
index 1e8e9e6..71689d8 100644
--- a/chromecast/renderer/media/media_pipeline_proxy.h
+++ b/chromecast/renderer/media/media_pipeline_proxy.h
@@ -11,9 +11,10 @@
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread_checker.h"
 #include "chromecast/media/cma/pipeline/load_type.h"
-#include "chromecast/media/cma/pipeline/media_pipeline.h"
 #include "chromecast/media/cma/pipeline/media_pipeline_client.h"
+#include "media/base/audio_decoder_config.h"
 #include "media/base/serial_runner.h"
+#include "media/base/video_decoder_config.h"
 
 namespace base {
 class SingleThreadTaskRunner;
@@ -22,34 +23,32 @@
 namespace chromecast {
 namespace media {
 class AudioPipelineProxy;
+class CodedFrameProvider;
 class MediaChannelProxy;
 class MediaPipelineProxyInternal;
 class VideoPipelineProxy;
 
-class MediaPipelineProxy : public MediaPipeline {
+class MediaPipelineProxy {
  public:
   MediaPipelineProxy(int render_frame_id,
                      scoped_refptr<base::SingleThreadTaskRunner> task_runner,
                      LoadType load_type);
-  ~MediaPipelineProxy() override;
+  ~MediaPipelineProxy();
 
-  // MediaPipeline implementation.
-  void SetClient(const MediaPipelineClient& client) override;
-  void SetCdm(int cdm_id) override;
-  AudioPipeline* GetAudioPipeline() const override;
-  VideoPipeline* GetVideoPipeline() const override;
-  void InitializeAudio(
-      const ::media::AudioDecoderConfig& config,
-      scoped_ptr<CodedFrameProvider> frame_provider,
-      const ::media::PipelineStatusCB& status_cb) override;
-  void InitializeVideo(
-      const std::vector<::media::VideoDecoderConfig>& configs,
-      scoped_ptr<CodedFrameProvider> frame_provider,
-      const ::media::PipelineStatusCB& status_cb) override;
-  void StartPlayingFrom(base::TimeDelta time) override;
-  void Flush(const ::media::PipelineStatusCB& status_cb) override;
-  void Stop() override;
-  void SetPlaybackRate(double playback_rate) override;
+  void SetClient(const MediaPipelineClient& client);
+  void SetCdm(int cdm_id);
+  AudioPipelineProxy* GetAudioPipeline() const;
+  VideoPipelineProxy* GetVideoPipeline() const;
+  void InitializeAudio(const ::media::AudioDecoderConfig& config,
+                       scoped_ptr<CodedFrameProvider> frame_provider,
+                       const ::media::PipelineStatusCB& status_cb);
+  void InitializeVideo(const std::vector<::media::VideoDecoderConfig>& configs,
+                       scoped_ptr<CodedFrameProvider> frame_provider,
+                       const ::media::PipelineStatusCB& status_cb);
+  void StartPlayingFrom(base::TimeDelta time);
+  void Flush(const ::media::PipelineStatusCB& status_cb);
+  void Stop();
+  void SetPlaybackRate(double playback_rate);
 
  private:
   void OnProxyFlushDone(const ::media::PipelineStatusCB& status_cb,
diff --git a/chromecast/media/cma/filters/multi_demuxer_stream_adapter_unittest.cc b/chromecast/renderer/media/multi_demuxer_stream_adapter_unittest.cc
similarity index 86%
rename from chromecast/media/cma/filters/multi_demuxer_stream_adapter_unittest.cc
rename to chromecast/renderer/media/multi_demuxer_stream_adapter_unittest.cc
index ed5c519..4f878b44 100644
--- a/chromecast/media/cma/filters/multi_demuxer_stream_adapter_unittest.cc
+++ b/chromecast/renderer/media/multi_demuxer_stream_adapter_unittest.cc
@@ -12,9 +12,9 @@
 #include "base/time/time.h"
 #include "chromecast/media/cma/base/balanced_media_task_runner_factory.h"
 #include "chromecast/media/cma/base/decoder_buffer_base.h"
-#include "chromecast/media/cma/filters/demuxer_stream_adapter.h"
-#include "chromecast/media/cma/test/demuxer_stream_for_test.h"
 #include "chromecast/public/media/cast_decoder_buffer.h"
+#include "chromecast/renderer/media/demuxer_stream_adapter.h"
+#include "chromecast/renderer/media/demuxer_stream_for_test.h"
 #include "media/base/audio_decoder_config.h"
 #include "media/base/decoder_buffer.h"
 #include "media/base/demuxer_stream.h"
@@ -76,8 +76,9 @@
 
 void MultiDemuxerStreamAdaptersTest::Start() {
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, base::Bind(&MultiDemuxerStreamAdaptersTest::OnTestTimeout,
-                            base::Unretained(this)),
+      FROM_HERE,
+      base::Bind(&MultiDemuxerStreamAdaptersTest::OnTestTimeout,
+                 base::Unretained(this)),
       base::TimeDelta::FromSeconds(5));
 
   media_task_runner_factory_ = new BalancedMediaTaskRunnerFactory(
@@ -89,18 +90,20 @@
   for (auto& stream : demuxer_streams_) {
     coded_frame_providers_.push_back(make_scoped_ptr(
         new DemuxerStreamAdapter(base::ThreadTaskRunnerHandle::Get(),
-                                 media_task_runner_factory_, stream)));
+                                 media_task_runner_factory_,
+                                 stream)));
   }
   running_stream_count_ = coded_frame_providers_.size();
 
   // read each stream
   for (auto& code_frame_provider : coded_frame_providers_) {
     auto read_cb = base::Bind(&MultiDemuxerStreamAdaptersTest::OnNewFrame,
-                              base::Unretained(this), code_frame_provider);
+                              base::Unretained(this),
+                              code_frame_provider);
 
-    base::Closure task =
-        base::Bind(&CodedFrameProvider::Read,
-                   base::Unretained(code_frame_provider), read_cb);
+    base::Closure task = base::Bind(&CodedFrameProvider::Read,
+                                    base::Unretained(code_frame_provider),
+                                    read_cb);
 
     base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, task);
   }
@@ -124,7 +127,8 @@
 
   frame_received_count_++;
   auto read_cb = base::Bind(&MultiDemuxerStreamAdaptersTest::OnNewFrame,
-                            base::Unretained(this), frame_provider);
+                            base::Unretained(this),
+                            frame_provider);
   frame_provider->Read(read_cb);
 }
 
diff --git a/chromecast/renderer/media/video_pipeline_proxy.cc b/chromecast/renderer/media/video_pipeline_proxy.cc
index bcef083..b5931b1 100644
--- a/chromecast/renderer/media/video_pipeline_proxy.cc
+++ b/chromecast/renderer/media/video_pipeline_proxy.cc
@@ -17,6 +17,7 @@
 #include "chromecast/media/cma/base/coded_frame_provider.h"
 #include "chromecast/media/cma/ipc/media_message_fifo.h"
 #include "chromecast/media/cma/ipc_streamer/av_streamer_proxy.h"
+#include "chromecast/media/cma/pipeline/video_pipeline_client.h"
 #include "chromecast/renderer/media/cma_message_filter_proxy.h"
 #include "chromecast/renderer/media/media_channel_proxy.h"
 #include "media/base/bind_to_current_loop.h"
@@ -213,8 +214,7 @@
       base::Bind(&VideoPipelineProxyInternal::Release, base::Passed(&proxy_)));
 }
 
-void VideoPipelineProxy::SetClient(
-    const VideoPipelineClient& video_client) {
+void VideoPipelineProxy::SetClient(const VideoPipelineClient& video_client) {
   DCHECK(thread_checker_.CalledOnValidThread());
   base::Closure pipe_read_cb =
       ::media::BindToCurrentLoop(
@@ -294,4 +294,4 @@
 }
 
 }  // namespace media
-}  // namespace chromecast
\ No newline at end of file
+}  // namespace chromecast
diff --git a/chromecast/renderer/media/video_pipeline_proxy.h b/chromecast/renderer/media/video_pipeline_proxy.h
index e30be8c..1ec76c3 100644
--- a/chromecast/renderer/media/video_pipeline_proxy.h
+++ b/chromecast/renderer/media/video_pipeline_proxy.h
@@ -12,7 +12,6 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread_checker.h"
-#include "chromecast/media/cma/pipeline/video_pipeline.h"
 #include "media/base/pipeline_status.h"
 
 namespace base {
@@ -26,17 +25,17 @@
 
 namespace chromecast {
 namespace media {
-struct AvPipelineClient;
 class AvStreamerProxy;
 class CodedFrameProvider;
-class VideoPipelineProxyInternal;
 class MediaChannelProxy;
+struct VideoPipelineClient;
+class VideoPipelineProxyInternal;
 
-class VideoPipelineProxy : public VideoPipeline {
+class VideoPipelineProxy {
  public:
   VideoPipelineProxy(scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
                      scoped_refptr<MediaChannelProxy> media_channel_proxy);
-  ~VideoPipelineProxy() override;
+  ~VideoPipelineProxy();
 
   void Initialize(const std::vector<::media::VideoDecoderConfig>& configs,
                   scoped_ptr<CodedFrameProvider> frame_provider,
@@ -45,8 +44,7 @@
   void Flush(const base::Closure& done_cb);
   void Stop();
 
-  // VideoPipeline implementation.
-  void SetClient(const VideoPipelineClient& video_client) override;
+  void SetClient(const VideoPipelineClient& video_client);
 
  private:
   base::ThreadChecker thread_checker_;
diff --git a/components/autofill/core/browser/autofill_metrics.cc b/components/autofill/core/browser/autofill_metrics.cc
index 9f344987..7e2175b 100644
--- a/components/autofill/core/browser/autofill_metrics.cc
+++ b/components/autofill/core/browser/autofill_metrics.cc
@@ -643,8 +643,10 @@
 }
 
 // static
-void AutofillMetrics::LogAutomaticProfileCreation(bool created) {
-  UMA_HISTOGRAM_BOOLEAN("Autofill.AutomaticProfileCreation", created);
+void AutofillMetrics::LogProfileActionOnFormSubmitted(
+    AutofillProfileAction action) {
+  UMA_HISTOGRAM_ENUMERATION("Autofill.ProfileActionOnFormSubmitted", action,
+                            AUTOFILL_PROFILE_ACTION_ENUM_SIZE);
 }
 
 AutofillMetrics::FormEventLogger::FormEventLogger(bool is_for_credit_card)
diff --git a/components/autofill/core/browser/autofill_metrics.h b/components/autofill/core/browser/autofill_metrics.h
index 66301fb..cbdbcab 100644
--- a/components/autofill/core/browser/autofill_metrics.h
+++ b/components/autofill/core/browser/autofill_metrics.h
@@ -22,6 +22,13 @@
 
 class AutofillMetrics {
  public:
+  enum AutofillProfileAction {
+    EXISTING_PROFILE_USED,
+    EXISTING_PROFILE_UPDATED,
+    NEW_PROFILE_CREATED,
+    AUTOFILL_PROFILE_ACTION_ENUM_SIZE,
+  };
+
   enum DeveloperEngagementMetric {
     // Parsed a form that is potentially autofillable.
     FILLABLE_FORM_PARSED = 0,
@@ -579,9 +586,9 @@
   // This should be called each time a server response is parsed for a form.
   static void LogServerResponseHasDataForForm(bool has_data);
 
-  // This should be called at each form submission to indicate whether a new
-  // profile was created.
-  static void LogAutomaticProfileCreation(bool created);
+  // This should be called at each form submission to indicate what profile
+  // action happened.
+  static void LogProfileActionOnFormSubmitted(AutofillProfileAction action);
 
   // Utility to autofill form events in the relevant histograms depending on
   // the presence of server and/or local data.
diff --git a/components/autofill/core/browser/autofill_metrics_unittest.cc b/components/autofill/core/browser/autofill_metrics_unittest.cc
index a86162c..e4924b92 100644
--- a/components/autofill/core/browser/autofill_metrics_unittest.cc
+++ b/components/autofill/core/browser/autofill_metrics_unittest.cc
@@ -3073,8 +3073,8 @@
   }
 }
 
-// Verify that we correctly log metrics for profile creation on form submission.
-TEST_F(AutofillMetricsTest, AutomaticProfileCreation) {
+// Verify that we correctly log metrics for profile action on form submission.
+TEST_F(AutofillMetricsTest, ProfileActionOnFormSubmitted) {
   base::HistogramTester histogram_tester;
 
   // Load a fillable form.
@@ -3101,6 +3101,8 @@
   form.fields.push_back(field);
   test::CreateTestFormField("Zip", "zip", "", "text", &field);
   form.fields.push_back(field);
+  test::CreateTestFormField("Organization", "organization", "", "text", &field);
+  form.fields.push_back(field);
 
   std::vector<FormData> forms(1, form);
 
@@ -3112,6 +3114,10 @@
   FormData third_form = form;
   std::vector<FormData> third_forms(1, third_form);
 
+  // Fill a fourth form.
+  FormData fourth_form = form;
+  std::vector<FormData> fourth_forms(1, fourth_form);
+
   // Fill the field values for the first form submission.
   form.fields[0].value = ASCIIToUTF16("Albert Canuck");
   form.fields[1].value = ASCIIToUTF16("can@gmail.com");
@@ -3128,36 +3134,65 @@
   // Fill the field values for the third form submission.
   third_form.fields[0].value = ASCIIToUTF16("Jean-Paul Canuck");
   third_form.fields[1].value = ASCIIToUTF16("can2@gmail.com");
-  third_form.fields[2].value = ASCIIToUTF16("12345678901");
+  third_form.fields[2].value = ASCIIToUTF16("");
   third_form.fields[3].value = ASCIIToUTF16("1234 McGill street.");
   third_form.fields[4].value = ASCIIToUTF16("Montreal");
   third_form.fields[5].value = ASCIIToUTF16("Canada");
   third_form.fields[6].value = ASCIIToUTF16("Quebec");
   third_form.fields[7].value = ASCIIToUTF16("A1A 1A1");
 
-  // Expect to log true for the metric since a new profile is submitted.
+  // Fill the field values for the fourth form submission (same as third form
+  // plus phone info).
+  fourth_form.fields = third_form.fields;
+  fourth_form.fields[2].value = ASCIIToUTF16("12345678901");
+
+  // Expect to log NEW_PROFILE_CREATED for the metric since a new profile is
+  // submitted.
   autofill_manager_->OnFormsSeen(forms, TimeTicks::FromInternalValue(1));
   autofill_manager_->SubmitForm(form, TimeTicks::FromInternalValue(17));
-  histogram_tester.ExpectBucketCount("Autofill.AutomaticProfileCreation",
-                                     true, 1);
-  histogram_tester.ExpectBucketCount("Autofill.AutomaticProfileCreation",
-                                     false, 0);
+  histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted",
+                                     AutofillMetrics::NEW_PROFILE_CREATED, 1);
+  histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted",
+                                     AutofillMetrics::EXISTING_PROFILE_USED, 0);
+  histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted",
+                                     AutofillMetrics::EXISTING_PROFILE_UPDATED,
+                                     0);
 
-  // Expect to log false for the metric since the same profile is submitted.
+  // Expect to log EXISTING_PROFILE_USED for the metric since the same profile
+  // is submitted.
   autofill_manager_->OnFormsSeen(second_forms, TimeTicks::FromInternalValue(1));
   autofill_manager_->SubmitForm(second_form, TimeTicks::FromInternalValue(17));
-  histogram_tester.ExpectBucketCount("Autofill.AutomaticProfileCreation",
-                                     true, 1);
-  histogram_tester.ExpectBucketCount("Autofill.AutomaticProfileCreation",
-                                     false, 1);
+  histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted",
+                                     AutofillMetrics::NEW_PROFILE_CREATED, 1);
+  histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted",
+                                     AutofillMetrics::EXISTING_PROFILE_USED, 1);
+  histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted",
+                                     AutofillMetrics::EXISTING_PROFILE_UPDATED,
+                                     0);
 
-  // Expect to log true for the metric since a new profile is submitted.
+  // Expect to log NEW_PROFILE_CREATED for the metric since a new profile is
+  // submitted.
   autofill_manager_->OnFormsSeen(third_forms, TimeTicks::FromInternalValue(1));
   autofill_manager_->SubmitForm(third_form, TimeTicks::FromInternalValue(17));
-  histogram_tester.ExpectBucketCount("Autofill.AutomaticProfileCreation",
-                                     true, 2);
-  histogram_tester.ExpectBucketCount("Autofill.AutomaticProfileCreation",
-                                     false, 1);
+  histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted",
+                                     AutofillMetrics::NEW_PROFILE_CREATED, 2);
+  histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted",
+                                     AutofillMetrics::EXISTING_PROFILE_USED, 1);
+  histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted",
+                                     AutofillMetrics::EXISTING_PROFILE_UPDATED,
+                                     0);
+
+  // Expect to log EXISTING_PROFILE_UPDATED for the metric since the profile was
+  // updated.
+  autofill_manager_->OnFormsSeen(fourth_forms, TimeTicks::FromInternalValue(1));
+  autofill_manager_->SubmitForm(fourth_form, TimeTicks::FromInternalValue(17));
+  histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted",
+                                     AutofillMetrics::NEW_PROFILE_CREATED, 2);
+  histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted",
+                                     AutofillMetrics::EXISTING_PROFILE_USED, 1);
+  histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted",
+                                     AutofillMetrics::EXISTING_PROFILE_UPDATED,
+                                     1);
 }
 
 // Test class that shares setup code for testing ParseQueryResponse.
diff --git a/components/autofill/core/browser/autofill_profile.cc b/components/autofill/core/browser/autofill_profile.cc
index afa29f8..6dcd28b 100644
--- a/components/autofill/core/browser/autofill_profile.cc
+++ b/components/autofill/core/browser/autofill_profile.cc
@@ -24,6 +24,7 @@
 #include "components/autofill/core/browser/address_i18n.h"
 #include "components/autofill/core/browser/autofill_country.h"
 #include "components/autofill/core/browser/autofill_field.h"
+#include "components/autofill/core/browser/autofill_metrics.h"
 #include "components/autofill/core/browser/autofill_type.h"
 #include "components/autofill/core/browser/contact_info.h"
 #include "components/autofill/core/browser/phone_number.h"
@@ -478,12 +479,15 @@
   return true;
 }
 
-void AutofillProfile::OverwriteName(const NameInfo& imported_name,
+bool AutofillProfile::OverwriteName(const NameInfo& imported_name,
                                     const std::string& app_locale) {
   if (name_.ParsedNamesAreEqual(imported_name)) {
-    if (name_.GetRawInfo(NAME_FULL).empty())
+    if (name_.GetRawInfo(NAME_FULL).empty() &&
+        !imported_name.GetRawInfo(NAME_FULL).empty()) {
       name_.SetRawInfo(NAME_FULL, imported_name.GetRawInfo(NAME_FULL));
-    return;
+      return true;
+    }
+    return false;
   }
 
   l10n::CaseInsensitiveCompare compare;
@@ -501,13 +505,14 @@
     NameInfo heuristically_parsed_name;
     heuristically_parsed_name.SetInfo(type, full_name, app_locale);
     if (imported_name.ParsedNamesAreEqual(heuristically_parsed_name))
-      return;
+      return false;
   }
 
   name_ = imported_name;
+  return true;
 }
 
-void AutofillProfile::OverwriteWith(const AutofillProfile& profile,
+bool AutofillProfile::OverwriteWith(const AutofillProfile& profile,
                                     const std::string& app_locale) {
   // Verified profiles should never be overwritten with unverified data.
   DCHECK(!IsVerified() || profile.IsVerified());
@@ -543,18 +548,26 @@
     field_types.erase(ADDRESS_HOME_LINE2);
   }
 
-  for (const auto& iter : field_types) {
-    FieldTypeGroup group = AutofillType(iter).group();
+  bool did_overwrite = false;
+
+  for (ServerFieldTypeSet::const_iterator iter = field_types.begin();
+       iter != field_types.end(); ++iter) {
+    FieldTypeGroup group = AutofillType(*iter).group();
+
     // Special case names.
     if (group == NAME) {
-      OverwriteName(profile.name_, app_locale);
+      did_overwrite = OverwriteName(profile.name_, app_locale) || did_overwrite;
       continue;
     }
 
-    base::string16 new_value = profile.GetRawInfo(iter);
-    if (!compare.StringsEqual(GetRawInfo(iter), new_value))
-      SetRawInfo(iter, new_value);
+    base::string16 new_value = profile.GetRawInfo(*iter);
+    if (!compare.StringsEqual(GetRawInfo(*iter), new_value)) {
+      SetRawInfo(*iter, new_value);
+      did_overwrite = true;
+    }
   }
+
+  return did_overwrite;
 }
 
 bool AutofillProfile::SaveAdditionalInfo(const AutofillProfile& profile,
@@ -622,8 +635,15 @@
     }
   }
 
-  if (!IsVerified() || profile.IsVerified())
-    OverwriteWith(profile, app_locale);
+  if (!IsVerified() || profile.IsVerified()) {
+    if (OverwriteWith(profile, app_locale)) {
+      AutofillMetrics::LogProfileActionOnFormSubmitted(
+          AutofillMetrics::EXISTING_PROFILE_UPDATED);
+    } else {
+      AutofillMetrics::LogProfileActionOnFormSubmitted(
+          AutofillMetrics::EXISTING_PROFILE_USED);
+    }
+  }
   return true;
 }
 
diff --git a/components/autofill/core/browser/autofill_profile.h b/components/autofill/core/browser/autofill_profile.h
index d52f228c..bfe97b0a3 100644
--- a/components/autofill/core/browser/autofill_profile.h
+++ b/components/autofill/core/browser/autofill_profile.h
@@ -114,8 +114,9 @@
                              const std::string& app_locale,
                              const ServerFieldTypeSet& types) const;
 
-  // Overwrites the field data in |profile| with this Profile.
-  void OverwriteWith(const AutofillProfile& profile,
+  // Overwrites the field data in |profile| with this Profile. Returns |true| if
+  // at least one field was overwritten.
+  bool OverwriteWith(const AutofillProfile& profile,
                      const std::string& app_locale);
 
   // Saves info from |profile| into |this|, provided |this| and |profile| do not
@@ -223,7 +224,8 @@
   // If |name| has the same full name representation as |name_|,
   // this will keep the one that has more information (i.e.
   // is not reconstructible via a heuristic parse of the full name string).
-  void OverwriteName(const NameInfo& name, const std::string& app_locale);
+  // Returns |true| is |name_| was overwritten.
+  bool OverwriteName(const NameInfo& name, const std::string& app_locale);
 
   // Same as operator==, but ignores differences in GUID.
   bool EqualsSansGuid(const AutofillProfile& profile) const;
diff --git a/components/autofill/core/browser/autofill_profile_unittest.cc b/components/autofill/core/browser/autofill_profile_unittest.cc
index 59732c2..b092feb 100644
--- a/components/autofill/core/browser/autofill_profile_unittest.cc
+++ b/components/autofill/core/browser/autofill_profile_unittest.cc
@@ -66,6 +66,14 @@
   std::vector<NameParts> expected_result;
 };
 
+void SetupTestProfile(AutofillProfile& profile) {
+  profile.set_guid(base::GenerateGUID());
+  profile.set_origin("Chrome settings");
+  test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison",
+                       "marion@me.xyz", "Fox", "123 Zoo St.", "unit 5",
+                       "Hollywood", "CA", "91601", "US", "12345678910");
+}
+
 }  // namespace
 
 // Tests different possibilities for summary string generation.
@@ -830,12 +838,9 @@
   EXPECT_FALSE(a->IsSubsetOf(*b, "en-US"));
 }
 
-TEST(AutofillProfileTest, OverwriteWith) {
-  AutofillProfile a(base::GenerateGUID(), "https://www.example.com");
-  test::SetProfileInfo(&a, "Marion", "Mitchell", "Morrison",
-                       "marion@me.xyz", "Fox", "123 Zoo St.", "unit 5",
-                       "Hollywood", "CA", "91601", "US",
-                       "12345678910");
+TEST(AutofillProfileTest, OverwriteWith_DifferentProfile) {
+  AutofillProfile a;
+  SetupTestProfile(a);
 
   // Create an identical profile except that the new profile:
   //   (1) Has a different origin,
@@ -852,7 +857,7 @@
   b.SetRawInfo(NAME_FULL, ASCIIToUTF16("Marion M. Morrison"));
   b.set_language_code("en");
 
-  a.OverwriteWith(b, "en-US");
+  EXPECT_TRUE(a.OverwriteWith(b, "en-US"));
   EXPECT_EQ("Chrome settings", a.origin());
   EXPECT_EQ(ASCIIToUTF16("area 51"), a.GetRawInfo(ADDRESS_HOME_LINE2));
   EXPECT_EQ(ASCIIToUTF16("Fox"), a.GetRawInfo(COMPANY_NAME));
@@ -861,6 +866,37 @@
   EXPECT_EQ("en", a.language_code());
 }
 
+TEST(AutofillProfileTest, OverwriteWith_SameProfile) {
+  AutofillProfile a;
+  SetupTestProfile(a);
+
+  AutofillProfile b = a;
+  b.set_guid(base::GenerateGUID());
+  EXPECT_FALSE(a.OverwriteWith(b, "en-US"));
+}
+
+TEST(AutofillProfileTest, OverwriteWith_DifferentName) {
+  AutofillProfile a;
+  SetupTestProfile(a);
+
+  AutofillProfile b = a;
+  b.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Mario"));
+  EXPECT_TRUE(a.OverwriteWith(b, "en-US"));
+  base::string16 name_full = a.GetInfo(AutofillType(NAME_FULL), "en-US");
+  EXPECT_EQ(ASCIIToUTF16("Mario Mitchell Morrison"), name_full);
+}
+
+TEST(AutofillProfileTest, OverwriteWith_DifferentAddress) {
+  AutofillProfile a;
+  SetupTestProfile(a);
+
+  AutofillProfile b = a;
+  b.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("123 Aquarium St."));
+  EXPECT_TRUE(a.OverwriteWith(b, "en-US"));
+  base::string16 address = a.GetRawInfo(ADDRESS_HOME_LINE1);
+  EXPECT_EQ(ASCIIToUTF16("123 Aquarium St."), address);
+}
+
 TEST(AutofillProfileTest, AssignmentOperator) {
   AutofillProfile a(base::GenerateGUID(), "https://www.example.com/");
   test::SetProfileInfo(&a, "Marion", "Mitchell", "Morrison",
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index 7ebad6e..3047044 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -1058,10 +1058,11 @@
   }
 
   // If the new profile was not merged with an existing one, add it to the list.
-  if (!matching_profile_found)
+  if (!matching_profile_found) {
     merged_profiles->push_back(new_profile);
-
-  AutofillMetrics::LogAutomaticProfileCreation(!matching_profile_found);
+    AutofillMetrics::LogProfileActionOnFormSubmitted(
+        AutofillMetrics::NEW_PROFILE_CREATED);
+  }
 
   return guid;
 }
diff --git a/components/autofill/ios/browser/resources/autofill_controller.js b/components/autofill/ios/browser/resources/autofill_controller.js
index aa5cc46..d9b8e6c 100644
--- a/components/autofill/ios/browser/resources/autofill_controller.js
+++ b/components/autofill/ios/browser/resources/autofill_controller.js
@@ -505,11 +505,16 @@
       continue;
 
     var controlElement = controlElements[i];
-    var fieldLabel = formFields[fieldIdx]['label'];
-    if (!fieldLabel) {
-      formFields[fieldIdx]['label'] =
+    var currentField = formFields[fieldIdx];
+    if (!currentField['label']) {
+      currentField['label'] =
           __gCrWeb.autofill.inferLabelForElement(controlElement);
     }
+    if (currentField['label'].length > __gCrWeb.autofill.MAX_DATA_LENGTH) {
+      currentField['label'] =
+          currentField['label'].substr(0, __gCrWeb.autofill.MAX_DATA_LENGTH);
+    }
+
     if (controlElement === formControlElement)
       field = formFields[fieldIdx];
     ++fieldIdx;
@@ -911,6 +916,7 @@
   form['origin'] = __gCrWeb.common.removeQueryAndReferenceFromURL(
       frame.location.href);
   form['action'] = ''
+  form['is_form_tag'] = false;
 
   return formOrFieldsetsToFormData_(
       null /* formElement*/, null /* formControlElement */, fieldsets,
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index deef8dc..4bfe456b 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -589,6 +589,7 @@
       'scheduler/child/webthread_impl_for_worker_scheduler_unittest.cc',
       'scheduler/child/worker_scheduler_impl_unittest.cc',
       'scheduler/renderer/deadline_task_runner_unittest.cc',
+      'scheduler/renderer/idle_time_estimator_unittest.cc',
       'scheduler/renderer/renderer_scheduler_impl_unittest.cc',
       'scheduler/renderer/task_cost_estimator_unittest.cc',
       'scheduler/renderer/user_model_unittest.cc',
@@ -962,6 +963,7 @@
         'components.gyp:memory_pressure',
         'components.gyp:metrics',
         'components.gyp:metrics_net',
+        'components.gyp:metrics_profiler',
         'components.gyp:metrics_test_support',
         'components.gyp:metrics_ui',
         'components.gyp:net_log',
@@ -1109,7 +1111,6 @@
             'components.gyp:navigation_interception',
             'components.gyp:network_hints_renderer',
             'components.gyp:metrics_gpu',
-            'components.gyp:metrics_profiler',
             'components.gyp:page_load_metrics_browser',
             'components.gyp:page_load_metrics_renderer',
             'components.gyp:password_manager_content_browser',
@@ -1167,11 +1168,6 @@
             'webp_transcode/webp_decoder_unittest.mm',
             'webp_transcode/webp_network_client_unittest.mm',
           ],
-          'sources!': [
-            'metrics/gpu/gpu_metrics_provider_unittest.cc',
-            'metrics/profiler/profiler_metrics_provider_unittest.cc',
-            'metrics/profiler/tracking_synchronizer_unittest.cc',
-          ],
           'sources/': [
             # Exclude all tests that depends on //content (based on layered-
             # component directory structure).
diff --git a/components/cronet/android/cronet_url_request_context_adapter.cc b/components/cronet/android/cronet_url_request_context_adapter.cc
index b2af72c..37a18ce 100644
--- a/components/cronet/android/cronet_url_request_context_adapter.cc
+++ b/components/cronet/android/cronet_url_request_context_adapter.cc
@@ -249,6 +249,13 @@
   // TODO(mmenke):  Add method to have the builder enable SPDY.
   net::URLRequestContextBuilder context_builder;
 
+  // TODO(mef): Remove this work around for crbug.com/543366 once it is fixed.
+  net::URLRequestContextBuilder::HttpNetworkSessionParams
+      custom_http_network_session_params;
+  custom_http_network_session_params.use_alternative_services = false;
+  context_builder.set_http_network_session_params(
+      custom_http_network_session_params);
+
   net_log_.reset(new net::NetLog);
   scoped_ptr<net::NetworkDelegate> network_delegate(new BasicNetworkDelegate());
 #if defined(DATA_REDUCTION_PROXY_SUPPORT)
diff --git a/components/data_reduction_proxy/content/browser/data_reduction_proxy_debug_blocking_page.cc b/components/data_reduction_proxy/content/browser/data_reduction_proxy_debug_blocking_page.cc
index 54b5893a..e8e79c1 100644
--- a/components/data_reduction_proxy/content/browser/data_reduction_proxy_debug_blocking_page.cc
+++ b/components/data_reduction_proxy/content/browser/data_reduction_proxy_debug_blocking_page.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/lazy_instance.h"
+#include "base/location.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
diff --git a/components/data_reduction_proxy/content/browser/data_reduction_proxy_debug_ui_manager.cc b/components/data_reduction_proxy/content/browser/data_reduction_proxy_debug_ui_manager.cc
index 3189466..48097ef9e 100644
--- a/components/data_reduction_proxy/content/browser/data_reduction_proxy_debug_ui_manager.cc
+++ b/components/data_reduction_proxy/content/browser/data_reduction_proxy_debug_ui_manager.cc
@@ -7,6 +7,7 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/single_thread_task_runner.h"
 #include "base/time/time.h"
 #include "components/data_reduction_proxy/content/browser/data_reduction_proxy_debug_blocking_page.h"
diff --git a/components/metrics.gypi b/components/metrics.gypi
index 3b6695e..36e8e57 100644
--- a/components/metrics.gypi
+++ b/components/metrics.gypi
@@ -198,6 +198,31 @@
         'metrics/test_metrics_service_client.h',
       ],
     },
+    {
+      # GN version: //components/metrics:profiler
+      'target_name': 'metrics_profiler',
+      'type': 'static_library',
+      'include_dirs': [
+        '..',
+      ],
+      'dependencies': [
+        'component_metrics_proto',
+        'metrics',
+        'variations',
+      ],
+      'export_dependent_settings': [
+        'component_metrics_proto',
+      ],
+      'sources': [
+        'metrics/profiler/profiler_metrics_provider.cc',
+        'metrics/profiler/profiler_metrics_provider.h',
+        'metrics/profiler/tracking_synchronizer.cc',
+        'metrics/profiler/tracking_synchronizer.h',
+        'metrics/profiler/tracking_synchronizer_delegate.h',
+        'metrics/profiler/tracking_synchronizer_observer.cc',
+        'metrics/profiler/tracking_synchronizer_observer.h',
+      ],
+    },
   ],
   'conditions': [
     ['OS=="linux"', {
@@ -238,32 +263,43 @@
           ],
         },
         {
-          # GN version: //components/metrics:profiler
-          'target_name': 'metrics_profiler',
+          # GN version: //components/metrics:profiler_content
+          'target_name': 'metrics_profiler_content',
           'type': 'static_library',
           'include_dirs': [
             '..',
           ],
           'dependencies': [
+            '../base/base.gyp:base',
             '../content/content.gyp:content_browser',
             '../content/content.gyp:content_common',
-            'component_metrics_proto',
-            'metrics',
-            'variations',
-          ],
-          'export_dependent_settings': [
-            'component_metrics_proto',
+            'metrics_profiler',
           ],
           'sources': [
-            'metrics/profiler/profiler_metrics_provider.cc',
-            'metrics/profiler/profiler_metrics_provider.h',
-            'metrics/profiler/tracking_synchronizer.cc',
-            'metrics/profiler/tracking_synchronizer.h',
-            'metrics/profiler/tracking_synchronizer_observer.cc',
-            'metrics/profiler/tracking_synchronizer_observer.h',
+            'metrics/profiler/content/content_tracking_synchronizer_delegate.cc',
+            'metrics/profiler/content/content_tracking_synchronizer_delegate.h',
           ],
         },
       ],
-    }]
+    }, {  # OS==ios
+      'targets': [
+        {
+          # GN version: //components/metrics:profiler_ios
+          'target_name': 'metrics_profiler_ios',
+          'type': 'static_library',
+          'include_dirs': [
+            '..',
+          ],
+          'dependencies': [
+            '../base/base.gyp:base',
+            'metrics_profiler',
+          ],
+          'sources': [
+            'metrics/profiler/ios/ios_tracking_synchronizer_delegate.cc',
+            'metrics/profiler/ios/ios_tracking_synchronizer_delegate.h',
+          ],
+        },
+      ],
+    }],
   ],
 }
diff --git a/components/metrics/BUILD.gn b/components/metrics/BUILD.gn
index b6c7edb..6e0dc23 100644
--- a/components/metrics/BUILD.gn
+++ b/components/metrics/BUILD.gn
@@ -138,6 +138,27 @@
   ]
 }
 
+# GYP version: components/metrics.gypi:metrics_profiler
+source_set("profiler") {
+  sources = [
+    "profiler/profiler_metrics_provider.cc",
+    "profiler/profiler_metrics_provider.h",
+    "profiler/tracking_synchronizer.cc",
+    "profiler/tracking_synchronizer.h",
+    "profiler/tracking_synchronizer_delegate.h",
+    "profiler/tracking_synchronizer_observer.cc",
+    "profiler/tracking_synchronizer_observer.h",
+  ]
+
+  public_deps = [
+    ":metrics",
+  ]
+  deps = [
+    "//base",
+    "//components/variations",
+  ]
+}
+
 # GYP version: components/metrics.gypi:metrics_ui
 source_set("ui") {
   sources = [
@@ -155,27 +176,37 @@
 }
 
 if (!is_ios) {
-  # GYP version: components/metrics.gypi:metrics_profiler
-  source_set("profiler") {
+  # GYP version: components/metrics.gypi:metrics_profiler_content
+  source_set("profiler_content") {
     sources = [
-      "profiler/profiler_metrics_provider.cc",
-      "profiler/profiler_metrics_provider.h",
-      "profiler/tracking_synchronizer.cc",
-      "profiler/tracking_synchronizer.h",
-      "profiler/tracking_synchronizer_observer.cc",
-      "profiler/tracking_synchronizer_observer.h",
+      "profiler/content/content_tracking_synchronizer_delegate.cc",
+      "profiler/content/content_tracking_synchronizer_delegate.h",
     ]
 
     public_deps = [
-      ":metrics",
+      ":profiler",
     ]
     deps = [
       "//base",
-      "//components/variations",
       "//content/public/browser",
       "//content/public/common",
     ]
   }
+} else {
+  # GYP version: components/metrics.gypi:metrics_profiler_ios
+  source_set("profiler_ios") {
+    sources = [
+      "profiler/ios/ios_tracking_synchronizer_delegate.cc",
+      "profiler/ios/ios_tracking_synchronizer_delegate.h",
+    ]
+
+    public_deps = [
+      ":profiler",
+    ]
+    deps = [
+      "//base",
+    ]
+  }
 }
 
 # GYP version: components/metrics.gypi:metrics_test_support
@@ -233,6 +264,7 @@
   deps = [
     ":metrics",
     ":net",
+    ":profiler",
     ":test_support",
     ":ui",
     "//base:prefs_test_support",
@@ -241,17 +273,6 @@
     "//testing/gtest",
   ]
 
-  if (!is_ios) {
-    deps += [
-      "//content/public/common",
-      ":gpu",
-      ":profiler",
-    ]
-    sources += [
-      "profiler/profiler_metrics_provider_unittest.cc",
-      "profiler/tracking_synchronizer_unittest.cc",
-    ]
-  }
   if (is_linux) {
     sources += [ "serialization/serialization_utils_unittest.cc" ]
     deps += [ ":serialization" ]
diff --git a/components/metrics/profiler/DEPS b/components/metrics/profiler/content/DEPS
similarity index 100%
rename from components/metrics/profiler/DEPS
rename to components/metrics/profiler/content/DEPS
diff --git a/components/metrics/profiler/content/content_tracking_synchronizer_delegate.cc b/components/metrics/profiler/content/content_tracking_synchronizer_delegate.cc
new file mode 100644
index 0000000..afefdd6
--- /dev/null
+++ b/components/metrics/profiler/content/content_tracking_synchronizer_delegate.cc
@@ -0,0 +1,99 @@
+// Copyright 2015 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 "components/metrics/profiler/content/content_tracking_synchronizer_delegate.h"
+
+#include "components/metrics/profiler/tracking_synchronizer.h"
+#include "components/nacl/common/nacl_process_type.h"
+#include "content/public/browser/profiler_controller.h"
+#include "content/public/common/process_type.h"
+
+namespace metrics {
+
+namespace {
+
+ProfilerEventProto::TrackedObject::ProcessType AsProtobufProcessType(
+    int process_type) {
+  switch (process_type) {
+    case content::PROCESS_TYPE_BROWSER:
+      return ProfilerEventProto::TrackedObject::BROWSER;
+    case content::PROCESS_TYPE_RENDERER:
+      return ProfilerEventProto::TrackedObject::RENDERER;
+    case content::PROCESS_TYPE_PLUGIN:
+      return ProfilerEventProto::TrackedObject::PLUGIN;
+    case content::PROCESS_TYPE_UTILITY:
+      return ProfilerEventProto::TrackedObject::UTILITY;
+    case content::PROCESS_TYPE_ZYGOTE:
+      return ProfilerEventProto::TrackedObject::ZYGOTE;
+    case content::PROCESS_TYPE_SANDBOX_HELPER:
+      return ProfilerEventProto::TrackedObject::SANDBOX_HELPER;
+    case content::PROCESS_TYPE_GPU:
+      return ProfilerEventProto::TrackedObject::GPU;
+    case content::PROCESS_TYPE_PPAPI_PLUGIN:
+      return ProfilerEventProto::TrackedObject::PPAPI_PLUGIN;
+    case content::PROCESS_TYPE_PPAPI_BROKER:
+      return ProfilerEventProto::TrackedObject::PPAPI_BROKER;
+    case PROCESS_TYPE_NACL_LOADER:
+      return ProfilerEventProto::TrackedObject::NACL_LOADER;
+    case PROCESS_TYPE_NACL_BROKER:
+      return ProfilerEventProto::TrackedObject::NACL_BROKER;
+    default:
+      NOTREACHED();
+      return ProfilerEventProto::TrackedObject::UNKNOWN;
+  }
+}
+
+}  // namespace
+
+// static
+scoped_ptr<TrackingSynchronizerDelegate>
+ContentTrackingSynchronizerDelegate::Create(
+    TrackingSynchronizer* synchronizer) {
+  return make_scoped_ptr(new ContentTrackingSynchronizerDelegate(synchronizer));
+}
+
+ContentTrackingSynchronizerDelegate::ContentTrackingSynchronizerDelegate(
+    TrackingSynchronizer* synchronizer)
+    : synchronizer_(synchronizer) {
+  DCHECK(synchronizer_);
+  content::ProfilerController::GetInstance()->Register(this);
+}
+
+ContentTrackingSynchronizerDelegate::~ContentTrackingSynchronizerDelegate() {
+  content::ProfilerController::GetInstance()->Unregister(this);
+}
+
+void ContentTrackingSynchronizerDelegate::GetProfilerDataForChildProcesses(
+    int sequence_number,
+    int current_profiling_phase) {
+  // Get profiler data from renderer and browser child processes.
+  content::ProfilerController::GetInstance()->GetProfilerData(
+      sequence_number, current_profiling_phase);
+}
+
+void ContentTrackingSynchronizerDelegate::OnProfilingPhaseCompleted(
+    int profiling_phase) {
+  // Notify renderer and browser child processes.
+  content::ProfilerController::GetInstance()->OnProfilingPhaseCompleted(
+      profiling_phase);
+}
+
+void ContentTrackingSynchronizerDelegate::OnPendingProcesses(
+    int sequence_number,
+    int pending_processes,
+    bool end) {
+  // Notify |synchronizer_|.
+  synchronizer_->OnPendingProcesses(sequence_number, pending_processes, end);
+}
+
+void ContentTrackingSynchronizerDelegate::OnProfilerDataCollected(
+    int sequence_number,
+    const tracked_objects::ProcessDataSnapshot& profiler_data,
+    content::ProcessType process_type) {
+  // Notify |synchronizer_|.
+  synchronizer_->OnProfilerDataCollected(sequence_number, profiler_data,
+                                         AsProtobufProcessType(process_type));
+}
+
+}  // namespace metrics
diff --git a/components/metrics/profiler/content/content_tracking_synchronizer_delegate.h b/components/metrics/profiler/content/content_tracking_synchronizer_delegate.h
new file mode 100644
index 0000000..ee75c92
--- /dev/null
+++ b/components/metrics/profiler/content/content_tracking_synchronizer_delegate.h
@@ -0,0 +1,52 @@
+// Copyright 2015 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 COMPONENTS_METRICS_PROFILER_CONTENT_CONTENT_TRACKING_SYNCHRONIZER_DELEGATE_H_
+#define COMPONENTS_METRICS_PROFILER_CONTENT_CONTENT_TRACKING_SYNCHRONIZER_DELEGATE_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "components/metrics/profiler/tracking_synchronizer_delegate.h"
+#include "content/public/browser/profiler_subscriber.h"
+
+namespace metrics {
+
+// Provides an implementation of TrackingSynchronizerDelegate for use on
+// //content-based platforms. Specifically, drives the tracking of profiler data
+// for child processes by interacting with content::ProfilerController.
+class ContentTrackingSynchronizerDelegate : public TrackingSynchronizerDelegate,
+                                            public content::ProfilerSubscriber {
+ public:
+  ~ContentTrackingSynchronizerDelegate() override;
+
+  // Creates a ContentTrackingSynchronizerDelegate that is associated with
+  // |synchronizer_|.
+  static scoped_ptr<TrackingSynchronizerDelegate> Create(
+      TrackingSynchronizer* synchronizer);
+
+ private:
+  ContentTrackingSynchronizerDelegate(TrackingSynchronizer* synchronizer);
+
+  // TrackingSynchronizerDelegate:
+  void GetProfilerDataForChildProcesses(int sequence_number,
+                                        int current_profiling_phase) override;
+  void OnProfilingPhaseCompleted(int profiling_phase) override;
+
+  // content::ProfilerSubscriber:
+  void OnPendingProcesses(int sequence_number,
+                          int pending_processes,
+                          bool end) override;
+  void OnProfilerDataCollected(
+      int sequence_number,
+      const tracked_objects::ProcessDataSnapshot& profiler_data,
+      content::ProcessType process_type) override;
+
+  TrackingSynchronizer* synchronizer_;
+
+  DISALLOW_COPY_AND_ASSIGN(ContentTrackingSynchronizerDelegate);
+};
+
+}  // namespace metrics
+
+#endif  // COMPONENTS_METRICS_PROFILER_CONTENT_CONTENT_TRACKING_SYNCHRONIZER_DELEGATE_H_
diff --git a/components/metrics/profiler/ios/ios_tracking_synchronizer_delegate.cc b/components/metrics/profiler/ios/ios_tracking_synchronizer_delegate.cc
new file mode 100644
index 0000000..881d92f
--- /dev/null
+++ b/components/metrics/profiler/ios/ios_tracking_synchronizer_delegate.cc
@@ -0,0 +1,35 @@
+// Copyright 2015 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 "components/metrics/profiler/ios/ios_tracking_synchronizer_delegate.h"
+#include "components/metrics/profiler/tracking_synchronizer.h"
+
+namespace metrics {
+
+// static
+scoped_ptr<TrackingSynchronizerDelegate>
+IOSTrackingSynchronizerDelegate::Create(TrackingSynchronizer* synchronizer) {
+  return make_scoped_ptr(new IOSTrackingSynchronizerDelegate(synchronizer));
+}
+
+IOSTrackingSynchronizerDelegate::IOSTrackingSynchronizerDelegate(
+    TrackingSynchronizer* synchronizer)
+    : synchronizer_(synchronizer) {
+  DCHECK(synchronizer_);
+}
+
+IOSTrackingSynchronizerDelegate::~IOSTrackingSynchronizerDelegate() {}
+
+void IOSTrackingSynchronizerDelegate::GetProfilerDataForChildProcesses(
+    int sequence_number,
+    int current_profiling_phase) {
+  // Notify |synchronizer_| that there are no processes pending (on iOS, there
+  // is only the browser process).
+  synchronizer_->OnPendingProcesses(sequence_number, 0, true);
+}
+
+void IOSTrackingSynchronizerDelegate::OnProfilingPhaseCompleted(
+    int profiling_phase) {}
+
+}  // namespace metrics
diff --git a/components/metrics/profiler/ios/ios_tracking_synchronizer_delegate.h b/components/metrics/profiler/ios/ios_tracking_synchronizer_delegate.h
new file mode 100644
index 0000000..dbdd265
--- /dev/null
+++ b/components/metrics/profiler/ios/ios_tracking_synchronizer_delegate.h
@@ -0,0 +1,40 @@
+// Copyright 2015 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 COMPONENTS_METRICS_PROFILER_IOS_IOS_TRACKING_SYNCHRONIZER_DELEGATE_H_
+#define COMPONENTS_METRICS_PROFILER_IOS_IOS_TRACKING_SYNCHRONIZER_DELEGATE_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "components/metrics/profiler/tracking_synchronizer_delegate.h"
+
+namespace metrics {
+
+// Provides an implementation of TrackingSynchronizerDelegate for usage on iOS.
+// This implementation is minimal, as on iOS there are no child processes.
+class IOSTrackingSynchronizerDelegate : public TrackingSynchronizerDelegate {
+ public:
+  ~IOSTrackingSynchronizerDelegate() override;
+
+  // Creates an IOSTrackingSynchronizerDelegate that is associated with
+  // |synchronizer_|.
+  static scoped_ptr<TrackingSynchronizerDelegate> Create(
+      TrackingSynchronizer* synchronizer);
+
+ private:
+  IOSTrackingSynchronizerDelegate(TrackingSynchronizer* synchronizer);
+
+  // TrackingSynchronizerDelegate:
+  void GetProfilerDataForChildProcesses(int sequence_number,
+                                        int current_profiling_phase) override;
+  void OnProfilingPhaseCompleted(int profiling_phase) override;
+
+  TrackingSynchronizer* synchronizer_;
+
+  DISALLOW_COPY_AND_ASSIGN(IOSTrackingSynchronizerDelegate);
+};
+
+}  // namespace metrics
+
+#endif  // COMPONENTS_METRICS_PROFILER_IOS_IOS_TRACKING_SYNCHRONIZER_DELEGATE_H_
diff --git a/components/metrics/profiler/tracking_synchronizer.cc b/components/metrics/profiler/tracking_synchronizer.cc
index 18baee1..caf088b 100644
--- a/components/metrics/profiler/tracking_synchronizer.cc
+++ b/components/metrics/profiler/tracking_synchronizer.cc
@@ -10,10 +10,7 @@
 #include "base/threading/thread.h"
 #include "base/tracked_objects.h"
 #include "components/metrics/profiler/tracking_synchronizer_observer.h"
-#include "components/nacl/common/nacl_process_type.h"
 #include "components/variations/variations_associated_data.h"
-#include "content/public/browser/profiler_controller.h"
-#include "content/public/common/process_type.h"
 
 using base::TimeTicks;
 
@@ -35,37 +32,6 @@
 // from the UI thread, or for about:profiler.
 static TrackingSynchronizer* g_tracking_synchronizer = NULL;
 
-ProfilerEventProto::TrackedObject::ProcessType AsProtobufProcessType(
-    int process_type) {
-  switch (process_type) {
-    case content::PROCESS_TYPE_BROWSER:
-      return ProfilerEventProto::TrackedObject::BROWSER;
-    case content::PROCESS_TYPE_RENDERER:
-      return ProfilerEventProto::TrackedObject::RENDERER;
-    case content::PROCESS_TYPE_PLUGIN:
-      return ProfilerEventProto::TrackedObject::PLUGIN;
-    case content::PROCESS_TYPE_UTILITY:
-      return ProfilerEventProto::TrackedObject::UTILITY;
-    case content::PROCESS_TYPE_ZYGOTE:
-      return ProfilerEventProto::TrackedObject::ZYGOTE;
-    case content::PROCESS_TYPE_SANDBOX_HELPER:
-      return ProfilerEventProto::TrackedObject::SANDBOX_HELPER;
-    case content::PROCESS_TYPE_GPU:
-      return ProfilerEventProto::TrackedObject::GPU;
-    case content::PROCESS_TYPE_PPAPI_PLUGIN:
-      return ProfilerEventProto::TrackedObject::PPAPI_PLUGIN;
-    case content::PROCESS_TYPE_PPAPI_BROKER:
-      return ProfilerEventProto::TrackedObject::PPAPI_BROKER;
-    case PROCESS_TYPE_NACL_LOADER:
-      return ProfilerEventProto::TrackedObject::NACL_LOADER;
-    case PROCESS_TYPE_NACL_BROKER:
-      return ProfilerEventProto::TrackedObject::NACL_BROKER;
-    default:
-      NOTREACHED();
-      return ProfilerEventProto::TrackedObject::UNKNOWN;
-  }
-}
-
 }  // namespace
 
 // The "RequestContext" structure describes an individual request received
@@ -209,27 +175,18 @@
 
 // TrackingSynchronizer methods and members.
 
-TrackingSynchronizer::TrackingSynchronizer(scoped_ptr<base::TickClock> clock)
+TrackingSynchronizer::TrackingSynchronizer(
+    scoped_ptr<base::TickClock> clock,
+    const TrackingSynchronizerDelegateFactory& delegate_factory)
     : last_used_sequence_number_(kNeverUsableSequenceNumber),
       clock_(clock.Pass()) {
   DCHECK(!g_tracking_synchronizer);
   g_tracking_synchronizer = this;
   phase_start_times_.push_back(clock_->NowTicks());
-
-#if !defined(OS_IOS)
-  // TODO: This ifdef and other ifdefs for OS_IOS in this file are only
-  // short-term hacks to make this compile on iOS, and the proper solution is to
-  // refactor to remove content dependencies from shared code.
-  // See crbug/472210.
-  content::ProfilerController::GetInstance()->Register(this);
-#endif
+  delegate_ = delegate_factory.Run(this);
 }
 
 TrackingSynchronizer::~TrackingSynchronizer() {
-#if !defined(OS_IOS)
-  content::ProfilerController::GetInstance()->Unregister(this);
-#endif
-
   // Just in case we have any pending tasks, clear them out.
   RequestContext::OnShutdown();
 
@@ -283,10 +240,10 @@
 void TrackingSynchronizer::OnProfilerDataCollected(
     int sequence_number,
     const tracked_objects::ProcessDataSnapshot& profiler_data,
-    content::ProcessType process_type) {
+    ProfilerEventProto::TrackedObject::ProcessType process_type) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DecrementPendingProcessesAndSendData(sequence_number, profiler_data,
-                                       AsProtobufProcessType(process_type));
+                                       process_type);
 }
 
 int TrackingSynchronizer::RegisterAndNotifyAllProcesses(
@@ -303,17 +260,8 @@
 
   const int current_profiling_phase = phase_completion_events_sequence_.size();
 
-#if !defined(OS_IOS)
-  // Get profiler data from renderer and browser child processes.
-  content::ProfilerController::GetInstance()->GetProfilerData(
-      sequence_number, current_profiling_phase);
-#else
-  // On non-iOS platforms, |OnPendingProcesses()| is called from
-  // |content::ProfilerController|. On iOS, manually call the method to indicate
-  // that there is no need to wait for data from child processes. On iOS, there
-  // is only the main browser process.
-  OnPendingProcesses(sequence_number, 0, true);
-#endif  // !defined(OS_IOS)
+  delegate_->GetProfilerDataForChildProcesses(sequence_number,
+                                              current_profiling_phase);
 
   // Send process data snapshot from browser process.
   tracked_objects::ProcessDataSnapshot process_data_snapshot;
@@ -352,11 +300,7 @@
 
   RegisterPhaseCompletion(profiling_event);
 
-#if !defined(OS_IOS)
-  // Notify renderer and browser child processes.
-  content::ProfilerController::GetInstance()->OnProfilingPhaseCompleted(
-      profiling_phase);
-#endif
+  delegate_->OnProfilingPhaseCompleted(profiling_phase);
 
   // Notify browser process.
   tracked_objects::ThreadData::OnProfilingPhaseCompleted(profiling_phase);
diff --git a/components/metrics/profiler/tracking_synchronizer.h b/components/metrics/profiler/tracking_synchronizer.h
index 9e3bf3d..f4691c56 100644
--- a/components/metrics/profiler/tracking_synchronizer.h
+++ b/components/metrics/profiler/tracking_synchronizer.h
@@ -10,14 +10,16 @@
 #include <vector>
 
 #include "base/basictypes.h"
+#include "base/callback.h"
 #include "base/lazy_instance.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread_checker.h"
 #include "base/time/tick_clock.h"
 #include "base/time/time.h"
+#include "base/tracked_objects.h"
+#include "components/metrics/profiler/tracking_synchronizer_delegate.h"
 #include "components/metrics/proto/chrome_user_metrics_extension.pb.h"
-#include "content/public/browser/profiler_subscriber.h"
 
 // This class maintains state that is used to upload profiler data from the
 // various processes, into the browser process. Such transactions are usually
@@ -38,16 +40,21 @@
 
 class TrackingSynchronizerObserver;
 
+typedef base::Callback<scoped_ptr<TrackingSynchronizerDelegate>(
+    TrackingSynchronizer*)> TrackingSynchronizerDelegateFactory;
+
 class TrackingSynchronizer
-    : public content::ProfilerSubscriber,
-      public base::RefCountedThreadSafe<TrackingSynchronizer> {
+    : public base::RefCountedThreadSafe<TrackingSynchronizer> {
  public:
   // Construction also sets up the global singleton instance. This instance is
   // used to communicate between the IO and UI thread, and is destroyed only as
   // the main thread (browser_main) terminates, which means the IO thread has
   // already completed, and will not need this instance any further.
   // |clock| is a clock used for durations of profiling phases.
-  explicit TrackingSynchronizer(scoped_ptr<base::TickClock> clock);
+  // |delegate| is used to abstract platform-specific profiling functionality.
+  TrackingSynchronizer(
+      scoped_ptr<base::TickClock> clock,
+      const TrackingSynchronizerDelegateFactory& delegate_factory);
 
   // Contact all processes, and get them to upload to the browser any/all
   // changes to profiler data. It calls |callback_object|'s SetData method with
@@ -62,18 +69,21 @@
   static void OnProfilingPhaseCompleted(
       ProfilerEventProto::ProfilerEvent profiling_event);
 
-  // ------------------------------------------------------
-  // ProfilerSubscriber methods for browser child processes
-  // ------------------------------------------------------
+  // Send profiler_data back to |callback_object_| by calling
+  // DecrementPendingProcessesAndSendData which records that we are waiting
+  // for one less profiler data from renderer or browser child process for the
+  // given sequence number. This method is accessible on UI thread.
+  void OnProfilerDataCollected(
+      int sequence_number,
+      const tracked_objects::ProcessDataSnapshot& profiler_data,
+      ProfilerEventProto::TrackedObject::ProcessType process_type);
 
   // Update the number of pending processes for the given |sequence_number|.
   // This is called on UI thread.
-  void OnPendingProcesses(int sequence_number,
-                          int pending_processes,
-                          bool end) override;
+  void OnPendingProcesses(int sequence_number, int pending_processes, bool end);
 
  protected:
-  ~TrackingSynchronizer() override;
+  virtual ~TrackingSynchronizer();
 
   // Update the sequence of completed phases with a new phase completion info.
   void RegisterPhaseCompletion(
@@ -90,15 +100,6 @@
 
   class RequestContext;
 
-  // Send profiler_data back to callback_object_ by calling
-  // DecrementPendingProcessesAndSendData which records that we are waiting
-  // for one less profiler data from renderer or browser child process for the
-  // given sequence number. This method is accessible on UI thread.
-  void OnProfilerDataCollected(
-      int sequence_number,
-      const tracked_objects::ProcessDataSnapshot& profiler_data,
-      content::ProcessType process_type) override;
-
   // Establish a new sequence_number_, and use it to notify all the processes of
   // the need to supply, to the browser, their tracking data. It also registers
   // |callback_object| in |outstanding_requests_| map. Return the
@@ -152,6 +153,11 @@
   // index in the vector is the phase number.
   std::vector<base::TimeTicks> phase_start_times_;
 
+  // This object's delegate.
+  // NOTE: Leave this ivar last so that the delegate is torn down first at
+  // destruction, as it has a reference to this object.
+  scoped_ptr<TrackingSynchronizerDelegate> delegate_;
+
   DISALLOW_COPY_AND_ASSIGN(TrackingSynchronizer);
 };
 
diff --git a/components/metrics/profiler/tracking_synchronizer_delegate.h b/components/metrics/profiler/tracking_synchronizer_delegate.h
new file mode 100644
index 0000000..ec57d2b7
--- /dev/null
+++ b/components/metrics/profiler/tracking_synchronizer_delegate.h
@@ -0,0 +1,32 @@
+// Copyright 2015 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 COMPONENTS_METRICS_PROFILER_TRACKING_SYNCHRONIZER_DELEGATE_H_
+#define COMPONENTS_METRICS_PROFILER_TRACKING_SYNCHRONIZER_DELEGATE_H_
+
+#include "base/basictypes.h"
+
+namespace metrics {
+
+class TrackingSynchronizer;
+
+// An abstraction of TrackingSynchronizer-related operations that depend on the
+// platform.
+class TrackingSynchronizerDelegate {
+ public:
+  virtual ~TrackingSynchronizerDelegate() {}
+
+  // Should perform the platform-specific action that is needed to start
+  // gathering profiler data for all relevant child processes.
+  virtual void GetProfilerDataForChildProcesses(
+      int sequence_number,
+      int current_profiling_phase) = 0;
+
+  // Called when |profiling_phase| has completed.
+  virtual void OnProfilingPhaseCompleted(int profiling_phase) = 0;
+};
+
+}  // namespace metrics
+
+#endif  // COMPONENTS_METRICS_PROFILER_TRACKING_SYNCHRONIZER_DELEGATE_H_
diff --git a/components/metrics/profiler/tracking_synchronizer_unittest.cc b/components/metrics/profiler/tracking_synchronizer_unittest.cc
index d60880e..a199bd8 100644
--- a/components/metrics/profiler/tracking_synchronizer_unittest.cc
+++ b/components/metrics/profiler/tracking_synchronizer_unittest.cc
@@ -2,12 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/bind.h"
 #include "base/memory/ref_counted.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "base/tracked_objects.h"
 #include "components/metrics/profiler/tracking_synchronizer.h"
+#include "components/metrics/profiler/tracking_synchronizer_delegate.h"
 #include "components/metrics/profiler/tracking_synchronizer_observer.h"
-#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using tracked_objects::ProcessDataPhaseSnapshot;
@@ -17,6 +18,24 @@
 
 namespace {
 
+class TestDelegate : public TrackingSynchronizerDelegate {
+ public:
+  ~TestDelegate() override {}
+
+  static scoped_ptr<TrackingSynchronizerDelegate> Create(
+      TrackingSynchronizer* synchronizer) {
+    return make_scoped_ptr(new TestDelegate());
+  }
+
+ private:
+  TestDelegate() {}
+
+  // TrackingSynchronizerDelegate:
+  void GetProfilerDataForChildProcesses(int sequence_number,
+                                        int current_profiling_phase) override {}
+  void OnProfilingPhaseCompleted(int profiling_phase) override {}
+};
+
 class TestObserver : public TrackingSynchronizerObserver {
  public:
   TestObserver() {}
@@ -82,7 +101,7 @@
 class TestTrackingSynchronizer : public TrackingSynchronizer {
  public:
   explicit TestTrackingSynchronizer(scoped_ptr<base::TickClock> clock)
-      : TrackingSynchronizer(clock.Pass()) {}
+      : TrackingSynchronizer(clock.Pass(), base::Bind(&TestDelegate::Create)) {}
 
   using TrackingSynchronizer::RegisterPhaseCompletion;
   using TrackingSynchronizer::SendData;
@@ -95,10 +114,6 @@
 
 TEST(TrackingSynchronizerTest, ProfilerData) {
   // Testing how TrackingSynchronizer reports 2 phases of profiling.
-#if !defined(OS_IOS)
-  content::TestBrowserThreadBundle thread_bundle;
-#endif
-
   auto clock = new base::SimpleTestTickClock();  // Will be owned by
                                                  // |tracking_synchronizer|.
   clock->Advance(base::TimeDelta::FromMilliseconds(111));
diff --git a/components/nacl/browser/test_nacl_browser_delegate.cc b/components/nacl/browser/test_nacl_browser_delegate.cc
index 3dbb7e105..dfa61d2 100644
--- a/components/nacl/browser/test_nacl_browser_delegate.cc
+++ b/components/nacl/browser/test_nacl_browser_delegate.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/callback.h"
 #include "components/nacl/browser/test_nacl_browser_delegate.h"
 
 TestNaClBrowserDelegate::TestNaClBrowserDelegate() {}
diff --git a/components/password_manager/core/browser/password_store_default_unittest.cc b/components/password_manager/core/browser/password_store_default_unittest.cc
index 1d8a899..53080d9 100644
--- a/components/password_manager/core/browser/password_store_default_unittest.cc
+++ b/components/password_manager/core/browser/password_store_default_unittest.cc
@@ -113,10 +113,15 @@
   }
 
   scoped_refptr<PasswordStoreDefault> CreateInitializedStore() {
+    return CreateInitializedStore(
+        make_scoped_ptr(new LoginDatabase(test_login_db_file_path())));
+  }
+
+  scoped_refptr<PasswordStoreDefault> CreateInitializedStore(
+      scoped_ptr<LoginDatabase> database) {
     scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
         base::ThreadTaskRunnerHandle::Get(),
-        base::ThreadTaskRunnerHandle::Get(),
-        make_scoped_ptr(new LoginDatabase(test_login_db_file_path()))));
+        base::ThreadTaskRunnerHandle::Get(), database.Pass()));
     store->Init(syncer::SyncableService::StartSyncFlare());
 
     return store;
@@ -131,10 +136,7 @@
 }
 
 TEST_F(PasswordStoreDefaultTest, NonASCIIData) {
-  scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
-      base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get(),
-      make_scoped_ptr(new LoginDatabase(test_login_db_file_path()))));
-  store->Init(syncer::SyncableService::StartSyncFlare());
+  scoped_refptr<PasswordStoreDefault> store = CreateInitializedStore();
 
   // Some non-ASCII password form data.
   static const PasswordFormData form_data[] = {
@@ -174,10 +176,7 @@
 }
 
 TEST_F(PasswordStoreDefaultTest, Notifications) {
-  scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
-      base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get(),
-      make_scoped_ptr(new LoginDatabase(test_login_db_file_path()))));
-  store->Init(syncer::SyncableService::StartSyncFlare());
+  scoped_refptr<PasswordStoreDefault> store = CreateInitializedStore();
 
   scoped_ptr<PasswordForm> form =
       CreatePasswordFormFromDataForTesting(CreateTestPasswordFormData());
@@ -229,11 +228,9 @@
 // explosions, but fail without side effect, return no data and trigger no
 // notifications.
 TEST_F(PasswordStoreDefaultTest, OperationsOnABadDatabaseSilentlyFail) {
-  scoped_refptr<PasswordStoreDefault> bad_store(new PasswordStoreDefault(
-      base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get(),
-      make_scoped_ptr<LoginDatabase>(new BadLoginDatabase)));
+  scoped_refptr<PasswordStoreDefault> bad_store =
+      CreateInitializedStore(make_scoped_ptr(new BadLoginDatabase));
 
-  bad_store->Init(syncer::SyncableService::StartSyncFlare());
   base::MessageLoop::current()->RunUntilIdle();
   ASSERT_EQ(nullptr, bad_store->login_db());
 
@@ -278,9 +275,11 @@
   // Delete one login; a range of logins.
   bad_store->RemoveLogin(*form);
   base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop run_loop;
   bad_store->RemoveLoginsCreatedBetween(base::Time(), base::Time::Max(),
-                                        base::Closure());
-  base::MessageLoop::current()->RunUntilIdle();
+                                        run_loop.QuitClosure());
+  run_loop.Run();
+
   bad_store->RemoveLoginsSyncedBetween(base::Time(), base::Time::Max());
   base::MessageLoop::current()->RunUntilIdle();
 
diff --git a/components/scheduler/renderer/idle_time_estimator.cc b/components/scheduler/renderer/idle_time_estimator.cc
new file mode 100644
index 0000000..5d572a2
--- /dev/null
+++ b/components/scheduler/renderer/idle_time_estimator.cc
@@ -0,0 +1,73 @@
+// Copyright 2015 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 "components/scheduler/renderer/idle_time_estimator.h"
+
+#include "base/time/default_tick_clock.h"
+
+namespace scheduler {
+
+IdleTimeEstimator::IdleTimeEstimator(
+    const scoped_refptr<TaskQueue>& compositor_task_runner,
+    int sample_count,
+    double estimation_percentile)
+    : compositor_task_runner_(compositor_task_runner),
+      per_frame_compositor_task_runtime_(sample_count),
+      time_source_(new base::DefaultTickClock),
+      estimation_percentile_(estimation_percentile),
+      nesting_level_(0),
+      did_commit_(false) {
+  compositor_task_runner_->AddTaskObserver(this);
+}
+
+IdleTimeEstimator::~IdleTimeEstimator() {
+  compositor_task_runner_->RemoveTaskObserver(this);
+}
+
+base::TimeDelta IdleTimeEstimator::GetExpectedIdleDuration(
+    base::TimeDelta compositor_frame_interval) const {
+  base::TimeDelta expected_compositor_task_runtime_ =
+      per_frame_compositor_task_runtime_.Percentile(estimation_percentile_);
+  return std::max(base::TimeDelta(), compositor_frame_interval -
+                                         expected_compositor_task_runtime_);
+}
+
+void IdleTimeEstimator::DidCommitFrameToCompositor() {
+  // This will run inside of a WillProcessTask / DidProcessTask pair, let
+  // DidProcessTask know a frame was comitted.
+  did_commit_ = true;
+}
+
+void IdleTimeEstimator::Clear() {
+  task_start_time_ = base::TimeTicks();
+  prev_commit_time_ = base::TimeTicks();
+  cumulative_compositor_runtime_ = base::TimeDelta();
+  per_frame_compositor_task_runtime_.Clear();
+  did_commit_ = false;
+}
+
+void IdleTimeEstimator::SetTimeSourceForTesting(
+    scoped_ptr<base::TickClock> time_source) {
+  time_source_ = time_source.Pass();
+}
+
+void IdleTimeEstimator::WillProcessTask(const base::PendingTask& pending_task) {
+  nesting_level_++;
+  task_start_time_ = time_source_->NowTicks();
+}
+
+void IdleTimeEstimator::DidProcessTask(const base::PendingTask& pending_task) {
+  DCHECK_EQ(nesting_level_, 1);
+  cumulative_compositor_runtime_ += time_source_->NowTicks() - task_start_time_;
+
+  if (did_commit_) {
+    per_frame_compositor_task_runtime_.InsertSample(
+        cumulative_compositor_runtime_);
+    cumulative_compositor_runtime_ = base::TimeDelta();
+    did_commit_ = false;
+  }
+  nesting_level_--;
+}
+
+}  // namespace scheduler
diff --git a/components/scheduler/renderer/idle_time_estimator.h b/components/scheduler/renderer/idle_time_estimator.h
new file mode 100644
index 0000000..4b69915
--- /dev/null
+++ b/components/scheduler/renderer/idle_time_estimator.h
@@ -0,0 +1,58 @@
+// Copyright 2015 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 COMPONENTS_SCHEDULER_RENDERER_IDLE_TIME_ESTIMATOR_H_
+#define COMPONENTS_SCHEDULER_RENDERER_IDLE_TIME_ESTIMATOR_H_
+
+#include "base/message_loop/message_loop.h"
+#include "base/time/tick_clock.h"
+#include "cc/base/rolling_time_delta_history.h"
+#include "components/scheduler/base/task_queue.h"
+#include "components/scheduler/scheduler_export.h"
+
+namespace scheduler {
+
+// Estimates how much idle time there is available.
+class SCHEDULER_EXPORT IdleTimeEstimator
+    : public base::MessageLoop::TaskObserver {
+ public:
+  IdleTimeEstimator(const scoped_refptr<TaskQueue>& compositor_task_runner,
+                    int sample_count,
+                    double estimation_percentile);
+
+  ~IdleTimeEstimator() override;
+
+  // Expected Idle time is defined as: |compositor_frame_interval| minus
+  // expected compositor task duration.
+  base::TimeDelta GetExpectedIdleDuration(
+      base::TimeDelta compositor_frame_interval) const;
+
+  void DidCommitFrameToCompositor();
+
+  void Clear();
+
+  // TaskObserver implementation:
+  void WillProcessTask(const base::PendingTask& pending_task) override;
+  void DidProcessTask(const base::PendingTask& pending_task) override;
+
+  void SetTimeSourceForTesting(scoped_ptr<base::TickClock> time_source);
+
+ private:
+  scoped_refptr<TaskQueue> compositor_task_runner_;
+  cc::RollingTimeDeltaHistory per_frame_compositor_task_runtime_;
+  scoped_ptr<base::TickClock> time_source_;
+  double estimation_percentile_;
+
+  base::TimeTicks task_start_time_;
+  base::TimeTicks prev_commit_time_;
+  base::TimeDelta cumulative_compositor_runtime_;
+  int nesting_level_;
+  bool did_commit_;
+
+  DISALLOW_COPY_AND_ASSIGN(IdleTimeEstimator);
+};
+
+}  // namespace scheduler
+
+#endif  // COMPONENTS_SCHEDULER_RENDERER_IDLE_TIME_ESTIMATOR_H_
diff --git a/components/scheduler/renderer/idle_time_estimator_unittest.cc b/components/scheduler/renderer/idle_time_estimator_unittest.cc
new file mode 100644
index 0000000..8f349443
--- /dev/null
+++ b/components/scheduler/renderer/idle_time_estimator_unittest.cc
@@ -0,0 +1,146 @@
+// Copyright 2015 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 "components/scheduler/renderer/idle_time_estimator.h"
+
+#include "base/test/simple_test_tick_clock.h"
+#include "cc/test/ordered_simple_task_runner.h"
+#include "components/scheduler/base/task_queue_manager.h"
+#include "components/scheduler/base/test_time_source.h"
+#include "components/scheduler/child/scheduler_task_runner_delegate_for_test.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace scheduler {
+
+class IdleTimeEstimatorForTest : public IdleTimeEstimator {
+ public:
+  IdleTimeEstimatorForTest(
+      const scoped_refptr<TaskQueue>& compositor_task_runner,
+      base::SimpleTestTickClock* clock,
+      int sample_count,
+      double estimation_percentile)
+      : IdleTimeEstimator(compositor_task_runner,
+                          sample_count,
+                          estimation_percentile) {
+    SetTimeSourceForTesting(make_scoped_ptr(new TestTimeSource(clock)));
+  }
+};
+
+class IdleTimeEstimatorTest : public testing::Test {
+ public:
+  IdleTimeEstimatorTest()
+      : frame_length_(base::TimeDelta::FromMilliseconds(16)) {}
+
+  ~IdleTimeEstimatorTest() override {}
+
+  void SetUp() override {
+    clock_.reset(new base::SimpleTestTickClock());
+    clock_->Advance(base::TimeDelta::FromMicroseconds(5000));
+    mock_task_runner_ = make_scoped_refptr(
+        new cc::OrderedSimpleTaskRunner(clock_.get(), false));
+    main_task_runner_ =
+        SchedulerTaskRunnerDelegateForTest::Create(mock_task_runner_);
+    manager_ = make_scoped_ptr(new TaskQueueManager(
+        main_task_runner_, "test.scheduler", "test.scheduler.debug"));
+    compositor_task_runner_ =
+        manager_->NewTaskQueue(TaskQueue::Spec("compositor_tq"));
+    estimator_.reset(new IdleTimeEstimatorForTest(compositor_task_runner_,
+                                                  clock_.get(), 10, 50));
+  }
+
+  void SimulateFrameWithOneCompositorTask(int compositor_time) {
+    base::TimeDelta non_idle_time =
+        base::TimeDelta::FromMilliseconds(compositor_time);
+    base::PendingTask task(FROM_HERE, base::Closure());
+    estimator_->WillProcessTask(task);
+    clock_->Advance(non_idle_time);
+    estimator_->DidCommitFrameToCompositor();
+    estimator_->DidProcessTask(task);
+    if (non_idle_time < frame_length_)
+      clock_->Advance(frame_length_ - non_idle_time);
+  }
+
+  void SimulateFrameWithTwoCompositorTasks(int compositor_time1,
+                                           int compositor_time2) {
+    base::TimeDelta non_idle_time1 =
+        base::TimeDelta::FromMilliseconds(compositor_time1);
+    base::TimeDelta non_idle_time2 =
+        base::TimeDelta::FromMilliseconds(compositor_time2);
+    base::PendingTask task(FROM_HERE, base::Closure());
+    estimator_->WillProcessTask(task);
+    clock_->Advance(non_idle_time1);
+    estimator_->DidProcessTask(task);
+
+    estimator_->WillProcessTask(task);
+    clock_->Advance(non_idle_time2);
+    estimator_->DidCommitFrameToCompositor();
+    estimator_->DidProcessTask(task);
+
+    base::TimeDelta idle_time = frame_length_ - non_idle_time1 - non_idle_time2;
+    clock_->Advance(idle_time);
+  }
+
+  scoped_ptr<base::SimpleTestTickClock> clock_;
+  scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_;
+  scoped_refptr<SchedulerTaskRunnerDelegate> main_task_runner_;
+  scoped_ptr<TaskQueueManager> manager_;
+  scoped_refptr<TaskQueue> compositor_task_runner_;
+  scoped_ptr<IdleTimeEstimatorForTest> estimator_;
+  const base::TimeDelta frame_length_;
+};
+
+TEST_F(IdleTimeEstimatorTest, InitialTimeEstimateWithNoData) {
+  EXPECT_EQ(frame_length_, estimator_->GetExpectedIdleDuration(frame_length_));
+}
+
+TEST_F(IdleTimeEstimatorTest, BasicEstimation_SteadyState) {
+  SimulateFrameWithOneCompositorTask(5);
+  SimulateFrameWithOneCompositorTask(5);
+
+  EXPECT_EQ(base::TimeDelta::FromMilliseconds(11),
+            estimator_->GetExpectedIdleDuration(frame_length_));
+}
+
+TEST_F(IdleTimeEstimatorTest, BasicEstimation_Variable) {
+  SimulateFrameWithOneCompositorTask(5);
+  SimulateFrameWithOneCompositorTask(6);
+  SimulateFrameWithOneCompositorTask(7);
+  SimulateFrameWithOneCompositorTask(7);
+  SimulateFrameWithOneCompositorTask(7);
+  SimulateFrameWithOneCompositorTask(8);
+
+  // We expect it to return the median.
+  EXPECT_EQ(base::TimeDelta::FromMilliseconds(9),
+            estimator_->GetExpectedIdleDuration(frame_length_));
+}
+
+TEST_F(IdleTimeEstimatorTest, NoIdleTime) {
+  SimulateFrameWithOneCompositorTask(100);
+  SimulateFrameWithOneCompositorTask(100);
+
+  EXPECT_EQ(base::TimeDelta::FromMilliseconds(0),
+            estimator_->GetExpectedIdleDuration(frame_length_));
+}
+
+TEST_F(IdleTimeEstimatorTest, Clear) {
+  SimulateFrameWithOneCompositorTask(5);
+  SimulateFrameWithOneCompositorTask(5);
+
+  EXPECT_EQ(base::TimeDelta::FromMilliseconds(11),
+            estimator_->GetExpectedIdleDuration(frame_length_));
+  estimator_->Clear();
+
+  EXPECT_EQ(frame_length_, estimator_->GetExpectedIdleDuration(frame_length_));
+}
+
+TEST_F(IdleTimeEstimatorTest, Estimation_MultipleTasks) {
+  SimulateFrameWithTwoCompositorTasks(1, 4);
+  SimulateFrameWithTwoCompositorTasks(1, 4);
+
+  EXPECT_EQ(base::TimeDelta::FromMilliseconds(11),
+            estimator_->GetExpectedIdleDuration(frame_length_));
+}
+
+}  // namespace scheduler
diff --git a/components/scheduler/renderer/renderer_scheduler_impl.cc b/components/scheduler/renderer/renderer_scheduler_impl.cc
index f122501..7189f984 100644
--- a/components/scheduler/renderer/renderer_scheduler_impl.cc
+++ b/components/scheduler/renderer/renderer_scheduler_impl.cc
@@ -20,7 +20,7 @@
 const int kTimerTaskEstimationSampleCount = 200;
 const double kTimerTaskEstimationPercentile = 90;
 const int kShortIdlePeriodDurationSampleCount = 10;
-const double kShortIdlePeriodDurationPercentile = 20;
+const double kShortIdlePeriodDurationPercentile = 50;
 }
 
 RendererSchedulerImpl::RendererSchedulerImpl(
@@ -43,6 +43,7 @@
           base::Bind(&RendererSchedulerImpl::UpdatePolicy,
                      base::Unretained(this)),
           helper_.ControlTaskRunner()),
+      main_thread_only_(compositor_task_runner_),
       policy_may_need_update_(&any_thread_lock_),
       weak_factory_(this) {
   update_policy_closure_ = base::Bind(&RendererSchedulerImpl::UpdatePolicy,
@@ -61,10 +62,6 @@
       TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler",
       this);
 
-  // Make sure that we don't initially assume there is no idle time.
-  MainThreadOnly().short_idle_period_duration.InsertSample(
-      cc::BeginFrameArgs::DefaultInterval());
-
   helper_.SetObserver(this);
 }
 
@@ -94,12 +91,15 @@
       timer_queue_priority(TaskQueue::NORMAL_PRIORITY),
       default_queue_priority(TaskQueue::NORMAL_PRIORITY) {}
 
-RendererSchedulerImpl::MainThreadOnly::MainThreadOnly()
+RendererSchedulerImpl::MainThreadOnly::MainThreadOnly(
+    const scoped_refptr<TaskQueue>& compositor_task_runner)
     : loading_task_cost_estimator(kLoadingTaskEstimationSampleCount,
                                   kLoadingTaskEstimationPercentile),
       timer_task_cost_estimator(kTimerTaskEstimationSampleCount,
                                 kTimerTaskEstimationPercentile),
-      short_idle_period_duration(kShortIdlePeriodDurationSampleCount),
+      idle_time_estimator(compositor_task_runner,
+                          kShortIdlePeriodDurationSampleCount,
+                          kShortIdlePeriodDurationPercentile),
       current_use_case(UseCase::NONE),
       timer_queue_suspend_count(0),
       navigation_task_expected_count(0),
@@ -220,6 +220,7 @@
   EndIdlePeriod();
   MainThreadOnly().estimated_next_frame_begin = args.frame_time + args.interval;
   MainThreadOnly().have_seen_a_begin_main_frame = true;
+  MainThreadOnly().compositor_frame_interval = args.interval;
   {
     base::AutoLock lock(any_thread_lock_);
     AnyThread().begin_main_frame_on_critical_path = args.on_critical_path;
@@ -240,16 +241,9 @@
     idle_helper_.StartIdlePeriod(
         IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, now,
         MainThreadOnly().estimated_next_frame_begin);
-    MainThreadOnly().short_idle_period_duration.InsertSample(
-        MainThreadOnly().estimated_next_frame_begin - now);
-  } else {
-    // There was no idle time :(
-    MainThreadOnly().short_idle_period_duration.InsertSample(base::TimeDelta());
   }
 
-  MainThreadOnly().expected_short_idle_period_duration =
-      MainThreadOnly().short_idle_period_duration.Percentile(
-          kShortIdlePeriodDurationPercentile);
+  MainThreadOnly().idle_time_estimator.DidCommitFrameToCompositor();
 }
 
 void RendererSchedulerImpl::BeginFrameNotExpectedSoon() {
@@ -260,6 +254,10 @@
     return;
 
   idle_helper_.EnableLongIdlePeriod();
+  {
+    base::AutoLock lock(any_thread_lock_);
+    AnyThread().begin_main_frame_on_critical_path = false;
+  }
 }
 
 void RendererSchedulerImpl::OnRendererHidden() {
@@ -559,14 +557,19 @@
       use_case, now, &touchstart_expected_flag_valid_for_duration);
   MainThreadOnly().touchstart_expected_soon = touchstart_expected_soon;
 
+  base::TimeDelta expected_idle_duration =
+      MainThreadOnly().idle_time_estimator.GetExpectedIdleDuration(
+          MainThreadOnly().compositor_frame_interval);
+  MainThreadOnly().expected_idle_duration = expected_idle_duration;
+
   bool loading_tasks_seem_expensive =
       MainThreadOnly().loading_task_cost_estimator.expected_task_duration() >
-      MainThreadOnly().expected_short_idle_period_duration;
+      expected_idle_duration;
   MainThreadOnly().loading_tasks_seem_expensive = loading_tasks_seem_expensive;
 
   bool timer_tasks_seem_expensive =
       MainThreadOnly().timer_task_cost_estimator.expected_task_duration() >
-      MainThreadOnly().expected_short_idle_period_duration;
+      expected_idle_duration;
   MainThreadOnly().timer_tasks_seem_expensive = timer_tasks_seem_expensive;
 
   // The |new_policy_duration| is the minimum of |expected_use_case_duration|
@@ -639,7 +642,8 @@
   if (block_expensive_tasks && loading_tasks_seem_expensive)
     new_policy.loading_queue_priority = TaskQueue::DISABLED_PRIORITY;
 
-  if (MainThreadOnly().timer_queue_suspend_count != 0 ||
+  if ((block_expensive_tasks && timer_tasks_seem_expensive) ||
+      MainThreadOnly().timer_queue_suspend_count != 0 ||
       MainThreadOnly().timer_queue_suspended_when_backgrounded) {
     new_policy.timer_queue_priority = TaskQueue::DISABLED_PRIORITY;
   }
@@ -758,6 +762,10 @@
   return &MainThreadOnly().timer_task_cost_estimator;
 }
 
+IdleTimeEstimator* RendererSchedulerImpl::GetIdleTimeEstimatorForTesting() {
+  return &MainThreadOnly().idle_time_estimator;
+}
+
 void RendererSchedulerImpl::SuspendTimerQueue() {
   MainThreadOnly().timer_queue_suspend_count++;
   ForceUpdatePolicy();
@@ -838,9 +846,11 @@
                        .timer_task_cost_estimator.expected_task_duration()
                        .InMillisecondsF());
   // TODO(skyostil): Can we somehow trace how accurate these estimates were?
+  state->SetDouble("expected_idle_duration",
+                   MainThreadOnly().expected_idle_duration.InMillisecondsF());
   state->SetDouble(
-      "expected_short_idle_period_duration",
-      MainThreadOnly().expected_short_idle_period_duration.InMillisecondsF());
+      "compositor_frame_interval",
+      MainThreadOnly().compositor_frame_interval.InMillisecondsF());
   state->SetDouble(
       "estimated_next_frame_begin",
       (MainThreadOnly().estimated_next_frame_begin - base::TimeTicks())
@@ -917,10 +927,7 @@
   any_thread_lock_.AssertAcquired();
   MainThreadOnly().loading_task_cost_estimator.Clear();
   MainThreadOnly().timer_task_cost_estimator.Clear();
-  MainThreadOnly().short_idle_period_duration.Clear();
-  // Make sure that we don't initially assume there is no idle time.
-  MainThreadOnly().short_idle_period_duration.InsertSample(
-      cc::BeginFrameArgs::DefaultInterval());
+  MainThreadOnly().idle_time_estimator.Clear();
   AnyThread().user_model.Reset(helper_.Now());
   MainThreadOnly().have_seen_a_begin_main_frame = false;
   UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED);
diff --git a/components/scheduler/renderer/renderer_scheduler_impl.h b/components/scheduler/renderer/renderer_scheduler_impl.h
index dbe1c00..11061670 100644
--- a/components/scheduler/renderer/renderer_scheduler_impl.h
+++ b/components/scheduler/renderer/renderer_scheduler_impl.h
@@ -11,6 +11,7 @@
 #include "components/scheduler/child/idle_helper.h"
 #include "components/scheduler/child/scheduler_helper.h"
 #include "components/scheduler/renderer/deadline_task_runner.h"
+#include "components/scheduler/renderer/idle_time_estimator.h"
 #include "components/scheduler/renderer/renderer_scheduler.h"
 #include "components/scheduler/renderer/task_cost_estimator.h"
 #include "components/scheduler/renderer/user_model.h"
@@ -75,6 +76,7 @@
   SchedulerHelper* GetSchedulerHelperForTesting();
   TaskCostEstimator* GetLoadingTaskCostEstimatorForTesting();
   TaskCostEstimator* GetTimerTaskCostEstimatorForTesting();
+  IdleTimeEstimator* GetIdleTimeEstimatorForTesting();
   base::TimeTicks CurrentIdleTaskDeadlineForTesting() const;
 
  private:
@@ -142,6 +144,10 @@
   // other tasks during the initial page load.
   static const int kRailsInitialLoadingPrioritizationMillis = 1000;
 
+  // The amount of time in milliseconds we have to respond to user input as
+  // defined by RAILS.
+  static const int kRailsResponseTimeMillis = 50;
+
   // For the purposes of deciding whether or not it's safe to turn timers and
   // loading tasks on only in idle periods, we regard the system as being as
   // being "idle period" starved if there hasn't been an idle period in the last
@@ -229,17 +235,19 @@
   // (the accessors) for the following data members.
 
   struct MainThreadOnly {
-    MainThreadOnly();
+    explicit MainThreadOnly(
+        const scoped_refptr<TaskQueue>& compositor_task_runner);
     ~MainThreadOnly();
 
     TaskCostEstimator loading_task_cost_estimator;
     TaskCostEstimator timer_task_cost_estimator;
-    cc::RollingTimeDeltaHistory short_idle_period_duration;
+    IdleTimeEstimator idle_time_estimator;
     UseCase current_use_case;
     Policy current_policy;
     base::TimeTicks current_policy_expiration_time;
     base::TimeTicks estimated_next_frame_begin;
-    base::TimeDelta expected_short_idle_period_duration;
+    base::TimeDelta compositor_frame_interval;
+    base::TimeDelta expected_idle_duration;
     int timer_queue_suspend_count;  // TIMER_TASK_QUEUE suspended if non-zero.
     int navigation_task_expected_count;
     bool renderer_hidden;
diff --git a/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc b/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc
index 4956bf13..460a67f 100644
--- a/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc
+++ b/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc
@@ -266,6 +266,8 @@
             make_scoped_ptr(new TestTimeSource(clock_.get())));
     scheduler_->GetTimerTaskCostEstimatorForTesting()->SetTimeSourceForTesting(
         make_scoped_ptr(new TestTimeSource(clock_.get())));
+    scheduler_->GetIdleTimeEstimatorForTesting()->SetTimeSourceForTesting(
+        make_scoped_ptr(new TestTimeSource(clock_.get())));
   }
 
   void TearDown() override {
@@ -294,7 +296,7 @@
   void DoMainFrame() {
     cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create(
         BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
-        base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL);
+        base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL);
     begin_frame_args.on_critical_path = false;
     scheduler_->WillBeginFrame(begin_frame_args);
     scheduler_->DidCommitFrameToCompositor();
@@ -303,7 +305,7 @@
   void ForceMainThreadScrollingUseCase() {
     cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create(
         BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
-        base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL);
+        base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL);
     begin_frame_args.on_critical_path = true;
     scheduler_->WillBeginFrame(begin_frame_args);
   }
@@ -337,6 +339,27 @@
     mock_task_runner_->SetAutoAdvanceNowToPendingTasks(false);
   }
 
+  void WillBeginMainThreadGestureFrame() {
+    scheduler_->DidAnimateForInputOnCompositorThread();
+    cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create(
+        BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
+        base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL);
+    begin_frame_args.on_critical_path = true;
+    scheduler_->WillBeginFrame(begin_frame_args);
+  }
+
+  void SimulateMainThreadGestureCompositorTask(
+      base::TimeDelta begin_main_frame_duration) {
+    WillBeginMainThreadGestureFrame();
+    clock_->Advance(begin_main_frame_duration);
+    scheduler_->DidCommitFrameToCompositor();
+  }
+
+  void SimulateTimerTask(base::TimeDelta duration) {
+    clock_->Advance(duration);
+    simulate_timer_task_ran_ = true;
+  }
+
   void EnableIdleTasks() { DoMainFrame(); }
 
   UseCase CurrentUseCase() {
@@ -364,6 +387,10 @@
     return scheduler_->MainThreadOnly().timer_tasks_seem_expensive;
   }
 
+  base::TimeTicks EstimatedNextFrameBegin() {
+    return scheduler_->MainThreadOnly().estimated_next_frame_begin;
+  }
+
   // Helper for posting several tasks of specific types. |task_descriptor| is a
   // string with space delimited task identifiers. The first letter of each
   // task identifier specifies the task type:
@@ -466,6 +493,7 @@
   scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner_;
   scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_;
   scoped_refptr<base::SingleThreadTaskRunner> timer_task_runner_;
+  bool simulate_timer_task_ran_;
 
   DISALLOW_COPY_AND_ASSIGN(RendererSchedulerImplTest);
 };
@@ -736,10 +764,9 @@
   EXPECT_EQ(RendererScheduler::UseCase::COMPOSITOR_GESTURE, CurrentUseCase());
 }
 
-// TODO(skyostil): Re-enable once timer blocking is re-enabled.
 TEST_F(
     RendererSchedulerImplTest,
-    DISABLED_TestCompositorPolicy_ExpensiveTimersDontRunWhenMainThreadOnCriticalPath) {
+    TestCompositorPolicy_ExpensiveTimersDontRunWhenMainThreadOnCriticalPath) {
   std::vector<std::string> run_order;
 
   SimulateExpensiveTasks(timer_task_runner_);
@@ -748,12 +775,7 @@
   PostTestTasks(&run_order, "C1 T1");
 
   // Trigger main_thread_gesture UseCase
-  scheduler_->DidAnimateForInputOnCompositorThread();
-  cc::BeginFrameArgs begin_frame_args1 = cc::BeginFrameArgs::Create(
-      BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
-      base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL);
-  begin_frame_args1.on_critical_path = true;
-  scheduler_->WillBeginFrame(begin_frame_args1);
+  WillBeginMainThreadGestureFrame();
   RunUntilIdle();
   EXPECT_EQ(RendererScheduler::UseCase::MAIN_THREAD_GESTURE, CurrentUseCase());
 
@@ -773,12 +795,7 @@
   scheduler_->OnNavigationStarted();
   PostTestTasks(&run_order, "C1 T1");
 
-  scheduler_->DidAnimateForInputOnCompositorThread();
-  cc::BeginFrameArgs begin_frame_args1 = cc::BeginFrameArgs::Create(
-      BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
-      base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL);
-  begin_frame_args1.on_critical_path = true;
-  scheduler_->WillBeginFrame(begin_frame_args1);
+  WillBeginMainThreadGestureFrame();
   scheduler_->DidCommitFrameToCompositor();  // Starts Idle Period
   RunUntilIdle();
 
@@ -2101,5 +2118,62 @@
   EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1")));
 }
 
+TEST_F(RendererSchedulerImplTest, ModeratelyExpensiveTimer_NotBlocked) {
+  for (int i = 0; i < 20; i++) {
+    simulate_timer_task_ran_ = false;
+    compositor_task_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(
+            &RendererSchedulerImplTest::SimulateMainThreadGestureCompositorTask,
+            base::Unretained(this), base::TimeDelta::FromMilliseconds(4)));
+    timer_task_runner_->PostTask(
+        FROM_HERE, base::Bind(&RendererSchedulerImplTest::SimulateTimerTask,
+                              base::Unretained(this),
+                              base::TimeDelta::FromMilliseconds(10)));
 
+    RunUntilIdle();
+    EXPECT_TRUE(simulate_timer_task_ran_);
+    EXPECT_EQ(RendererScheduler::UseCase::MAIN_THREAD_GESTURE,
+              CurrentUseCase());
+    EXPECT_FALSE(LoadingTasksSeemExpensive());
+    EXPECT_FALSE(TimerTasksSeemExpensive());
+
+    base::TimeDelta time_till_next_frame =
+        EstimatedNextFrameBegin() - clock_->NowTicks();
+    if (time_till_next_frame > base::TimeDelta())
+      clock_->Advance(time_till_next_frame);
+  }
+}
+
+TEST_F(RendererSchedulerImplTest, ExpensiveTimer_Blocked) {
+  for (int i = 0; i < 20; i++) {
+    simulate_timer_task_ran_ = false;
+    compositor_task_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(
+            &RendererSchedulerImplTest::SimulateMainThreadGestureCompositorTask,
+            base::Unretained(this), base::TimeDelta::FromMilliseconds(8)));
+    timer_task_runner_->PostTask(
+        FROM_HERE, base::Bind(&RendererSchedulerImplTest::SimulateTimerTask,
+                              base::Unretained(this),
+                              base::TimeDelta::FromMilliseconds(10)));
+
+    RunUntilIdle();
+    EXPECT_EQ(RendererScheduler::UseCase::MAIN_THREAD_GESTURE,
+              CurrentUseCase());
+    EXPECT_FALSE(LoadingTasksSeemExpensive());
+    if (i == 0) {
+      EXPECT_FALSE(TimerTasksSeemExpensive());
+      EXPECT_TRUE(simulate_timer_task_ran_);
+    } else {
+      EXPECT_TRUE(TimerTasksSeemExpensive());
+      EXPECT_FALSE(simulate_timer_task_ran_);
+    }
+
+    base::TimeDelta time_till_next_frame =
+        EstimatedNextFrameBegin() - clock_->NowTicks();
+    if (time_till_next_frame > base::TimeDelta())
+      clock_->Advance(time_till_next_frame);
+  }
+}
 }  // namespace scheduler
diff --git a/components/scheduler/scheduler.gypi b/components/scheduler/scheduler.gypi
index 13ca288e6..b9b8cdd 100644
--- a/components/scheduler/scheduler.gypi
+++ b/components/scheduler/scheduler.gypi
@@ -48,6 +48,8 @@
       'ppapi/webthread_impl_for_ppapi.h',
       'renderer/deadline_task_runner.cc',
       'renderer/deadline_task_runner.h',
+      'renderer/idle_time_estimator.cc',
+      'renderer/idle_time_estimator.h',
       'renderer/renderer_scheduler.cc',
       'renderer/renderer_scheduler.h',
       'renderer/renderer_scheduler_impl.cc',
diff --git a/components/web_modal/web_contents_modal_dialog_manager.cc b/components/web_modal/web_contents_modal_dialog_manager.cc
index d49d36e..afb2344 100644
--- a/components/web_modal/web_contents_modal_dialog_manager.cc
+++ b/components/web_modal/web_contents_modal_dialog_manager.cc
@@ -8,6 +8,7 @@
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 
@@ -126,7 +127,7 @@
   // RenderViewHost may be NULL during shutdown.
   content::RenderViewHost* host = contents->GetRenderViewHost();
   if (host)
-    host->SetIgnoreInputEvents(blocked);
+    host->GetWidget()->SetIgnoreInputEvents(blocked);
   if (delegate_)
     delegate_->SetWebContentsBlocked(contents, blocked);
 }
diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc
index d7c5cd9..bc83a1c 100644
--- a/content/browser/android/content_view_core_impl.cc
+++ b/content/browser/android/content_view_core_impl.cc
@@ -310,11 +310,13 @@
     old_pid = GetRenderProcessIdFromRenderViewHost(old_host);
 
     RenderWidgetHostViewAndroid* view =
-        static_cast<RenderWidgetHostViewAndroid*>(old_host->GetView());
+        static_cast<RenderWidgetHostViewAndroid*>(
+            old_host->GetWidget()->GetView());
     if (view)
       view->SetContentViewCore(NULL);
 
-    view = static_cast<RenderWidgetHostViewAndroid*>(new_host->GetView());
+    view = static_cast<RenderWidgetHostViewAndroid*>(
+        new_host->GetWidget()->GetView());
     if (view)
       view->SetContentViewCore(this);
   }
@@ -342,6 +344,7 @@
       rwhv = web_contents_->GetInterstitialPage()
                  ->GetMainFrame()
                  ->GetRenderViewHost()
+                 ->GetWidget()
                  ->GetView();
     }
   }
diff --git a/content/browser/android/in_process/synchronous_compositor_impl.cc b/content/browser/android/in_process/synchronous_compositor_impl.cc
index 0e99e8d5..4f90a97 100644
--- a/content/browser/android/in_process/synchronous_compositor_impl.cc
+++ b/content/browser/android/in_process/synchronous_compositor_impl.cc
@@ -21,6 +21,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/common/child_process_host.h"
 #include "ui/gfx/geometry/scroll_offset.h"
 #include "ui/gl/gl_surface.h"
@@ -51,7 +52,7 @@
   if (!rvh)
     return nullptr;
   RenderWidgetHostViewAndroid* rwhva =
-      static_cast<RenderWidgetHostViewAndroid*>(rvh->GetView());
+      static_cast<RenderWidgetHostViewAndroid*>(rvh->GetWidget()->GetView());
   if (!rwhva)
     return nullptr;
   return rwhva->GetSynchronousCompositorImpl();
diff --git a/content/browser/browser_plugin/browser_plugin_embedder.cc b/content/browser/browser_plugin/browser_plugin_embedder.cc
index 4c6fecd..87659e4b 100644
--- a/content/browser/browser_plugin/browser_plugin_embedder.cc
+++ b/content/browser/browser_plugin/browser_plugin_embedder.cc
@@ -50,8 +50,8 @@
 bool BrowserPluginEmbedder::NotifyScreenInfoChanged(
     WebContents* guest_web_contents) {
   if (guest_web_contents->GetRenderViewHost()) {
-    auto render_widget_host =
-        RenderWidgetHostImpl::From(guest_web_contents->GetRenderViewHost());
+    auto render_widget_host = RenderWidgetHostImpl::From(
+        guest_web_contents->GetRenderViewHost()->GetWidget());
     render_widget_host->NotifyScreenInfoChanged();
   }
 
diff --git a/content/browser/browser_plugin/browser_plugin_guest.cc b/content/browser/browser_plugin/browser_plugin_guest.cc
index 00529ff..a79c954 100644
--- a/content/browser/browser_plugin/browser_plugin_guest.cc
+++ b/content/browser/browser_plugin/browser_plugin_guest.cc
@@ -610,8 +610,9 @@
   Send(new InputMsg_SetFocus(routing_id(), focused_));
   UpdateVisibility();
 
-  RenderWidgetHostImpl::From(rvh)->set_hung_renderer_delay(
-      base::TimeDelta::FromMilliseconds(kHungRendererDelayMs));
+  RenderWidgetHostImpl::From(rvh->GetWidget())
+      ->set_hung_renderer_delay(
+          base::TimeDelta::FromMilliseconds(kHungRendererDelayMs));
 }
 
 void BrowserPluginGuest::RenderProcessGone(base::TerminationStatus status) {
@@ -750,9 +751,9 @@
         GetWebContents()->GetRenderViewHost())->Init();
     WebContentsViewGuest* web_contents_view =
         static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
-    if (!web_contents()->GetRenderViewHost()->GetView()) {
+    if (!web_contents()->GetRenderViewHost()->GetWidget()->GetView()) {
       web_contents_view->CreateViewForWidget(
-          web_contents()->GetRenderViewHost(), true);
+          web_contents()->GetRenderViewHost()->GetWidget(), true);
     }
   }
 
diff --git a/content/browser/frame_host/interstitial_page_impl.cc b/content/browser/frame_host/interstitial_page_impl.cc
index 2fe3c90..8b7a22733a 100644
--- a/content/browser/frame_host/interstitial_page_impl.cc
+++ b/content/browser/frame_host/interstitial_page_impl.cc
@@ -226,7 +226,8 @@
   // already been destroyed.
   notification_registrar_.Add(
       this, NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
-      Source<RenderWidgetHost>(controller_->delegate()->GetRenderViewHost()));
+      Source<RenderWidgetHost>(
+          controller_->delegate()->GetRenderViewHost()->GetWidget()));
 
   // Update the g_web_contents_to_interstitial_page map.
   iter = g_web_contents_to_interstitial_page->find(web_contents_);
@@ -272,7 +273,7 @@
   Disable();
 
   RenderWidgetHostView* old_view =
-      controller_->delegate()->GetRenderViewHost()->GetView();
+      controller_->delegate()->GetRenderViewHost()->GetWidget()->GetView();
   if (controller_->delegate()->GetInterstitialPage() == this &&
       old_view &&
       !old_view->IsShowing() &&
@@ -289,8 +290,12 @@
   // (Note that in unit-tests the RVH may not have a view).
   if (render_view_host_->GetView() &&
       render_view_host_->GetView()->HasFocus() &&
-      controller_->delegate()->GetRenderViewHost()->GetView()) {
-    controller_->delegate()->GetRenderViewHost()->GetView()->Focus();
+      controller_->delegate()->GetRenderViewHost()->GetWidget()->GetView()) {
+    controller_->delegate()
+        ->GetRenderViewHost()
+        ->GetWidget()
+        ->GetView()
+        ->Focus();
   }
 
   // Delete this and call Shutdown on the RVH asynchronously, as we may have
@@ -512,7 +517,7 @@
   controller_->delegate()->AttachInterstitialPage(this);
 
   RenderWidgetHostView* rwh_view =
-      controller_->delegate()->GetRenderViewHost()->GetView();
+      controller_->delegate()->GetRenderViewHost()->GetWidget()->GetView();
 
   // The RenderViewHost may already have crashed before we even get here.
   if (rwh_view) {
diff --git a/content/browser/frame_host/navigation_entry_screenshot_manager.cc b/content/browser/frame_host/navigation_entry_screenshot_manager.cc
index 8ad5080..dac7422 100644
--- a/content/browser/frame_host/navigation_entry_screenshot_manager.cc
+++ b/content/browser/frame_host/navigation_entry_screenshot_manager.cc
@@ -86,7 +86,8 @@
     return;
 
   RenderViewHost* render_view_host = owner_->delegate()->GetRenderViewHost();
-  content::RenderWidgetHostView* view = render_view_host->GetView();
+  content::RenderWidgetHostView* view =
+      render_view_host->GetWidget()->GetView();
   if (!view)
     return;
 
@@ -115,14 +116,12 @@
 void NavigationEntryScreenshotManager::TakeScreenshotImpl(
     RenderViewHost* host,
     NavigationEntryImpl* entry) {
-  DCHECK(host && host->GetView());
+  DCHECK(host && host->GetWidget()->GetView());
   DCHECK(entry);
-  host->CopyFromBackingStore(
-      gfx::Rect(),
-      host->GetView()->GetViewBounds().size(),
+  host->GetWidget()->CopyFromBackingStore(
+      gfx::Rect(), host->GetWidget()->GetView()->GetViewBounds().size(),
       base::Bind(&NavigationEntryScreenshotManager::OnScreenshotTaken,
-                 screenshot_factory_.GetWeakPtr(),
-                 entry->GetUniqueID()),
+                 screenshot_factory_.GetWeakPtr(), entry->GetUniqueID()),
       kAlpha_8_SkColorType);
 }
 
diff --git a/content/browser/frame_host/popup_menu_helper_mac.mm b/content/browser/frame_host/popup_menu_helper_mac.mm
index 1ab1917..9826711 100644
--- a/content/browser/frame_host/popup_menu_helper_mac.mm
+++ b/content/browser/frame_host/popup_menu_helper_mac.mm
@@ -32,10 +32,12 @@
       popup_was_hidden_(false) {
   notification_registrar_.Add(
       this, NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
-      Source<RenderWidgetHost>(render_frame_host->GetRenderViewHost()));
+      Source<RenderWidgetHost>(
+          render_frame_host->GetRenderViewHost()->GetWidget()));
   notification_registrar_.Add(
       this, NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
-      Source<RenderWidgetHost>(render_frame_host->GetRenderViewHost()));
+      Source<RenderWidgetHost>(
+          render_frame_host->GetRenderViewHost()->GetWidget()));
 }
 
 void PopupMenuHelper::ShowPopupMenu(
@@ -117,14 +119,14 @@
 
 RenderWidgetHostViewMac* PopupMenuHelper::GetRenderWidgetHostView() const {
   return static_cast<RenderWidgetHostViewMac*>(
-      render_frame_host_->GetRenderViewHost()->GetView());
+      render_frame_host_->GetRenderViewHost()->GetWidget()->GetView());
 }
 
 void PopupMenuHelper::Observe(int type,
                               const NotificationSource& source,
                               const NotificationDetails& details) {
   DCHECK_EQ(Source<RenderWidgetHost>(source).ptr(),
-            render_frame_host_->GetRenderViewHost());
+            render_frame_host_->GetRenderViewHost()->GetWidget());
   switch (type) {
     case NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED: {
       render_frame_host_ = NULL;
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index 6263bcb7..e19b9fa 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -1792,8 +1792,10 @@
 
       // If we are reusing the RenderViewHost and it doesn't already have a
       // RenderWidgetHostView, we need to create one if this is the main frame.
-      if (!render_view_host->GetView() && frame_tree_node_->IsMainFrame())
+      if (!render_view_host->GetWidget()->GetView() &&
+          frame_tree_node_->IsMainFrame()) {
         delegate_->CreateRenderWidgetHostViewForRenderManager(render_view_host);
+      }
     }
   } else {
     // Create a new RenderFrameHost if we don't find an existing one.
diff --git a/content/browser/media/capture/web_contents_video_capture_device_unittest.cc b/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
index 9a72b8a..6e133b1d 100644
--- a/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
+++ b/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
@@ -648,7 +648,7 @@
   // particular window).
   float GetDeviceScaleFactor() const {
     RenderWidgetHostView* const view =
-        web_contents_->GetRenderViewHost()->GetView();
+        web_contents_->GetRenderViewHost()->GetWidget()->GetView();
     CHECK(view);
     return ui::GetScaleFactorForNativeView(view->GetNativeView());
   }
@@ -657,13 +657,14 @@
     if (source()->CanUseFrameSubscriber()) {
       // Print
       CaptureTestView* test_view = static_cast<CaptureTestView*>(
-          web_contents_->GetRenderViewHost()->GetView());
+          web_contents_->GetRenderViewHost()->GetWidget()->GetView());
       test_view->SimulateUpdate();
     } else {
       // Simulate a non-accelerated paint.
       NotificationService::current()->Notify(
           NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
-          Source<RenderWidgetHost>(web_contents_->GetRenderViewHost()),
+          Source<RenderWidgetHost>(
+              web_contents_->GetRenderViewHost()->GetWidget()),
           NotificationService::NoDetails());
     }
   }
@@ -671,7 +672,7 @@
   void SimulateSourceSizeChange(const gfx::Size& size) {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
     CaptureTestView* test_view = static_cast<CaptureTestView*>(
-        web_contents_->GetRenderViewHost()->GetView());
+        web_contents_->GetRenderViewHost()->GetWidget()->GetView());
     test_view->SetSize(size);
     // Normally, RenderWidgetHostImpl would notify WebContentsImpl that the size
     // has changed.  However, in this test setup where there is no render
diff --git a/content/browser/renderer_host/input/touch_action_browsertest.cc b/content/browser/renderer_host/input/touch_action_browsertest.cc
index 02d53e8a..5f3eae90 100644
--- a/content/browser/renderer_host/input/touch_action_browsertest.cc
+++ b/content/browser/renderer_host/input/touch_action_browsertest.cc
@@ -74,8 +74,8 @@
   ~TouchActionBrowserTest() override {}
 
   RenderWidgetHostImpl* GetWidgetHost() {
-    return RenderWidgetHostImpl::From(shell()->web_contents()->
-                                          GetRenderViewHost());
+    return RenderWidgetHostImpl::From(
+        shell()->web_contents()->GetRenderViewHost()->GetWidget());
   }
 
   void OnSyntheticGestureCompleted(SyntheticGesture::Result result) {
diff --git a/content/browser/renderer_host/input/touch_input_browsertest.cc b/content/browser/renderer_host/input/touch_input_browsertest.cc
index de959b5..a497dd79e 100644
--- a/content/browser/renderer_host/input/touch_input_browsertest.cc
+++ b/content/browser/renderer_host/input/touch_input_browsertest.cc
@@ -140,8 +140,8 @@
   ~TouchInputBrowserTest() override {}
 
   RenderWidgetHostImpl* GetWidgetHost() {
-    return RenderWidgetHostImpl::From(shell()->web_contents()->
-                                          GetRenderViewHost());
+    return RenderWidgetHostImpl::From(
+        shell()->web_contents()->GetRenderViewHost()->GetWidget());
   }
 
   InputEventMessageFilter* filter() { return filter_.get(); }
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index 4c2c1fac..b09ff1f5 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -734,6 +734,23 @@
   Send(new DragMsg_SourceSystemDragEnded(GetRoutingID()));
 }
 
+bool RenderViewHostImpl::Send(IPC::Message* msg) {
+  return RenderWidgetHostImpl::Send(msg);
+}
+
+RenderWidgetHost* RenderViewHostImpl::GetWidget() const {
+  return const_cast<RenderWidgetHost*>(
+      static_cast<const RenderWidgetHost*>(this));
+}
+
+RenderProcessHost* RenderViewHostImpl::GetProcess() const {
+  return RenderWidgetHostImpl::GetProcess();
+}
+
+int RenderViewHostImpl::GetRoutingID() const {
+  return RenderWidgetHostImpl::GetRoutingID();
+}
+
 RenderFrameHost* RenderViewHostImpl::GetMainFrame() {
   return RenderFrameHost::FromID(GetProcess()->GetID(), main_frame_routing_id_);
 }
@@ -883,8 +900,10 @@
 // RenderViewHostImpl, IPC message handlers:
 
 bool RenderViewHostImpl::OnMessageReceived(const IPC::Message& msg) {
-  if (!BrowserMessageFilter::CheckCanDispatchOnUI(msg, this))
+  if (!BrowserMessageFilter::CheckCanDispatchOnUI(
+          msg, static_cast<RenderWidgetHostImpl*>(this))) {
     return true;
+  }
 
   // Filter out most IPC messages if this renderer is swapped out.
   // We still want to handle certain ACKs to keep our state consistent.
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h
index c1adca8..db63ad5 100644
--- a/content/browser/renderer_host/render_view_host_impl.h
+++ b/content/browser/renderer_host/render_view_host_impl.h
@@ -122,6 +122,10 @@
   ~RenderViewHostImpl() override;
 
   // RenderViewHost implementation.
+  bool Send(IPC::Message* msg) override;
+  RenderWidgetHost* GetWidget() const override;
+  RenderProcessHost* GetProcess() const override;
+  int GetRoutingID() const override;
   RenderFrameHost* GetMainFrame() override;
   void AllowBindings(int binding_flags) override;
   void ClearFocusedElement() override;
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index 64d2dda..db62fa0 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -80,12 +80,11 @@
 
 // This implements the RenderWidgetHost interface that is exposed to
 // embedders of content, and adds things only visible to content.
-class CONTENT_EXPORT RenderWidgetHostImpl
-    : virtual public RenderWidgetHost,
-      public InputRouterClient,
-      public InputAckHandler,
-      public TouchEmulatorClient,
-      public IPC::Listener {
+class CONTENT_EXPORT RenderWidgetHostImpl : public RenderWidgetHost,
+                                            public InputRouterClient,
+                                            public InputAckHandler,
+                                            public TouchEmulatorClient,
+                                            public IPC::Listener {
  public:
   // |routing_id| must not be MSG_ROUTING_NONE.
   // If this object outlives |delegate|, DetachDelegate() must be called when
diff --git a/content/browser/renderer_host/render_widget_host_view_browsertest.cc b/content/browser/renderer_host/render_widget_host_view_browsertest.cc
index df02f17..6eb62bd 100644
--- a/content/browser/renderer_host/render_widget_host_view_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_browsertest.cc
@@ -104,7 +104,7 @@
 
   RenderWidgetHostViewBase* GetRenderWidgetHostView() const {
     return static_cast<RenderWidgetHostViewBase*>(
-        GetRenderViewHost()->GetView());
+        GetRenderViewHost()->GetWidget()->GetView());
   }
 
   // Callback when using CopyFromBackingStore() API.
@@ -154,13 +154,11 @@
     while (true) {
       ++count_attempts;
       base::RunLoop run_loop;
-      GetRenderViewHost()->CopyFromBackingStore(
-          gfx::Rect(),
-          frame_size(),
+      GetRenderViewHost()->GetWidget()->CopyFromBackingStore(
+          gfx::Rect(), frame_size(),
           base::Bind(
               &RenderWidgetHostViewBrowserTest::FinishCopyFromBackingStore,
-              base::Unretained(this),
-              run_loop.QuitClosure()),
+              base::Unretained(this), run_loop.QuitClosure()),
           kN32_SkColorType);
       run_loop.Run();
 
@@ -289,12 +287,10 @@
   SET_UP_SURFACE_OR_PASS_TEST(NULL);
 
   base::RunLoop run_loop;
-  GetRenderViewHost()->CopyFromBackingStore(
-      gfx::Rect(),
-      frame_size(),
+  GetRenderViewHost()->GetWidget()->CopyFromBackingStore(
+      gfx::Rect(), frame_size(),
       base::Bind(&RenderWidgetHostViewBrowserTest::FinishCopyFromBackingStore,
-                 base::Unretained(this),
-                 run_loop.QuitClosure()),
+                 base::Unretained(this), run_loop.QuitClosure()),
       kN32_SkColorType);
   run_loop.Run();
 
diff --git a/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm b/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
index 4a7dad6f..5a0ec418 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
@@ -206,10 +206,10 @@
     // TestRenderViewHost's destruction assumes that its view is a
     // TestRenderWidgetHostView, so store its view and reset it back to the
     // stored view in |TearDown()|.
-    old_rwhv_ = rvh()->GetView();
+    old_rwhv_ = rvh()->GetWidget()->GetView();
 
     // Owned by its |cocoa_view()|, i.e. |rwhv_cocoa_|.
-    rwhv_mac_ = new RenderWidgetHostViewMac(rvh(), false);
+    rwhv_mac_ = new RenderWidgetHostViewMac(rvh()->GetWidget(), false);
     rwhv_cocoa_.reset([rwhv_mac_->cocoa_view() retain]);
   }
   void TearDown() override {
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 8a907d5..0896a67 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -385,7 +385,7 @@
   // The out-of-process iframe should have its own RenderWidgetHost,
   // independent of any RenderViewHost.
   EXPECT_NE(
-      rvh->GetView(),
+      rvh->GetWidget()->GetView(),
       proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
   EXPECT_TRUE(child->current_frame_host()->GetRenderWidgetHost());
 
@@ -3501,7 +3501,8 @@
   EXPECT_EQ(root->child_at(0), root->frame_tree()->GetFocusedFrame());
 
   // Click on the root frame.
-  shell()->web_contents()->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+  shell()->web_contents()->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(
+      mouse_event);
 
   // Check that the subframe lost focus and fired blur event on its
   // document's body.
diff --git a/content/browser/web_contents/web_contents_android.cc b/content/browser/web_contents/web_contents_android.cc
index 5b6f256..eff18f9 100644
--- a/content/browser/web_contents/web_contents_android.cc
+++ b/content/browser/web_contents/web_contents_android.cc
@@ -28,6 +28,7 @@
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/message_port_provider.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
 #include "jni/WebContentsImpl_jni.h"
@@ -284,6 +285,7 @@
     rwhv = web_contents_->GetInterstitialPage()
                ->GetMainFrame()
                ->GetRenderViewHost()
+               ->GetWidget()
                ->GetView();
   }
   return static_cast<RenderWidgetHostViewAndroid*>(rwhv);
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 11f33c4..2e9e6d9 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -3906,7 +3906,7 @@
     // If we're fullscreen only update the url if it's from the fullscreen
     // renderer.
     RenderWidgetHostView* fs = GetFullscreenRenderWidgetHostView();
-    if (fs && fs->GetRenderWidgetHost() != render_view_host)
+    if (fs && fs->GetRenderWidgetHost() != render_view_host->GetWidget())
       return;
   }
   if (delegate_)
@@ -4352,10 +4352,10 @@
       BrowserPluginGuestMode::UseCrossProcessFramesForGuests();
   if (is_guest_in_site_per_process) {
     RenderWidgetHostViewChildFrame* rwh_view_child =
-        new RenderWidgetHostViewChildFrame(render_view_host);
+        new RenderWidgetHostViewChildFrame(render_view_host->GetWidget());
     rwh_view = rwh_view_child;
   } else {
-    rwh_view = view_->CreateViewForWidget(render_view_host, false);
+    rwh_view = view_->CreateViewForWidget(render_view_host->GetWidget(), false);
   }
 
   // Now that the RenderView has been created, we need to tell it its size.
@@ -4393,7 +4393,7 @@
 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
   // Force a ViewMsg_Resize to be sent, needed to make plugins show up on
   // linux. See crbug.com/83941.
-  RenderWidgetHostView* rwh_view = render_view_host->GetView();
+  RenderWidgetHostView* rwh_view = render_view_host->GetWidget()->GetView();
   if (rwh_view) {
     if (RenderWidgetHost* render_widget_host = rwh_view->GetRenderWidgetHost())
       render_widget_host->WasResized();
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
index aa00317..aa975789 100644
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -142,7 +142,7 @@
 
   // WebContentsObserver:
   void RenderViewCreated(RenderViewHost* rvh) override {
-    rwhv_create_size_ = rvh->GetView()->GetViewBounds().size();
+    rwhv_create_size_ = rvh->GetWidget()->GetView()->GetViewBounds().size();
   }
 
   void DidStartProvisionalLoadForFrame(
@@ -706,7 +706,7 @@
 
   delegate.set_mode(blink::WebDisplayModeFullscreen);
   // Simulate widget is entering fullscreen (changing size is enough).
-  shell()->web_contents()->GetRenderViewHost()->WasResized();
+  shell()->web_contents()->GetRenderViewHost()->GetWidget()->WasResized();
 
   ASSERT_TRUE(ExecuteScript(shell()->web_contents(),
                             "document.title = "
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index 7dabef2c..63f032c 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -150,7 +150,8 @@
 
   bool is_showing() const {
     return static_cast<TestRenderWidgetHostView*>(
-               GetMainFrame()->GetRenderViewHost()->GetView())->is_showing();
+               GetMainFrame()->GetRenderViewHost()->GetWidget()->GetView())
+        ->is_showing();
   }
 
   void ClearStates() {
diff --git a/content/browser/web_contents/web_contents_view_android.cc b/content/browser/web_contents/web_contents_view_android.cc
index 48ccdc54..73bfa2bd 100644
--- a/content/browser/web_contents/web_contents_view_android.cc
+++ b/content/browser/web_contents/web_contents_view_android.cc
@@ -11,6 +11,7 @@
 #include "content/browser/renderer_host/render_view_host_factory.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents_delegate.h"
 
 namespace content {
@@ -48,6 +49,7 @@
         web_contents_->GetInterstitialPage()
             ->GetMainFrame()
             ->GetRenderViewHost()
+            ->GetWidget()
             ->GetView());
     if (rwhv)
       rwhv->SetContentViewCore(content_view_core_);
diff --git a/content/browser/web_contents/web_contents_view_aura.cc b/content/browser/web_contents/web_contents_view_aura.cc
index 42259fe6..f3fd2dd 100644
--- a/content/browser/web_contents/web_contents_view_aura.cc
+++ b/content/browser/web_contents/web_contents_view_aura.cc
@@ -687,7 +687,7 @@
       gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint();
   gfx::Point client_loc = screen_loc;
   RenderViewHost* rvh = web_contents_->GetRenderViewHost();
-  aura::Window* window = rvh->GetView()->GetNativeView();
+  aura::Window* window = rvh->GetWidget()->GetView()->GetNativeView();
   aura::Window::ConvertPointToTarget(root_window, window, &client_loc);
   if (!web_contents_)
     return;
diff --git a/content/browser/web_contents/web_contents_view_aura_browsertest.cc b/content/browser/web_contents/web_contents_view_aura_browsertest.cc
index d2f01ee..43e4ced 100644
--- a/content/browser/web_contents/web_contents_view_aura_browsertest.cc
+++ b/content/browser/web_contents/web_contents_view_aura_browsertest.cc
@@ -26,6 +26,7 @@
 #include "content/common/view_messages.h"
 #include "content/public/browser/browser_message_filter.h"
 #include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/content_switches.h"
@@ -396,7 +397,7 @@
 
   RenderWidgetHostViewBase* GetRenderWidgetHostView() const {
     return static_cast<RenderWidgetHostViewBase*>(
-        GetRenderViewHost()->GetView());
+        GetRenderViewHost()->GetWidget()->GetView());
   }
 
   InputEventMessageFilterWaitsForAcks* filter() {
diff --git a/content/public/browser/render_view_host.h b/content/public/browser/render_view_host.h
index 5909d28..3b5a168 100644
--- a/content/public/browser/render_view_host.h
+++ b/content/public/browser/render_view_host.h
@@ -7,9 +7,9 @@
 
 #include "base/callback_forward.h"
 #include "content/common/content_export.h"
-#include "content/public/browser/render_widget_host.h"
 #include "content/public/common/file_chooser_params.h"
 #include "content/public/common/page_zoom.h"
+#include "ipc/ipc_sender.h"
 #include "third_party/WebKit/public/web/WebDragOperation.h"
 #include "third_party/mojo/src/mojo/public/cpp/system/core.h"
 
@@ -27,13 +27,16 @@
 
 namespace gfx {
 class Point;
+class Size;
 }
 
 namespace content {
 
 class ChildProcessSecurityPolicy;
 class RenderFrameHost;
+class RenderProcessHost;
 class RenderViewHostDelegate;
+class RenderWidgetHost;
 class SessionStorageNamespace;
 class SiteInstance;
 struct DropData;
@@ -53,23 +56,38 @@
 // WebContents (see WebContents for an example) but also as views, etc.
 //
 // DEPRECATED: RenderViewHost is being removed as part of the SiteIsolation
-// project. New code should not be added here, but to either RenderFrameHost
-// (if frame specific) or WebContents (if page specific).
+// project. New code should not be added here, but to RenderWidgetHost (if it's
+// about drawing or events), RenderFrameHost (if it's frame specific), or
+// WebContents (if it's page specific).
 //
 // For context, please see https://crbug.com/467770 and
 // http://www.chromium.org/developers/design-documents/site-isolation.
-class CONTENT_EXPORT RenderViewHost : virtual public RenderWidgetHost {
+class CONTENT_EXPORT RenderViewHost : public IPC::Sender {
  public:
   // Returns the RenderViewHost given its ID and the ID of its render process.
   // Returns nullptr if the IDs do not correspond to a live RenderViewHost.
   static RenderViewHost* FromID(int render_process_id, int render_view_id);
 
-  // Downcasts from a RenderWidgetHost to a RenderViewHost.  Required
-  // because RenderWidgetHost is a virtual base class.
+  // Returns the RenderViewHost, if any, that uses the specified
+  // RenderWidgetHost. Returns nullptr if there is no such RenderViewHost.
   static RenderViewHost* From(RenderWidgetHost* rwh);
 
   ~RenderViewHost() override {}
 
+  // Returns the RenderWidgetHost for this RenderViewHost.
+  virtual RenderWidgetHost* GetWidget() const = 0;
+
+  // Returns the RenderProcessHost for this RenderViewHost.
+  virtual RenderProcessHost* GetProcess() const = 0;
+
+  // Returns the routing id for IPC use for this RenderViewHost.
+  //
+  // Implementation note: Historically, RenderViewHost was-a RenderWidgetHost,
+  // and shared its IPC channel and its routing ID. Although this inheritance is
+  // no longer so, the IPC channel is currently still shared. Expect this to
+  // change.
+  virtual int GetRoutingID() const = 0;
+
   // Returns the main frame for this render view.
   virtual RenderFrameHost* GetMainFrame() = 0;
 
diff --git a/content/public/browser/screen_orientation_provider.cc b/content/public/browser/screen_orientation_provider.cc
index b575f09..5fa5b23 100644
--- a/content/public/browser/screen_orientation_provider.cc
+++ b/content/public/browser/screen_orientation_provider.cc
@@ -6,6 +6,7 @@
 
 #include "content/browser/renderer_host/render_view_host_delegate.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/screen_orientation_delegate.h"
 #include "content/public/browser/screen_orientation_dispatcher_host.h"
 #include "content/public/browser/web_contents.h"
@@ -131,7 +132,7 @@
 
 blink::WebScreenOrientationLockType
     ScreenOrientationProvider::GetNaturalLockType() const {
-  RenderWidgetHost* rwh = web_contents()->GetRenderViewHost();
+  RenderWidgetHost* rwh = web_contents()->GetRenderViewHost()->GetWidget();
   if (!rwh)
     return blink::WebScreenOrientationLockDefault;
 
@@ -164,7 +165,7 @@
 
 bool ScreenOrientationProvider::LockMatchesCurrentOrientation(
     blink::WebScreenOrientationLockType lock) {
-  RenderWidgetHost* rwh = web_contents()->GetRenderViewHost();
+  RenderWidgetHost* rwh = web_contents()->GetRenderViewHost()->GetWidget();
   if (!rwh)
     return false;
 
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index fdf58cc7..60b8abb 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -227,7 +227,7 @@
                        int modifiers) {
   NativeWebKeyboardEvent event;
   BuildSimpleWebKeyEvent(type, key_code, native_key_code, modifiers, &event);
-  web_contents->GetRenderViewHost()->ForwardKeyboardEvent(event);
+  web_contents->GetRenderViewHost()->GetWidget()->ForwardKeyboardEvent(event);
 }
 
 void GetCookiesCallback(std::string* cookies_out,
@@ -382,8 +382,8 @@
   aura::WindowTreeHost* window_host = content->GetHost();
   aura::WindowEventDispatcher* dispatcher = window_host->dispatcher();
   aura::test::WindowEventDispatcherTestApi dispatcher_test(dispatcher);
-  RenderWidgetHostImpl* widget_host =
-      RenderWidgetHostImpl::From(web_contents->GetRenderViewHost());
+  RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
+      web_contents->GetRenderViewHost()->GetWidget());
   if (!IsResizeComplete(&dispatcher_test, widget_host)) {
     WindowedNotificationObserver resize_observer(
         NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
@@ -397,8 +397,8 @@
 }
 
 void WaitForResizeComplete(WebContents* web_contents) {
-  RenderWidgetHostImpl* widget_host =
-      RenderWidgetHostImpl::From(web_contents->GetRenderViewHost());
+  RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
+      web_contents->GetRenderViewHost()->GetWidget());
   if (!IsResizeComplete(widget_host)) {
     WindowedNotificationObserver resize_observer(
         NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
@@ -431,9 +431,11 @@
   mouse_event.globalX = point.x() + offset.x();
   mouse_event.globalY = point.y() + offset.y();
   mouse_event.clickCount = 1;
-  web_contents->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+  web_contents->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(
+      mouse_event);
   mouse_event.type = blink::WebInputEvent::MouseUp;
-  web_contents->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+  web_contents->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(
+      mouse_event);
 }
 
 void SimulateMouseEvent(WebContents* web_contents,
@@ -443,7 +445,8 @@
   mouse_event.type = type;
   mouse_event.x = point.x();
   mouse_event.y = point.y();
-  web_contents->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+  web_contents->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(
+      mouse_event);
 }
 
 void SimulateMouseWheelEvent(WebContents* web_contents,
@@ -455,16 +458,16 @@
   wheel_event.y = point.y();
   wheel_event.deltaX = delta.x();
   wheel_event.deltaY = delta.y();
-  RenderWidgetHostImpl* widget_host =
-      RenderWidgetHostImpl::From(web_contents->GetRenderViewHost());
+  RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
+      web_contents->GetRenderViewHost()->GetWidget());
   widget_host->ForwardWheelEvent(wheel_event);
 }
 
 void SimulateGestureScrollSequence(WebContents* web_contents,
                                    const gfx::Point& point,
                                    const gfx::Vector2dF& delta) {
-  RenderWidgetHostImpl* widget_host =
-      RenderWidgetHostImpl::From(web_contents->GetRenderViewHost());
+  RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
+      web_contents->GetRenderViewHost()->GetWidget());
 
   blink::WebGestureEvent scroll_begin;
   scroll_begin.type = blink::WebGestureEvent::GestureScrollBegin;
@@ -495,8 +498,8 @@
   tap.x = point.x();
   tap.y = point.y();
   tap.modifiers = blink::WebInputEvent::ControlKey;
-  RenderWidgetHostImpl* widget_host =
-      RenderWidgetHostImpl::From(web_contents->GetRenderViewHost());
+  RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
+      web_contents->GetRenderViewHost()->GetWidget());
   widget_host->ForwardGestureEvent(tap);
 }
 
@@ -508,16 +511,16 @@
   tap.x = point.x();
   tap.y = point.y();
   tap.modifiers = modifiers;
-  RenderWidgetHostImpl* widget_host =
-      RenderWidgetHostImpl::From(web_contents->GetRenderViewHost());
+  RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
+      web_contents->GetRenderViewHost()->GetWidget());
   widget_host->ForwardGestureEvent(tap);
 }
 
 void SimulateTouchPressAt(WebContents* web_contents, const gfx::Point& point) {
   SyntheticWebTouchEvent touch;
   touch.PressPoint(point.x(), point.y());
-  RenderWidgetHostImpl* widget_host =
-      RenderWidgetHostImpl::From(web_contents->GetRenderViewHost());
+  RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
+      web_contents->GetRenderViewHost()->GetWidget());
   widget_host->ForwardTouchEventWithLatencyInfo(touch, ui::LatencyInfo());
 }
 
@@ -1047,7 +1050,8 @@
 
 bool RequestFrame(WebContents* web_contents) {
   DCHECK(web_contents);
-  return RenderWidgetHostImpl::From(web_contents->GetRenderViewHost())
+  return RenderWidgetHostImpl::From(
+             web_contents->GetRenderViewHost()->GetWidget())
       ->ScheduleComposite();
 }
 
@@ -1074,8 +1078,8 @@
 
 void FrameWatcher::AttachTo(WebContents* web_contents) {
   DCHECK(web_contents);
-  RenderWidgetHostImpl* widget_host =
-      RenderWidgetHostImpl::From(web_contents->GetRenderViewHost());
+  RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
+      web_contents->GetRenderViewHost()->GetWidget());
   widget_host->GetProcess()->AddFilter(this);
 }
 
diff --git a/content/public/test/test_renderer_host.cc b/content/public/test/test_renderer_host.cc
index d884779..ee61a312 100644
--- a/content/public/test/test_renderer_host.cc
+++ b/content/public/test/test_renderer_host.cc
@@ -70,7 +70,8 @@
 
 // static
 bool RenderViewHostTester::HasTouchEventHandler(RenderViewHost* rvh) {
-  RenderWidgetHostImpl* host_impl = RenderWidgetHostImpl::From(rvh);
+  RenderWidgetHostImpl* host_impl =
+      RenderWidgetHostImpl::From(rvh->GetWidget());
   return host_impl->has_touch_handler();
 }
 
diff --git a/content/shell/browser/blink_test_controller.cc b/content/shell/browser/blink_test_controller.cc
index 39ab1da..7b55670058 100644
--- a/content/shell/browser/blink_test_controller.cc
+++ b/content/shell/browser/blink_test_controller.cc
@@ -24,6 +24,7 @@
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/service_worker_context.h"
 #include "content/public/browser/storage_partition.h"
@@ -276,9 +277,15 @@
     // Shell::SizeTo is not implemented on all platforms.
     main_window_->SizeTo(initial_size_);
 #endif
-    main_window_->web_contents()->GetRenderViewHost()->GetView()
+    main_window_->web_contents()
+        ->GetRenderViewHost()
+        ->GetWidget()
+        ->GetView()
         ->SetSize(initial_size_);
-    main_window_->web_contents()->GetRenderViewHost()->WasResized();
+    main_window_->web_contents()
+        ->GetRenderViewHost()
+        ->GetWidget()
+        ->WasResized();
     RenderViewHost* render_view_host =
         main_window_->web_contents()->GetRenderViewHost();
     WebPreferences prefs = render_view_host->GetWebkitPreferences();
@@ -293,8 +300,9 @@
     main_window_->web_contents()->GetController().LoadURLWithParams(params);
     main_window_->web_contents()->Focus();
   }
-  main_window_->web_contents()->GetRenderViewHost()->SetActive(true);
-  main_window_->web_contents()->GetRenderViewHost()->Focus();
+  main_window_->web_contents()->GetRenderViewHost()->GetWidget()->SetActive(
+      true);
+  main_window_->web_contents()->GetRenderViewHost()->GetWidget()->Focus();
   return true;
 }
 
diff --git a/content/shell/browser/shell.cc b/content/shell/browser/shell.cc
index d903e62..13a0dcb 100644
--- a/content/shell/browser/shell.cc
+++ b/content/shell/browser/shell.cc
@@ -17,6 +17,7 @@
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/content_switches.h"
@@ -313,7 +314,7 @@
     return;
   if (is_fullscreen_ != enter_fullscreen) {
     is_fullscreen_ = enter_fullscreen;
-    web_contents->GetRenderViewHost()->WasResized();
+    web_contents->GetRenderViewHost()->GetWidget()->WasResized();
   }
 }
 
@@ -398,11 +399,11 @@
 }
 
 void Shell::ActivateContents(WebContents* contents) {
-  contents->GetRenderViewHost()->Focus();
+  contents->GetRenderViewHost()->GetWidget()->Focus();
 }
 
 void Shell::DeactivateContents(WebContents* contents) {
-  contents->GetRenderViewHost()->Blur();
+  contents->GetRenderViewHost()->GetWidget()->Blur();
 }
 
 bool Shell::HandleContextMenu(const content::ContextMenuParams& params) {
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index 39286be..62bf889 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -81,7 +81,6 @@
 
     self.Fail('conformance2/buffers/uniform-buffers.html', bug=483282)
     self.Fail('conformance2/glsl3/array-complex-indexing.html', bug=483282)
-    self.Fail('conformance2/glsl3/frag-depth.html', bug=483282)
     self.Fail('conformance2/glsl3/invalid-default-precision.html', bug=483282)
     self.Fail('conformance2/glsl3/sequence-operator-returns-non-constant.html',
         bug=483282)
@@ -103,6 +102,8 @@
         ['win'], bug=483282)
     self.Fail('conformance2/glsl3/array-in-complex-expression.html',
         ['win'], bug=483282)
+    self.Fail('conformance2/glsl3/frag-depth.html',
+        ['win'], bug=483282)
     self.Fail('conformance2/glsl3/short-circuiting-in-loop-condition.html',
         ['win'], bug=483282)
     self.Fail('conformance2/reading/read-pixels-from-fbo-test.html',
@@ -111,8 +112,6 @@
         ['win'], bug=1082) # angle bug ID
     self.Fail('conformance2/rendering/draw-buffers.html',
         ['win'], bug=483282)
-    self.Fail('conformance2/state/gl-get-calls.html',
-        ['win'], bug=483282)
     self.Fail('conformance2/state/gl-object-get-calls.html',
         ['win'], bug=483282)
     self.Fail('conformance2/textures/canvas/*', ['win'], bug=483282)
diff --git a/extensions/browser/app_window/app_window.cc b/extensions/browser/app_window/app_window.cc
index 0f24847..f3c9d97 100644
--- a/extensions/browser/app_window/app_window.cc
+++ b/extensions/browser/app_window/app_window.cc
@@ -20,6 +20,7 @@
 #include "content/public/browser/invalidate_type.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/resource_dispatcher_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.cc b/extensions/browser/guest_view/web_view/web_view_guest.cc
index f4d1cc4..6cf3d9f 100644
--- a/extensions/browser/guest_view/web_view/web_view_guest.cc
+++ b/extensions/browser/guest_view/web_view/web_view_guest.cc
@@ -23,6 +23,7 @@
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/resource_request_details.h"
 #include "content/public/browser/site_instance.h"
@@ -453,11 +454,15 @@
   // interstitial page if one is showing at this time. We only want opacity
   // to apply to web pages.
   if (allow_transparency_) {
-    web_contents()->GetRenderViewHost()->GetView()->SetBackgroundColor(
-        SK_ColorTRANSPARENT);
+    web_contents()
+        ->GetRenderViewHost()
+        ->GetWidget()
+        ->GetView()
+        ->SetBackgroundColor(SK_ColorTRANSPARENT);
   } else {
     web_contents()
         ->GetRenderViewHost()
+        ->GetWidget()
         ->GetView()
         ->SetBackgroundColorToDefault();
   }
@@ -1157,15 +1162,19 @@
     return;
 
   allow_transparency_ = allow;
-  if (!web_contents()->GetRenderViewHost()->GetView())
+  if (!web_contents()->GetRenderViewHost()->GetWidget()->GetView())
     return;
 
   if (allow_transparency_) {
-    web_contents()->GetRenderViewHost()->GetView()->SetBackgroundColor(
-        SK_ColorTRANSPARENT);
+    web_contents()
+        ->GetRenderViewHost()
+        ->GetWidget()
+        ->GetView()
+        ->SetBackgroundColor(SK_ColorTRANSPARENT);
   } else {
     web_contents()
         ->GetRenderViewHost()
+        ->GetWidget()
         ->GetView()
         ->SetBackgroundColorToDefault();
   }
@@ -1487,7 +1496,7 @@
   }
   // Since we changed fullscreen state, sending a Resize message ensures that
   // renderer/ sees the change.
-  web_contents()->GetRenderViewHost()->WasResized();
+  web_contents()->GetRenderViewHost()->GetWidget()->WasResized();
 }
 
 }  // namespace extensions
diff --git a/extensions/browser/load_monitoring_extension_host_queue_unittest.cc b/extensions/browser/load_monitoring_extension_host_queue_unittest.cc
index c4e2e441..cd080b79 100644
--- a/extensions/browser/load_monitoring_extension_host_queue_unittest.cc
+++ b/extensions/browser/load_monitoring_extension_host_queue_unittest.cc
@@ -4,6 +4,7 @@
 
 #include <limits>
 
+#include "base/bind.h"
 #include "base/memory/scoped_vector.h"
 #include "base/run_loop.h"
 #include "content/public/test/test_browser_thread_bundle.h"
diff --git a/extensions/common/permissions/permissions_data.cc b/extensions/common/permissions/permissions_data.cc
index 7c001a5..ea66b6cc 100644
--- a/extensions/common/permissions/permissions_data.cc
+++ b/extensions/common/permissions/permissions_data.cc
@@ -72,21 +72,6 @@
 }
 
 // static
-bool PermissionsData::ScriptsMayRequireActionForExtension(
-    const Extension* extension,
-    const PermissionSet& permissions) {
-  // An extension may require user action to execute scripts iff the extension
-  // shows up in chrome:extensions (so the user can grant withheld permissions),
-  // is not part of chrome or corporate policy, not on the scripting whitelist,
-  // and requires enough permissions that we should withhold them.
-  return extension->ShouldDisplayInExtensionSettings() &&
-         !Manifest::IsPolicyLocation(extension->location()) &&
-         !Manifest::IsComponentLocation(extension->location()) &&
-         !CanExecuteScriptEverywhere(extension) &&
-         permissions.ShouldWarnAllHosts();
-}
-
-// static
 bool PermissionsData::ShouldSkipPermissionWarnings(
     const std::string& extension_id) {
   // See http://b/4946060 for more details.
diff --git a/extensions/common/permissions/permissions_data.h b/extensions/common/permissions/permissions_data.h
index 19fbe02..5de25c2 100644
--- a/extensions/common/permissions/permissions_data.h
+++ b/extensions/common/permissions/permissions_data.h
@@ -72,14 +72,6 @@
   // whitelist of extensions that can script all pages.
   static bool CanExecuteScriptEverywhere(const Extension* extension);
 
-  // Returns true if the --scripts-require-action flag would possibly affect
-  // the given |extension| and |permissions|. We pass in the |permissions|
-  // explicitly, as we may need to check with permissions other than the ones
-  // that are currently on the extension's PermissionsData.
-  static bool ScriptsMayRequireActionForExtension(
-      const Extension* extension,
-      const PermissionSet& permissions);
-
   // Returns true if we should skip the permissions warning for the extension
   // with the given |extension_id|.
   static bool ShouldSkipPermissionWarnings(const std::string& extension_id);
diff --git a/extensions/components/native_app_window/native_app_window_views.cc b/extensions/components/native_app_window/native_app_window_views.cc
index b060233b..1b6fa9e 100644
--- a/extensions/components/native_app_window/native_app_window_views.cc
+++ b/extensions/components/native_app_window/native_app_window_views.cc
@@ -6,6 +6,7 @@
 
 #include "base/threading/sequenced_worker_pool.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/browser/app_window/app_window.h"
@@ -297,7 +298,8 @@
 void NativeAppWindowViews::RenderViewCreated(
     content::RenderViewHost* render_view_host) {
   if (app_window_->requested_alpha_enabled() && CanHaveAlphaEnabled()) {
-    content::RenderWidgetHostView* view = render_view_host->GetView();
+    content::RenderWidgetHostView* view =
+        render_view_host->GetWidget()->GetView();
     DCHECK(view);
     view->SetBackgroundColor(SK_ColorTRANSPARENT);
   }
diff --git a/ios/chrome/browser/tab_parenting_global_observer.cc b/ios/chrome/browser/tab_parenting_global_observer.cc
new file mode 100644
index 0000000..1ed07d1
--- /dev/null
+++ b/ios/chrome/browser/tab_parenting_global_observer.cc
@@ -0,0 +1,24 @@
+// Copyright 2015 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 "ios/chrome/browser/tab_parenting_global_observer.h"
+
+#include "base/memory/singleton.h"
+
+TabParentingGlobalObserver* TabParentingGlobalObserver::GetInstance() {
+  return base::Singleton<TabParentingGlobalObserver>::get();
+}
+
+scoped_ptr<base::CallbackList<void(web::WebState*)>::Subscription>
+TabParentingGlobalObserver::RegisterCallback(const OnTabParentedCallback& cb) {
+  return on_tab_parented_callback_list_.Add(cb);
+}
+
+void TabParentingGlobalObserver::OnTabParented(web::WebState* web_state) {
+  on_tab_parented_callback_list_.Notify(web_state);
+}
+
+TabParentingGlobalObserver::TabParentingGlobalObserver() {}
+
+TabParentingGlobalObserver::~TabParentingGlobalObserver() {}
diff --git a/ios/chrome/browser/tab_parenting_global_observer.h b/ios/chrome/browser/tab_parenting_global_observer.h
new file mode 100644
index 0000000..61f64ac
--- /dev/null
+++ b/ios/chrome/browser/tab_parenting_global_observer.h
@@ -0,0 +1,49 @@
+// Copyright 2015 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_TAB_PARENTING_GLOBAL_OBSERVER_H_
+#define IOS_CHROME_BROWSER_TAB_PARENTING_GLOBAL_OBSERVER_H_
+
+#include "base/callback_list.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace base {
+template <typename T>
+struct DefaultSingletonTraits;
+}  // namespace base
+
+namespace web {
+class WebState;
+}
+
+// Allows clients to observe every tab (i.e., WebState) that is parented.
+// NOTE: Should be used only to correspond to //chrome flows that listen for
+// the TAB_PARENTED notification from all sources.
+class TabParentingGlobalObserver {
+ public:
+  typedef base::Callback<void(web::WebState*)> OnTabParentedCallback;
+
+  // Returns the instance of TabParentingGlobalObserver.
+  static TabParentingGlobalObserver* GetInstance();
+
+  // Registers |cb| to be invoked when a tab is parented.
+  scoped_ptr<base::CallbackList<void(web::WebState*)>::Subscription>
+  RegisterCallback(const OnTabParentedCallback& cb);
+
+  // Called to notify all registered callbacks that |web_state| was parented.
+  void OnTabParented(web::WebState* web_state);
+
+ private:
+  friend struct base::DefaultSingletonTraits<TabParentingGlobalObserver>;
+
+  TabParentingGlobalObserver();
+  ~TabParentingGlobalObserver();
+
+  base::CallbackList<void(web::WebState*)> on_tab_parented_callback_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(TabParentingGlobalObserver);
+};
+
+#endif  // IOS_CHROME_BROWSER_TAB_PARENTING_GLOBAL_OBSERVER_H_
diff --git a/ios/chrome/ios_chrome.gyp b/ios/chrome/ios_chrome.gyp
index 2eeb37e8..9a156121 100644
--- a/ios/chrome/ios_chrome.gyp
+++ b/ios/chrome/ios_chrome.gyp
@@ -401,6 +401,8 @@
         'browser/sync/sync_setup_service.h',
         'browser/sync/sync_setup_service_factory.cc',
         'browser/sync/sync_setup_service_factory.h',
+        'browser/tab_parenting_global_observer.cc',
+        'browser/tab_parenting_global_observer.h',
         'browser/translate/after_translate_infobar_controller.h',
         'browser/translate/after_translate_infobar_controller.mm',
         'browser/translate/before_translate_infobar_controller.h',
diff --git a/net/cookies/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc
index 203dd10..839add8 100644
--- a/net/cookies/cookie_monster_unittest.cc
+++ b/net/cookies/cookie_monster_unittest.cc
@@ -70,7 +70,6 @@
 const char kTopLevelDomainPlus2Secure[] = "https://www.math.harvard.edu";
 const char kTopLevelDomainPlus3[] = "http://www.bourbaki.math.harvard.edu";
 const char kOtherDomain[] = "http://www.mit.edu";
-const char kUrlGoogleSpecific[] = "http://www.gmail.google.izzle";
 
 class GetCookieListCallback : public CookieCallback {
  public:
@@ -359,8 +358,9 @@
       scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
       for (int i = 0; i < more_than_enough_cookies; ++i) {
         std::string cookie = base::StringPrintf("a%03d=b", i);
-        EXPECT_TRUE(SetCookie(cm.get(), url_google_, cookie));
-        std::string cookies = this->GetCookies(cm.get(), url_google_);
+        EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), cookie));
+        std::string cookies =
+            this->GetCookies(cm.get(), http_www_google_.url());
         // Make sure we find it in the cookies.
         EXPECT_NE(cookies.find(cookie), std::string::npos);
         // Count the number of cookies.
@@ -371,15 +371,17 @@
     // Add a bunch of cookies on multiple hosts within a single eTLD.
     // Should keep at least kDomainMaxCookies - kDomainPurgeCookies
     // between them.  We shouldn't go above kDomainMaxCookies for both together.
-    GURL url_google_specific(kUrlGoogleSpecific);
+    GURL url_google_specific(http_www_google_.Format("http://www.gmail.%D"));
     {
       scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
       for (int i = 0; i < more_than_enough_cookies; ++i) {
         std::string cookie_general = base::StringPrintf("a%03d=b", i);
-        EXPECT_TRUE(SetCookie(cm.get(), url_google_, cookie_general));
+        EXPECT_TRUE(
+            SetCookie(cm.get(), http_www_google_.url(), cookie_general));
         std::string cookie_specific = base::StringPrintf("c%03d=b", i);
         EXPECT_TRUE(SetCookie(cm.get(), url_google_specific, cookie_specific));
-        std::string cookies_general = this->GetCookies(cm.get(), url_google_);
+        std::string cookies_general =
+            this->GetCookies(cm.get(), http_www_google_.url());
         EXPECT_NE(cookies_general.find(cookie_general), std::string::npos);
         std::string cookies_specific =
             this->GetCookies(cm.get(), url_google_specific);
@@ -390,7 +392,8 @@
       }
       // After all this, there should be at least
       // kDomainMaxCookies - kDomainPurgeCookies for both URLs.
-      std::string cookies_general = this->GetCookies(cm.get(), url_google_);
+      std::string cookies_general =
+          this->GetCookies(cm.get(), http_www_google_.url());
       std::string cookies_specific =
           this->GetCookies(cm.get(), url_google_specific);
       int total_cookies = (CountInString(cookies_general, '=') +
@@ -413,8 +416,8 @@
     return COOKIE_PRIORITY_DEFAULT;
   }
 
-  // Instantiates a CookieMonster, adds multiple cookies (to url_google_) with
-  // priorities specified by |coded_priority_str|, and tests priority-aware
+  // Instantiates a CookieMonster, adds multiple cookies (to http_www_google_)
+  // with priorities specified by |coded_priority_str|, and tests priority-aware
   // domain cookie eviction.
   // |coded_priority_str| specifies a run-length-encoded string of priorities.
   // Example: "2M 3L M 4H" means "MMLLLMHHHH", and speicifies sequential (i.e.,
@@ -453,7 +456,7 @@
       for (; rep > 0; --rep, ++next_cookie_id) {
         std::string cookie = base::StringPrintf(
             "a%d=b;priority=%s", next_cookie_id, priority_str.c_str());
-        EXPECT_TRUE(SetCookie(cm, url_google_, cookie));
+        EXPECT_TRUE(SetCookie(cm, http_www_google_.url(), cookie));
         priority_list.push_back(priority);
         id_list[priority].push_back(next_cookie_id);
       }
@@ -463,7 +466,7 @@
     std::vector<int> surviving_id_list[3];  // Indexed by CookiePriority.
 
     // Parse the list of cookies
-    std::string cookie_str = this->GetCookies(cm, url_google_);
+    std::string cookie_str = this->GetCookies(cm, http_www_google_.url());
     for (const std::string& token : base::SplitString(
              cookie_str, ";", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
       // Assuming *it is "a#=b", so extract and parse "#" portion.
@@ -816,20 +819,21 @@
 };
 
 TEST_F(DeferredCookieTaskTest, DeferredGetCookies) {
-  DeclareLoadedCookie("www.google.izzle",
+  DeclareLoadedCookie(http_www_google_.host(),
                       "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
                       Time::Now() + TimeDelta::FromDays(3));
 
   MockGetCookiesCallback get_cookies_callback;
 
   BeginWithForDomainKey(
-      "google.izzle",
-      GetCookiesAction(&cookie_monster(), url_google_, &get_cookies_callback));
+      http_www_google_.domain(),
+      GetCookiesAction(&cookie_monster(), http_www_google_.url(),
+                       &get_cookies_callback));
 
   WaitForLoadCall();
 
   EXPECT_CALL(get_cookies_callback, Invoke("X=1"))
-      .WillOnce(GetCookiesAction(&cookie_monster(), url_google_,
+      .WillOnce(GetCookiesAction(&cookie_monster(), http_www_google_.url(),
                                  &get_cookies_callback));
   EXPECT_CALL(get_cookies_callback, Invoke("X=1"))
       .WillOnce(QuitCurrentMessageLoop());
@@ -840,15 +844,16 @@
 TEST_F(DeferredCookieTaskTest, DeferredSetCookie) {
   MockSetCookiesCallback set_cookies_callback;
 
-  BeginWithForDomainKey("google.izzle",
-                        SetCookieAction(&cookie_monster(), url_google_, "A=B",
-                                        &set_cookies_callback));
+  BeginWithForDomainKey(
+      http_www_google_.domain(),
+      SetCookieAction(&cookie_monster(), http_www_google_.url(), "A=B",
+                      &set_cookies_callback));
 
   WaitForLoadCall();
 
   EXPECT_CALL(set_cookies_callback, Invoke(true))
-      .WillOnce(SetCookieAction(&cookie_monster(), url_google_, "X=Y",
-                                &set_cookies_callback));
+      .WillOnce(SetCookieAction(&cookie_monster(), http_www_google_.url(),
+                                "X=Y", &set_cookies_callback));
   EXPECT_CALL(set_cookies_callback, Invoke(true))
       .WillOnce(QuitCurrentMessageLoop());
 
@@ -858,10 +863,12 @@
 TEST_F(DeferredCookieTaskTest, DeferredSetAllCookies) {
   MockSetCookiesCallback set_cookies_callback;
   CookieList list;
-  list.push_back(CanonicalCookie(url_google_, "A", "B", "google.izzle", "/",
+  list.push_back(CanonicalCookie(http_www_google_.url(), "A", "B",
+                                 http_www_google_.domain(), "/",
                                  base::Time::Now(), base::Time(), base::Time(),
                                  false, true, false, COOKIE_PRIORITY_DEFAULT));
-  list.push_back(CanonicalCookie(url_google_, "C", "D", "google.izzle", "/",
+  list.push_back(CanonicalCookie(http_www_google_.url(), "C", "D",
+                                 http_www_google_.domain(), "/",
                                  base::Time::Now(), base::Time(), base::Time(),
                                  false, true, false, COOKIE_PRIORITY_DEFAULT));
 
@@ -882,15 +889,16 @@
 TEST_F(DeferredCookieTaskTest, DeferredDeleteCookie) {
   MockClosure delete_cookie_callback;
 
-  BeginWithForDomainKey("google.izzle",
-                        DeleteCookieAction(&cookie_monster(), url_google_, "A",
-                                           &delete_cookie_callback));
+  BeginWithForDomainKey(
+      http_www_google_.domain(),
+      DeleteCookieAction(&cookie_monster(), http_www_google_.url(), "A",
+                         &delete_cookie_callback));
 
   WaitForLoadCall();
 
   EXPECT_CALL(delete_cookie_callback, Invoke())
-      .WillOnce(DeleteCookieAction(&cookie_monster(), url_google_, "X",
-                                   &delete_cookie_callback));
+      .WillOnce(DeleteCookieAction(&cookie_monster(), http_www_google_.url(),
+                                   "X", &delete_cookie_callback));
   EXPECT_CALL(delete_cookie_callback, Invoke())
       .WillOnce(QuitCurrentMessageLoop());
 
@@ -900,7 +908,7 @@
 TEST_F(DeferredCookieTaskTest, DeferredSetCookieWithDetails) {
   MockSetCookiesCallback set_cookies_callback;
 
-  CookiesInputInfo cookie_info = {url_google_foo_,
+  CookiesInputInfo cookie_info = {www_google_foo_.url(),
                                   "A",
                                   "B",
                                   std::string(),
@@ -911,12 +919,13 @@
                                   false,
                                   COOKIE_PRIORITY_DEFAULT};
   BeginWithForDomainKey(
-      "google.izzle", SetCookieWithDetailsAction(&cookie_monster(), cookie_info,
-                                                 &set_cookies_callback));
+      http_www_google_.domain(),
+      SetCookieWithDetailsAction(&cookie_monster(), cookie_info,
+                                 &set_cookies_callback));
 
   WaitForLoadCall();
 
-  CookiesInputInfo cookie_info_exp = {url_google_foo_,
+  CookiesInputInfo cookie_info_exp = {www_google_foo_.url(),
                                       "A",
                                       "B",
                                       std::string(),
@@ -936,7 +945,7 @@
 }
 
 TEST_F(DeferredCookieTaskTest, DeferredGetAllCookies) {
-  DeclareLoadedCookie("www.google.izzle",
+  DeclareLoadedCookie(http_www_google_.host(),
                       "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
                       Time::Now() + TimeDelta::FromDays(3));
 
@@ -956,20 +965,22 @@
 }
 
 TEST_F(DeferredCookieTaskTest, DeferredGetAllForUrlCookies) {
-  DeclareLoadedCookie("www.google.izzle",
+  DeclareLoadedCookie(http_www_google_.host(),
                       "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
                       Time::Now() + TimeDelta::FromDays(3));
 
   MockGetCookieListCallback get_cookie_list_callback;
 
   BeginWithForDomainKey(
-      "google.izzle", GetAllCookiesForUrlAction(&cookie_monster(), url_google_,
-                                                &get_cookie_list_callback));
+      http_www_google_.domain(),
+      GetAllCookiesForUrlAction(&cookie_monster(), http_www_google_.url(),
+                                &get_cookie_list_callback));
 
   WaitForLoadCall();
 
   EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_))
-      .WillOnce(GetAllCookiesForUrlAction(&cookie_monster(), url_google_,
+      .WillOnce(GetAllCookiesForUrlAction(&cookie_monster(),
+                                          http_www_google_.url(),
                                           &get_cookie_list_callback));
   EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_))
       .WillOnce(QuitCurrentMessageLoop());
@@ -978,21 +989,23 @@
 }
 
 TEST_F(DeferredCookieTaskTest, DeferredGetAllForUrlWithOptionsCookies) {
-  DeclareLoadedCookie("www.google.izzle",
+  DeclareLoadedCookie(http_www_google_.host(),
                       "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
                       Time::Now() + TimeDelta::FromDays(3));
 
   MockGetCookieListCallback get_cookie_list_callback;
 
-  BeginWithForDomainKey("google.izzle", GetAllCookiesForUrlWithOptionsAction(
-                                            &cookie_monster(), url_google_,
-                                            &get_cookie_list_callback));
+  BeginWithForDomainKey(http_www_google_.domain(),
+                        GetAllCookiesForUrlWithOptionsAction(
+                            &cookie_monster(), http_www_google_.url(),
+                            &get_cookie_list_callback));
 
   WaitForLoadCall();
 
   EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_))
       .WillOnce(GetAllCookiesForUrlWithOptionsAction(
-          &cookie_monster(), url_google_, &get_cookie_list_callback));
+          &cookie_monster(), http_www_google_.url(),
+          &get_cookie_list_callback));
   EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_))
       .WillOnce(QuitCurrentMessageLoop());
 
@@ -1036,14 +1049,15 @@
   MockDeleteCallback delete_callback;
 
   BeginWithForDomainKey(
-      "google.izzle",
-      DeleteAllForHostAction(&cookie_monster(), url_google_, &delete_callback));
+      http_www_google_.domain(),
+      DeleteAllForHostAction(&cookie_monster(), http_www_google_.url(),
+                             &delete_callback));
 
   WaitForLoadCall();
 
   EXPECT_CALL(delete_callback, Invoke(false))
-      .WillOnce(DeleteAllForHostAction(&cookie_monster(), url_google_,
-                                       &delete_callback));
+      .WillOnce(DeleteAllForHostAction(
+          &cookie_monster(), http_www_google_.url(), &delete_callback));
   EXPECT_CALL(delete_callback, Invoke(false))
       .WillOnce(QuitCurrentMessageLoop());
 
@@ -1052,8 +1066,8 @@
 
 TEST_F(DeferredCookieTaskTest, DeferredDeleteCanonicalCookie) {
   std::vector<CanonicalCookie*> cookies;
-  CanonicalCookie cookie =
-      BuildCanonicalCookie("www.google.com", "X=1; path=/", base::Time::Now());
+  CanonicalCookie cookie = BuildCanonicalCookie(
+      http_www_google_.host(), "X=1; path=/", base::Time::Now());
 
   MockDeleteCookieCallback delete_cookie_callback;
 
@@ -1091,7 +1105,7 @@
 // the backing store and that new tasks received while the queued tasks are
 // being dispatched go to the end of the queue.
 TEST_F(DeferredCookieTaskTest, DeferredTaskOrder) {
-  DeclareLoadedCookie("www.google.izzle",
+  DeclareLoadedCookie(http_www_google_.host(),
                       "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
                       Time::Now() + TimeDelta::FromDays(3));
 
@@ -1100,17 +1114,18 @@
   MockGetCookiesCallback get_cookies_callback_deferred;
 
   EXPECT_CALL(*this, Begin())
-      .WillOnce(testing::DoAll(GetCookiesAction(&cookie_monster(), url_google_,
-                                                &get_cookies_callback),
-                               SetCookieAction(&cookie_monster(), url_google_,
-                                               "A=B", &set_cookies_callback)));
+      .WillOnce(testing::DoAll(
+          GetCookiesAction(&cookie_monster(), http_www_google_.url(),
+                           &get_cookies_callback),
+          SetCookieAction(&cookie_monster(), http_www_google_.url(), "A=B",
+                          &set_cookies_callback)));
   ExpectLoadCall();
-  ExpectLoadForKeyCall("google.izzle", false);
+  ExpectLoadForKeyCall(http_www_google_.domain(), false);
   Begin();
 
   WaitForLoadCall();
   EXPECT_CALL(get_cookies_callback, Invoke("X=1"))
-      .WillOnce(GetCookiesAction(&cookie_monster(), url_google_,
+      .WillOnce(GetCookiesAction(&cookie_monster(), http_www_google_.url(),
                                  &get_cookies_callback_deferred));
   EXPECT_CALL(set_cookies_callback, Invoke(true));
   EXPECT_CALL(get_cookies_callback_deferred, Invoke("A=B; X=1"))
@@ -1125,20 +1140,22 @@
   CookieOptions options;
   options.set_include_httponly();
 
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, kValidCookieLine));
-  EXPECT_EQ("A=B", GetCookies(cm.get(), url_google_));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), kValidCookieLine));
+  EXPECT_EQ("A=B", GetCookies(cm.get(), http_www_google_.url()));
 
-  EXPECT_TRUE(
-      SetCookieWithOptions(cm.get(), url_google_, "C=D; httponly", options));
-  EXPECT_EQ("A=B; C=D", GetCookiesWithOptions(cm.get(), url_google_, options));
+  EXPECT_TRUE(SetCookieWithOptions(cm.get(), http_www_google_.url(),
+                                   "C=D; httponly", options));
+  EXPECT_EQ("A=B; C=D",
+            GetCookiesWithOptions(cm.get(), http_www_google_.url(), options));
 
   EXPECT_EQ(2, DeleteAll(cm.get()));
-  EXPECT_EQ("", GetCookiesWithOptions(cm.get(), url_google_, options));
+  EXPECT_EQ("",
+            GetCookiesWithOptions(cm.get(), http_www_google_.url(), options));
   EXPECT_EQ(0u, store->commands().size());
 
   // Create a persistent cookie.
   EXPECT_TRUE(SetCookie(
-      cm.get(), url_google_,
+      cm.get(), http_www_google_.url(),
       std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-22 22:50:13 GMT"));
   ASSERT_EQ(1u, store->commands().size());
   EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type);
@@ -1147,7 +1164,8 @@
   ASSERT_EQ(2u, store->commands().size());
   EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
 
-  EXPECT_EQ("", GetCookiesWithOptions(cm.get(), url_google_, options));
+  EXPECT_EQ("",
+            GetCookiesWithOptions(cm.get(), http_www_google_.url(), options));
 }
 
 TEST_F(CookieMonsterTest, TestCookieDeleteAllCreatedBetweenTimestamps) {
@@ -1159,15 +1177,16 @@
                                        Time()));
 
   // Create 3 cookies with creation date of today, yesterday and the day before.
-  EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-0=Now", now));
-  EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-1=Yesterday",
-                                            now - TimeDelta::FromDays(1)));
-  EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-2=DayBefore",
-                                            now - TimeDelta::FromDays(2)));
-  EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-3=ThreeDays",
-                                            now - TimeDelta::FromDays(3)));
-  EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-7=LastWeek",
-                                            now - TimeDelta::FromDays(7)));
+  EXPECT_TRUE(
+      cm->SetCookieWithCreationTime(http_www_google_.url(), "T-0=Now", now));
+  EXPECT_TRUE(cm->SetCookieWithCreationTime(
+      http_www_google_.url(), "T-1=Yesterday", now - TimeDelta::FromDays(1)));
+  EXPECT_TRUE(cm->SetCookieWithCreationTime(
+      http_www_google_.url(), "T-2=DayBefore", now - TimeDelta::FromDays(2)));
+  EXPECT_TRUE(cm->SetCookieWithCreationTime(
+      http_www_google_.url(), "T-3=ThreeDays", now - TimeDelta::FromDays(3)));
+  EXPECT_TRUE(cm->SetCookieWithCreationTime(
+      http_www_google_.url(), "T-7=LastWeek", now - TimeDelta::FromDays(7)));
 
   // Try to delete threedays and the daybefore.
   EXPECT_EQ(2, DeleteAllCreatedBetween(cm.get(), now - TimeDelta::FromDays(3),
@@ -1195,18 +1214,18 @@
   scoped_refptr<CookieMonster> cm(
       new CookieMonster(NULL, NULL, kLastAccessThresholdMilliseconds));
 
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "A=B"));
   const Time last_access_date(GetFirstCookieAccessDate(cm.get()));
 
   // Reading the cookie again immediately shouldn't update the access date,
   // since we're inside the threshold.
-  EXPECT_EQ("A=B", GetCookies(cm.get(), url_google_));
+  EXPECT_EQ("A=B", GetCookies(cm.get(), http_www_google_.url()));
   EXPECT_TRUE(last_access_date == GetFirstCookieAccessDate(cm.get()));
 
   // Reading after a short wait should update the access date.
   base::PlatformThread::Sleep(
       base::TimeDelta::FromMilliseconds(kAccessDelayMs));
-  EXPECT_EQ("A=B", GetCookies(cm.get(), url_google_));
+  EXPECT_EQ("A=B", GetCookies(cm.get(), http_www_google_.url()));
   EXPECT_FALSE(last_access_date == GetFirstCookieAccessDate(cm.get()));
 }
 
@@ -1221,16 +1240,17 @@
 TEST_F(CookieMonsterTest, TestDeleteSingleCookie) {
   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
 
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "C=D"));
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "E=F"));
-  EXPECT_EQ("A=B; C=D; E=F", GetCookies(cm.get(), url_google_));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "A=B"));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "C=D"));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "E=F"));
+  EXPECT_EQ("A=B; C=D; E=F", GetCookies(cm.get(), http_www_google_.url()));
 
-  EXPECT_TRUE(FindAndDeleteCookie(cm.get(), url_google_.host(), "C"));
-  EXPECT_EQ("A=B; E=F", GetCookies(cm.get(), url_google_));
+  EXPECT_TRUE(
+      FindAndDeleteCookie(cm.get(), http_www_google_.url().host(), "C"));
+  EXPECT_EQ("A=B; E=F", GetCookies(cm.get(), http_www_google_.url()));
 
   EXPECT_FALSE(FindAndDeleteCookie(cm.get(), "random.host", "E"));
-  EXPECT_EQ("A=B; E=F", GetCookies(cm.get(), url_google_));
+  EXPECT_EQ("A=B; E=F", GetCookies(cm.get(), http_www_google_.url()));
 }
 
 TEST_F(CookieMonsterTest, SetCookieableSchemes) {
@@ -1258,13 +1278,14 @@
   CookieOptions options;
   options.set_include_httponly();
 
-  EXPECT_TRUE(
-      SetCookieWithOptions(cm.get(), url_google_, "A=B; httponly", options));
-  EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_,
-                                   "C=D; domain=.google.izzle", options));
-  EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_secure_,
-                                   "E=F; domain=.google.izzle; secure",
+  EXPECT_TRUE(SetCookieWithOptions(cm.get(), http_www_google_.url(),
+                                   "A=B; httponly", options));
+  EXPECT_TRUE(SetCookieWithOptions(cm.get(), http_www_google_.url(),
+                                   http_www_google_.Format("C=D; domain=.%D"),
                                    options));
+  EXPECT_TRUE(SetCookieWithOptions(
+      cm.get(), https_www_google_.url(),
+      http_www_google_.Format("E=F; domain=.%D; secure"), options));
 
   const Time last_access_date(GetFirstCookieAccessDate(cm.get()));
 
@@ -1272,44 +1293,44 @@
       base::TimeDelta::FromMilliseconds(kAccessDelayMs));
 
   // Check cookies for url.
-  CookieList cookies = GetAllCookiesForURL(cm.get(), url_google_);
+  CookieList cookies = GetAllCookiesForURL(cm.get(), http_www_google_.url());
   CookieList::iterator it = cookies.begin();
 
   ASSERT_TRUE(it != cookies.end());
-  EXPECT_EQ("www.google.izzle", it->Domain());
+  EXPECT_EQ(http_www_google_.host(), it->Domain());
   EXPECT_EQ("A", it->Name());
 
   ASSERT_TRUE(++it != cookies.end());
-  EXPECT_EQ(".google.izzle", it->Domain());
+  EXPECT_EQ(http_www_google_.Format(".%D"), it->Domain());
   EXPECT_EQ("C", it->Name());
 
   ASSERT_TRUE(++it == cookies.end());
 
   // Check cookies for url excluding http-only cookies.
-  cookies =
-      GetAllCookiesForURLWithOptions(cm.get(), url_google_, CookieOptions());
+  cookies = GetAllCookiesForURLWithOptions(cm.get(), http_www_google_.url(),
+                                           CookieOptions());
   it = cookies.begin();
 
   ASSERT_TRUE(it != cookies.end());
-  EXPECT_EQ(".google.izzle", it->Domain());
+  EXPECT_EQ(http_www_google_.Format(".%D"), it->Domain());
   EXPECT_EQ("C", it->Name());
 
   ASSERT_TRUE(++it == cookies.end());
 
   // Test secure cookies.
-  cookies = GetAllCookiesForURL(cm.get(), url_google_secure_);
+  cookies = GetAllCookiesForURL(cm.get(), https_www_google_.url());
   it = cookies.begin();
 
   ASSERT_TRUE(it != cookies.end());
-  EXPECT_EQ("www.google.izzle", it->Domain());
+  EXPECT_EQ(http_www_google_.host(), it->Domain());
   EXPECT_EQ("A", it->Name());
 
   ASSERT_TRUE(++it != cookies.end());
-  EXPECT_EQ(".google.izzle", it->Domain());
+  EXPECT_EQ(http_www_google_.Format(".%D"), it->Domain());
   EXPECT_EQ("C", it->Name());
 
   ASSERT_TRUE(++it != cookies.end());
-  EXPECT_EQ(".google.izzle", it->Domain());
+  EXPECT_EQ(http_www_google_.Format(".%D"), it->Domain());
   EXPECT_EQ("E", it->Name());
 
   ASSERT_TRUE(++it == cookies.end());
@@ -1322,13 +1343,14 @@
   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
   CookieOptions options;
 
-  EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_foo_, "A=B; path=/foo;",
-                                   options));
-  EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_bar_, "C=D; path=/bar;",
-                                   options));
-  EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "E=F;", options));
+  EXPECT_TRUE(SetCookieWithOptions(cm.get(), www_google_foo_.url(),
+                                   "A=B; path=/foo;", options));
+  EXPECT_TRUE(SetCookieWithOptions(cm.get(), www_google_bar_.url(),
+                                   "C=D; path=/bar;", options));
+  EXPECT_TRUE(
+      SetCookieWithOptions(cm.get(), http_www_google_.url(), "E=F;", options));
 
-  CookieList cookies = GetAllCookiesForURL(cm.get(), url_google_foo_);
+  CookieList cookies = GetAllCookiesForURL(cm.get(), www_google_foo_.url());
   CookieList::iterator it = cookies.begin();
 
   ASSERT_TRUE(it != cookies.end());
@@ -1341,7 +1363,7 @@
 
   ASSERT_TRUE(++it == cookies.end());
 
-  cookies = GetAllCookiesForURL(cm.get(), url_google_bar_);
+  cookies = GetAllCookiesForURL(cm.get(), www_google_bar_.url());
   it = cookies.begin();
 
   ASSERT_TRUE(it != cookies.end());
@@ -1358,15 +1380,18 @@
 TEST_F(CookieMonsterTest, CookieSorting) {
   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
 
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=B1; path=/"));
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=B2; path=/foo"));
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=B3; path=/foo/bar"));
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=A1; path=/"));
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=A2; path=/foo"));
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=A3; path=/foo/bar"));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "B=B1; path=/"));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "B=B2; path=/foo"));
+  EXPECT_TRUE(
+      SetCookie(cm.get(), http_www_google_.url(), "B=B3; path=/foo/bar"));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "A=A1; path=/"));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "A=A2; path=/foo"));
+  EXPECT_TRUE(
+      SetCookie(cm.get(), http_www_google_.url(), "A=A3; path=/foo/bar"));
 
   // Re-set cookie which should not change sort order.
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=B3; path=/foo/bar"));
+  EXPECT_TRUE(
+      SetCookie(cm.get(), http_www_google_.url(), "B=B3; path=/foo/bar"));
 
   CookieList cookies = GetAllCookies(cm.get());
   ASSERT_EQ(6u, cookies.size());
@@ -1385,14 +1410,14 @@
 TEST_F(CookieMonsterTest, DeleteCookieByName) {
   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
 
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=A1; path=/"));
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=A2; path=/foo"));
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=A3; path=/bar"));
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=B1; path=/"));
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=B2; path=/foo"));
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=B3; path=/bar"));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "A=A1; path=/"));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "A=A2; path=/foo"));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "A=A3; path=/bar"));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "B=B1; path=/"));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "B=B2; path=/foo"));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "B=B3; path=/bar"));
 
-  DeleteCookie(cm.get(), GURL(std::string(kUrlGoogle) + "/foo/bar"), "A");
+  DeleteCookie(cm.get(), http_www_google_.AppendPath("foo/bar"), "A");
 
   CookieList cookies = GetAllCookies(cm.get());
   size_t expected_size = 4;
@@ -1407,11 +1432,12 @@
   scoped_refptr<CookieMonster> cm_1(new CookieMonster(NULL, NULL));
   CookieOptions options;
 
-  EXPECT_TRUE(SetCookieWithOptions(cm_1.get(), url_google_foo_,
+  EXPECT_TRUE(SetCookieWithOptions(cm_1.get(), www_google_foo_.url(),
                                    "A1=B; path=/foo;", options));
-  EXPECT_TRUE(SetCookieWithOptions(cm_1.get(), url_google_bar_,
+  EXPECT_TRUE(SetCookieWithOptions(cm_1.get(), www_google_bar_.url(),
                                    "A2=D; path=/bar;", options));
-  EXPECT_TRUE(SetCookieWithOptions(cm_1.get(), url_google_, "A3=F;", options));
+  EXPECT_TRUE(SetCookieWithOptions(cm_1.get(), http_www_google_.url(), "A3=F;",
+                                   options));
 
   CookieList cookies_1 = GetAllCookies(cm_1.get());
   scoped_refptr<CookieMonster> cm_2(new CookieMonster(NULL, NULL));
@@ -1559,47 +1585,53 @@
   scoped_refptr<CookieMonster> cm(
       new CookieMonster(store.get(), delegate.get()));
 
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "C=D"));
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "E=F"));
-  EXPECT_EQ("A=B; C=D; E=F", GetCookies(cm.get(), url_google_));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "A=B"));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "C=D"));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "E=F"));
+  EXPECT_EQ("A=B; C=D; E=F", GetCookies(cm.get(), http_www_google_.url()));
   ASSERT_EQ(3u, delegate->changes().size());
   EXPECT_FALSE(delegate->changes()[0].second);
-  EXPECT_EQ(url_google_.host(), delegate->changes()[0].first.Domain());
+  EXPECT_EQ(http_www_google_.url().host(),
+            delegate->changes()[0].first.Domain());
   EXPECT_EQ("A", delegate->changes()[0].first.Name());
   EXPECT_EQ("B", delegate->changes()[0].first.Value());
-  EXPECT_EQ(url_google_.host(), delegate->changes()[1].first.Domain());
+  EXPECT_EQ(http_www_google_.url().host(),
+            delegate->changes()[1].first.Domain());
   EXPECT_FALSE(delegate->changes()[1].second);
   EXPECT_EQ("C", delegate->changes()[1].first.Name());
   EXPECT_EQ("D", delegate->changes()[1].first.Value());
-  EXPECT_EQ(url_google_.host(), delegate->changes()[2].first.Domain());
+  EXPECT_EQ(http_www_google_.url().host(),
+            delegate->changes()[2].first.Domain());
   EXPECT_FALSE(delegate->changes()[2].second);
   EXPECT_EQ("E", delegate->changes()[2].first.Name());
   EXPECT_EQ("F", delegate->changes()[2].first.Value());
   delegate->reset();
 
-  EXPECT_TRUE(FindAndDeleteCookie(cm.get(), url_google_.host(), "C"));
-  EXPECT_EQ("A=B; E=F", GetCookies(cm.get(), url_google_));
+  EXPECT_TRUE(
+      FindAndDeleteCookie(cm.get(), http_www_google_.url().host(), "C"));
+  EXPECT_EQ("A=B; E=F", GetCookies(cm.get(), http_www_google_.url()));
   ASSERT_EQ(1u, delegate->changes().size());
-  EXPECT_EQ(url_google_.host(), delegate->changes()[0].first.Domain());
+  EXPECT_EQ(http_www_google_.url().host(),
+            delegate->changes()[0].first.Domain());
   EXPECT_TRUE(delegate->changes()[0].second);
   EXPECT_EQ("C", delegate->changes()[0].first.Name());
   EXPECT_EQ("D", delegate->changes()[0].first.Value());
   delegate->reset();
 
   EXPECT_FALSE(FindAndDeleteCookie(cm.get(), "random.host", "E"));
-  EXPECT_EQ("A=B; E=F", GetCookies(cm.get(), url_google_));
+  EXPECT_EQ("A=B; E=F", GetCookies(cm.get(), http_www_google_.url()));
   EXPECT_EQ(0u, delegate->changes().size());
 
   // Insert a cookie "a" for path "/path1"
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_,
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(),
                         "a=val1; path=/path1; "
                         "expires=Mon, 18-Apr-22 22:50:13 GMT"));
   ASSERT_EQ(1u, store->commands().size());
   EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type);
   ASSERT_EQ(1u, delegate->changes().size());
   EXPECT_FALSE(delegate->changes()[0].second);
-  EXPECT_EQ(url_google_.host(), delegate->changes()[0].first.Domain());
+  EXPECT_EQ(http_www_google_.url().host(),
+            delegate->changes()[0].first.Domain());
   EXPECT_EQ("a", delegate->changes()[0].first.Name());
   EXPECT_EQ("val1", delegate->changes()[0].first.Value());
   delegate->reset();
@@ -1608,7 +1640,7 @@
   // overwrite the non-http-only version.
   CookieOptions allow_httponly;
   allow_httponly.set_include_httponly();
-  EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_,
+  EXPECT_TRUE(SetCookieWithOptions(cm.get(), http_www_google_.url(),
                                    "a=val2; path=/path1; httponly; "
                                    "expires=Mon, 18-Apr-22 22:50:14 GMT",
                                    allow_httponly));
@@ -1616,11 +1648,13 @@
   EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
   EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[2].type);
   ASSERT_EQ(2u, delegate->changes().size());
-  EXPECT_EQ(url_google_.host(), delegate->changes()[0].first.Domain());
+  EXPECT_EQ(http_www_google_.url().host(),
+            delegate->changes()[0].first.Domain());
   EXPECT_TRUE(delegate->changes()[0].second);
   EXPECT_EQ("a", delegate->changes()[0].first.Name());
   EXPECT_EQ("val1", delegate->changes()[0].first.Value());
-  EXPECT_EQ(url_google_.host(), delegate->changes()[1].first.Domain());
+  EXPECT_EQ(http_www_google_.url().host(),
+            delegate->changes()[1].first.Domain());
   EXPECT_FALSE(delegate->changes()[1].second);
   EXPECT_EQ("a", delegate->changes()[1].first.Name());
   EXPECT_EQ("val2", delegate->changes()[1].first.Value());
@@ -1630,40 +1664,40 @@
 TEST_F(CookieMonsterTest, SetCookieWithDetails) {
   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
 
-  EXPECT_TRUE(SetCookieWithDetails(cm.get(), url_google_foo_, "A", "B",
+  EXPECT_TRUE(SetCookieWithDetails(cm.get(), www_google_foo_.url(), "A", "B",
                                    std::string(), "/foo", base::Time(), false,
                                    false, false, COOKIE_PRIORITY_DEFAULT));
-  EXPECT_TRUE(SetCookieWithDetails(cm.get(), url_google_bar_, "C", "D",
-                                   "google.izzle", "/bar", base::Time(), false,
-                                   true, false, COOKIE_PRIORITY_DEFAULT));
   EXPECT_TRUE(SetCookieWithDetails(
-      cm.get(), url_google_, "E", "F", std::string(), std::string(),
+      cm.get(), www_google_bar_.url(), "C", "D", www_google_bar_.domain(),
+      "/bar", base::Time(), false, true, false, COOKIE_PRIORITY_DEFAULT));
+  EXPECT_TRUE(SetCookieWithDetails(
+      cm.get(), http_www_google_.url(), "E", "F", std::string(), std::string(),
       base::Time(), true, false, false, COOKIE_PRIORITY_DEFAULT));
 
   // Test that malformed attributes fail to set the cookie.
-  EXPECT_FALSE(SetCookieWithDetails(cm.get(), url_google_foo_, " A", "B",
+  EXPECT_FALSE(SetCookieWithDetails(cm.get(), www_google_foo_.url(), " A", "B",
                                     std::string(), "/foo", base::Time(), false,
                                     false, false, COOKIE_PRIORITY_DEFAULT));
-  EXPECT_FALSE(SetCookieWithDetails(cm.get(), url_google_foo_, "A;", "B",
+  EXPECT_FALSE(SetCookieWithDetails(cm.get(), www_google_foo_.url(), "A;", "B",
                                     std::string(), "/foo", base::Time(), false,
                                     false, false, COOKIE_PRIORITY_DEFAULT));
-  EXPECT_FALSE(SetCookieWithDetails(cm.get(), url_google_foo_, "A=", "B",
+  EXPECT_FALSE(SetCookieWithDetails(cm.get(), www_google_foo_.url(), "A=", "B",
                                     std::string(), "/foo", base::Time(), false,
                                     false, false, COOKIE_PRIORITY_DEFAULT));
   EXPECT_FALSE(SetCookieWithDetails(
-      cm.get(), url_google_foo_, "A", "B", "google.ozzzzzzle", "foo",
+      cm.get(), www_google_foo_.url(), "A", "B", "google.ozzzzzzle", "foo",
       base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT));
-  EXPECT_FALSE(SetCookieWithDetails(cm.get(), url_google_foo_, "A=", "B",
+  EXPECT_FALSE(SetCookieWithDetails(cm.get(), www_google_foo_.url(), "A=", "B",
                                     std::string(), "foo", base::Time(), false,
                                     false, false, COOKIE_PRIORITY_DEFAULT));
 
-  CookieList cookies = GetAllCookiesForURL(cm.get(), url_google_foo_);
+  CookieList cookies = GetAllCookiesForURL(cm.get(), www_google_foo_.url());
   CookieList::iterator it = cookies.begin();
 
   ASSERT_TRUE(it != cookies.end());
   EXPECT_EQ("A", it->Name());
   EXPECT_EQ("B", it->Value());
-  EXPECT_EQ("www.google.izzle", it->Domain());
+  EXPECT_EQ(www_google_foo_.host(), it->Domain());
   EXPECT_EQ("/foo", it->Path());
   EXPECT_FALSE(it->IsPersistent());
   EXPECT_FALSE(it->IsSecure());
@@ -1671,27 +1705,27 @@
 
   ASSERT_TRUE(++it == cookies.end());
 
-  cookies = GetAllCookiesForURL(cm.get(), url_google_bar_);
+  cookies = GetAllCookiesForURL(cm.get(), www_google_bar_.url());
   it = cookies.begin();
 
   ASSERT_TRUE(it != cookies.end());
   EXPECT_EQ("C", it->Name());
   EXPECT_EQ("D", it->Value());
-  EXPECT_EQ(".google.izzle", it->Domain());
+  EXPECT_EQ(www_google_bar_.Format(".%D"), it->Domain());
   EXPECT_EQ("/bar", it->Path());
   EXPECT_FALSE(it->IsSecure());
   EXPECT_TRUE(it->IsHttpOnly());
 
   ASSERT_TRUE(++it == cookies.end());
 
-  cookies = GetAllCookiesForURL(cm.get(), url_google_secure_);
+  cookies = GetAllCookiesForURL(cm.get(), https_www_google_.url());
   it = cookies.begin();
 
   ASSERT_TRUE(it != cookies.end());
   EXPECT_EQ("E", it->Name());
   EXPECT_EQ("F", it->Value());
   EXPECT_EQ("/", it->Path());
-  EXPECT_EQ("www.google.izzle", it->Domain());
+  EXPECT_EQ(https_www_google_.host(), it->Domain());
   EXPECT_TRUE(it->IsSecure());
   EXPECT_FALSE(it->IsHttpOnly());
 
@@ -1779,26 +1813,29 @@
 
   // SetCookie, SetCookieWithOptions, SetCookieWithDetails
 
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "SetCookie1=A"));
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "SetCookie2=A"));
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "SetCookie3=A"));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "SetCookie1=A"));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "SetCookie2=A"));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "SetCookie3=A"));
 
-  EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_,
+  EXPECT_TRUE(SetCookieWithOptions(cm.get(), http_www_google_.url(),
                                    "setCookieWithOptions1=A", options));
-  EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_,
+  EXPECT_TRUE(SetCookieWithOptions(cm.get(), http_www_google_.url(),
                                    "setCookieWithOptions2=A", options));
-  EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_,
+  EXPECT_TRUE(SetCookieWithOptions(cm.get(), http_www_google_.url(),
                                    "setCookieWithOptions3=A", options));
 
   EXPECT_TRUE(SetCookieWithDetails(
-      cm.get(), url_google_, "setCookieWithDetails1", "A", ".google.izzle", "/",
-      Time(), false, false, false, COOKIE_PRIORITY_DEFAULT));
+      cm.get(), http_www_google_.url(), "setCookieWithDetails1", "A",
+      http_www_google_.Format(".%D"), "/", Time(), false, false, false,
+      COOKIE_PRIORITY_DEFAULT));
   EXPECT_TRUE(SetCookieWithDetails(
-      cm.get(), url_google_, "setCookieWithDetails2", "A", ".google.izzle", "/",
-      Time(), false, false, false, COOKIE_PRIORITY_DEFAULT));
+      cm.get(), http_www_google_.url(), "setCookieWithDetails2", "A",
+      http_www_google_.Format(".%D"), "/", Time(), false, false, false,
+      COOKIE_PRIORITY_DEFAULT));
   EXPECT_TRUE(SetCookieWithDetails(
-      cm.get(), url_google_, "setCookieWithDetails3", "A", ".google.izzle", "/",
-      Time(), false, false, false, COOKIE_PRIORITY_DEFAULT));
+      cm.get(), http_www_google_.url(), "setCookieWithDetails3", "A",
+      http_www_google_.Format(".%D"), "/", Time(), false, false, false,
+      COOKIE_PRIORITY_DEFAULT));
 
   // Now we check
   CookieList cookie_list(GetAllCookies(cm.get()));
@@ -2059,7 +2096,7 @@
 
   // Set a persistent cookie.
   ASSERT_TRUE(SetCookieWithOptions(
-      cm.get(), url_google_,
+      cm.get(), http_www_google_.url(),
       std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-22 22:50:13 GMT",
       options));
 
@@ -2069,7 +2106,7 @@
 
   // Use a past expiry date to delete the cookie.
   ASSERT_TRUE(SetCookieWithOptions(
-      cm.get(), url_google_,
+      cm.get(), http_www_google_.url(),
       std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-1977 22:50:13 GMT",
       options));
 
@@ -2194,19 +2231,21 @@
   scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
   cm->SetPersistSessionCookies(true);
 
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "U=V; path=/"));
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "W=X; path=/foo"));
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "Y=Z; path=/"));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "U=V; path=/"));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "W=X; path=/foo"));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "Y=Z; path=/"));
 
   CookieList list;
-  list.push_back(CanonicalCookie(url_google_, "A", "B", url_google_.host(), "/",
+  list.push_back(CanonicalCookie(http_www_google_.url(), "A", "B",
+                                 http_www_google_.url().host(), "/",
                                  base::Time::Now(), base::Time(), base::Time(),
                                  false, false, false, COOKIE_PRIORITY_DEFAULT));
-  list.push_back(CanonicalCookie(url_google_, "W", "X", url_google_.host(),
-                                 "/bar", base::Time::Now(), base::Time(),
-                                 base::Time(), false, false, false,
-                                 COOKIE_PRIORITY_DEFAULT));
-  list.push_back(CanonicalCookie(url_google_, "Y", "Z", url_google_.host(), "/",
+  list.push_back(CanonicalCookie(http_www_google_.url(), "W", "X",
+                                 http_www_google_.url().host(), "/bar",
+                                 base::Time::Now(), base::Time(), base::Time(),
+                                 false, false, false, COOKIE_PRIORITY_DEFAULT));
+  list.push_back(CanonicalCookie(http_www_google_.url(), "Y", "Z",
+                                 http_www_google_.url().host(), "/",
                                  base::Time::Now(), base::Time(), base::Time(),
                                  false, false, false, COOKIE_PRIORITY_DEFAULT));
 
@@ -2240,39 +2279,49 @@
   base::Time now = base::Time::Now();
   base::Time creation_time = now - base::TimeDelta::FromSeconds(1);
 
-  CanonicalCookie cookie1(url_google_, "A", "B", url_google_.host(), "/",
-                          creation_time, base::Time(), base::Time(), false,
-                          false, false, COOKIE_PRIORITY_DEFAULT);
-  CanonicalCookie cookie2(url_google_, "C", "D", url_google_.host(), "/",
-                          creation_time, base::Time(), base::Time(), false,
-                          false, false, COOKIE_PRIORITY_DEFAULT);
-  CanonicalCookie cookie3(url_google_, "E", "F", url_google_.host(), "/",
-                          creation_time, base::Time(), base::Time(), false,
-                          false, false, COOKIE_PRIORITY_DEFAULT);
-  CanonicalCookie cookie4(url_google_, "G", "H", url_google_.host(), "/",
-                          creation_time, base::Time(), base::Time(), false,
-                          false, false, COOKIE_PRIORITY_DEFAULT);
+  CanonicalCookie cookie1(http_www_google_.url(), "A", "B",
+                          http_www_google_.url().host(), "/", creation_time,
+                          base::Time(), base::Time(), false, false, false,
+                          COOKIE_PRIORITY_DEFAULT);
+  CanonicalCookie cookie2(http_www_google_.url(), "C", "D",
+                          http_www_google_.url().host(), "/", creation_time,
+                          base::Time(), base::Time(), false, false, false,
+                          COOKIE_PRIORITY_DEFAULT);
+  CanonicalCookie cookie3(http_www_google_.url(), "E", "F",
+                          http_www_google_.url().host(), "/", creation_time,
+                          base::Time(), base::Time(), false, false, false,
+                          COOKIE_PRIORITY_DEFAULT);
+  CanonicalCookie cookie4(http_www_google_.url(), "G", "H",
+                          http_www_google_.url().host(), "/", creation_time,
+                          base::Time(), base::Time(), false, false, false,
+                          COOKIE_PRIORITY_DEFAULT);
   CanonicalCookie cookie4_with_new_value(
-      url_google_, "G", "iamnew", url_google_.host(), "/", creation_time,
-      base::Time(), base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT);
-  CanonicalCookie cookie5(url_google_, "I", "J", url_google_.host(), "/",
-                          creation_time, base::Time(), base::Time(), false,
-                          false, false, COOKIE_PRIORITY_DEFAULT);
+      http_www_google_.url(), "G", "iamnew", http_www_google_.url().host(), "/",
+      creation_time, base::Time(), base::Time(), false, false, false,
+      COOKIE_PRIORITY_DEFAULT);
+  CanonicalCookie cookie5(http_www_google_.url(), "I", "J",
+                          http_www_google_.url().host(), "/", creation_time,
+                          base::Time(), base::Time(), false, false, false,
+                          COOKIE_PRIORITY_DEFAULT);
   CanonicalCookie cookie5_with_new_creation_time(
-      url_google_, "I", "J", url_google_.host(), "/", now, base::Time(),
-      base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT);
-  CanonicalCookie cookie6(url_google_, "K", "L", url_google_.host(), "/foo",
-                          creation_time, base::Time(), base::Time(), false,
-                          false, false, COOKIE_PRIORITY_DEFAULT);
+      http_www_google_.url(), "I", "J", http_www_google_.url().host(), "/", now,
+      base::Time(), base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT);
+  CanonicalCookie cookie6(http_www_google_.url(), "K", "L",
+                          http_www_google_.url().host(), "/foo", creation_time,
+                          base::Time(), base::Time(), false, false, false,
+                          COOKIE_PRIORITY_DEFAULT);
   CanonicalCookie cookie6_with_new_path(
-      url_google_, "K", "L", url_google_.host(), "/bar", creation_time,
-      base::Time(), base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT);
-  CanonicalCookie cookie7(url_google_, "M", "N", url_google_.host(), "/foo",
-                          creation_time, base::Time(), base::Time(), false,
-                          false, false, COOKIE_PRIORITY_DEFAULT);
+      http_www_google_.url(), "K", "L", http_www_google_.url().host(), "/bar",
+      creation_time, base::Time(), base::Time(), false, false, false,
+      COOKIE_PRIORITY_DEFAULT);
+  CanonicalCookie cookie7(http_www_google_.url(), "M", "N",
+                          http_www_google_.url().host(), "/foo", creation_time,
+                          base::Time(), base::Time(), false, false, false,
+                          COOKIE_PRIORITY_DEFAULT);
   CanonicalCookie cookie7_with_new_path(
-      url_google_, "M", "N", url_google_.host(), "/bar", creation_time,
-      base::Time(), base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT);
+      http_www_google_.url(), "M", "N", http_www_google_.url().host(), "/bar",
+      creation_time, base::Time(), base::Time(), false, false, false,
+      COOKIE_PRIORITY_DEFAULT);
 
   CookieList old_cookies;
   old_cookies.push_back(cookie1);
@@ -2345,7 +2394,7 @@
   scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
   cm->SetPersistSessionCookies(true);
 
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "X=Y; path=/"));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "X=Y; path=/"));
 
   ASSERT_EQ(0, store->flush_count());
   EXPECT_EQ(1, DeleteAll(cm.get()));
@@ -2373,7 +2422,7 @@
   EXPECT_EQ(samples1->TotalCount() + 1, samples2->TotalCount());
 
   // kValidCookieLine creates a session cookie.
-  ASSERT_TRUE(SetCookie(cm.get(), url_google_, kValidCookieLine));
+  ASSERT_TRUE(SetCookie(cm.get(), http_www_google_.url(), kValidCookieLine));
 
   scoped_ptr<base::HistogramSamples> samples3(
       expired_histogram->SnapshotSamples());
@@ -2484,11 +2533,11 @@
 
 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckGetAllCookies) {
   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "A=B"));
   CookieList cookies = GetAllCookies(cm.get());
   CookieList::const_iterator it = cookies.begin();
   ASSERT_TRUE(it != cookies.end());
-  EXPECT_EQ("www.google.izzle", it->Domain());
+  EXPECT_EQ(http_www_google_.host(), it->Domain());
   EXPECT_EQ("A", it->Name());
   ASSERT_TRUE(++it == cookies.end());
   GetCookieListCallback callback(&other_thread_);
@@ -2499,66 +2548,66 @@
   EXPECT_TRUE(callback.did_run());
   it = callback.cookies().begin();
   ASSERT_TRUE(it != callback.cookies().end());
-  EXPECT_EQ("www.google.izzle", it->Domain());
+  EXPECT_EQ(http_www_google_.host(), it->Domain());
   EXPECT_EQ("A", it->Name());
   ASSERT_TRUE(++it == callback.cookies().end());
 }
 
 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckGetAllCookiesForURL) {
   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
-  CookieList cookies = GetAllCookiesForURL(cm.get(), url_google_);
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "A=B"));
+  CookieList cookies = GetAllCookiesForURL(cm.get(), http_www_google_.url());
   CookieList::const_iterator it = cookies.begin();
   ASSERT_TRUE(it != cookies.end());
-  EXPECT_EQ("www.google.izzle", it->Domain());
+  EXPECT_EQ(http_www_google_.host(), it->Domain());
   EXPECT_EQ("A", it->Name());
   ASSERT_TRUE(++it == cookies.end());
   GetCookieListCallback callback(&other_thread_);
   base::Closure task =
       base::Bind(&MultiThreadedCookieMonsterTest::GetAllCookiesForURLTask,
-                 base::Unretained(this), cm, url_google_, &callback);
+                 base::Unretained(this), cm, http_www_google_.url(), &callback);
   RunOnOtherThread(task);
   EXPECT_TRUE(callback.did_run());
   it = callback.cookies().begin();
   ASSERT_TRUE(it != callback.cookies().end());
-  EXPECT_EQ("www.google.izzle", it->Domain());
+  EXPECT_EQ(http_www_google_.host(), it->Domain());
   EXPECT_EQ("A", it->Name());
   ASSERT_TRUE(++it == callback.cookies().end());
 }
 
 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckGetAllCookiesForURLWithOpt) {
   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "A=B"));
   CookieOptions options;
   CookieList cookies =
-      GetAllCookiesForURLWithOptions(cm.get(), url_google_, options);
+      GetAllCookiesForURLWithOptions(cm.get(), http_www_google_.url(), options);
   CookieList::const_iterator it = cookies.begin();
   ASSERT_TRUE(it != cookies.end());
-  EXPECT_EQ("www.google.izzle", it->Domain());
+  EXPECT_EQ(http_www_google_.host(), it->Domain());
   EXPECT_EQ("A", it->Name());
   ASSERT_TRUE(++it == cookies.end());
   GetCookieListCallback callback(&other_thread_);
   base::Closure task = base::Bind(
       &MultiThreadedCookieMonsterTest::GetAllCookiesForURLWithOptionsTask,
-      base::Unretained(this), cm, url_google_, options, &callback);
+      base::Unretained(this), cm, http_www_google_.url(), options, &callback);
   RunOnOtherThread(task);
   EXPECT_TRUE(callback.did_run());
   it = callback.cookies().begin();
   ASSERT_TRUE(it != callback.cookies().end());
-  EXPECT_EQ("www.google.izzle", it->Domain());
+  EXPECT_EQ(http_www_google_.host(), it->Domain());
   EXPECT_EQ("A", it->Name());
   ASSERT_TRUE(++it == callback.cookies().end());
 }
 
 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckSetCookieWithDetails) {
   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
-  EXPECT_TRUE(SetCookieWithDetails(cm.get(), url_google_foo_, "A", "B",
+  EXPECT_TRUE(SetCookieWithDetails(cm.get(), www_google_foo_.url(), "A", "B",
                                    std::string(), "/foo", base::Time(), false,
                                    false, false, COOKIE_PRIORITY_DEFAULT));
   ResultSavingCookieCallback<bool> callback(&other_thread_);
   base::Closure task =
       base::Bind(&MultiThreadedCookieMonsterTest::SetCookieWithDetailsTask,
-                 base::Unretained(this), cm, url_google_foo_, &callback);
+                 base::Unretained(this), cm, www_google_foo_.url(), &callback);
   RunOnOtherThread(task);
   EXPECT_TRUE(callback.did_run());
   EXPECT_TRUE(callback.result());
@@ -2568,10 +2617,12 @@
   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
   CookieOptions options;
   Time now = Time::Now();
-  EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
+  EXPECT_TRUE(
+      SetCookieWithOptions(cm.get(), http_www_google_.url(), "A=B", options));
   EXPECT_EQ(1, DeleteAllCreatedBetween(cm.get(), now - TimeDelta::FromDays(99),
                                        Time()));
-  EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
+  EXPECT_TRUE(
+      SetCookieWithOptions(cm.get(), http_www_google_.url(), "A=B", options));
   ResultSavingCookieCallback<int> callback(&other_thread_);
   base::Closure task =
       base::Bind(&MultiThreadedCookieMonsterTest::DeleteAllCreatedBetweenTask,
@@ -2585,13 +2636,15 @@
 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckDeleteAllForHost) {
   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
   CookieOptions options;
-  EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
-  EXPECT_EQ(1, DeleteAllForHost(cm.get(), url_google_));
-  EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
+  EXPECT_TRUE(
+      SetCookieWithOptions(cm.get(), http_www_google_.url(), "A=B", options));
+  EXPECT_EQ(1, DeleteAllForHost(cm.get(), http_www_google_.url()));
+  EXPECT_TRUE(
+      SetCookieWithOptions(cm.get(), http_www_google_.url(), "A=B", options));
   ResultSavingCookieCallback<int> callback(&other_thread_);
   base::Closure task =
       base::Bind(&MultiThreadedCookieMonsterTest::DeleteAllForHostTask,
-                 base::Unretained(this), cm, url_google_, &callback);
+                 base::Unretained(this), cm, http_www_google_.url(), &callback);
   RunOnOtherThread(task);
   EXPECT_TRUE(callback.did_run());
   EXPECT_EQ(1, callback.result());
@@ -2610,29 +2663,35 @@
   Time ago3 = now - TimeDelta::FromDays(99);
 
   // These 3 cookies match the first deletion.
-  EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
-  EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "C=D", options));
-  EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "Y=Z", options));
+  EXPECT_TRUE(
+      SetCookieWithOptions(cm.get(), http_www_google_.url(), "A=B", options));
+  EXPECT_TRUE(
+      SetCookieWithOptions(cm.get(), http_www_google_.url(), "C=D", options));
+  EXPECT_TRUE(
+      SetCookieWithOptions(cm.get(), http_www_google_.url(), "Y=Z", options));
 
   // This cookie does not match host.
   EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_not_google, "E=F", options));
 
   // This cookie does not match time range: [ago3, inf], for first deletion, but
   // matches for the second deletion.
-  EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "G=H", ago2));
+  EXPECT_TRUE(
+      cm->SetCookieWithCreationTime(http_www_google_.url(), "G=H", ago2));
 
   // 1. First set of deletions.
-  EXPECT_EQ(
-      3,  // Deletes A=B, C=D, Y=Z
-      DeleteAllCreatedBetweenForHost(cm.get(), ago3, Time::Max(), url_google_));
+  EXPECT_EQ(3,  // Deletes A=B, C=D, Y=Z
+            DeleteAllCreatedBetweenForHost(cm.get(), ago3, Time::Max(),
+                                           http_www_google_.url()));
 
-  EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
+  EXPECT_TRUE(
+      SetCookieWithOptions(cm.get(), http_www_google_.url(), "A=B", options));
   ResultSavingCookieCallback<int> callback(&other_thread_);
 
   // 2. Second set of deletions.
   base::Closure task = base::Bind(
       &MultiThreadedCookieMonsterTest::DeleteAllCreatedBetweenForHostTask,
-      base::Unretained(this), cm, ago1, Time(), url_google_, &callback);
+      base::Unretained(this), cm, ago1, Time(), http_www_google_.url(),
+      &callback);
   RunOnOtherThread(task);
   EXPECT_TRUE(callback.did_run());
   EXPECT_EQ(2, callback.result());  // Deletes A=B, G=H.
@@ -2641,12 +2700,14 @@
 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckDeleteCanonicalCookie) {
   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
   CookieOptions options;
-  EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
+  EXPECT_TRUE(
+      SetCookieWithOptions(cm.get(), http_www_google_.url(), "A=B", options));
   CookieList cookies = GetAllCookies(cm.get());
   CookieList::iterator it = cookies.begin();
   EXPECT_TRUE(DeleteCanonicalCookie(cm.get(), *it));
 
-  EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
+  EXPECT_TRUE(
+      SetCookieWithOptions(cm.get(), http_www_google_.url(), "A=B", options));
   ResultSavingCookieCallback<bool> callback(&other_thread_);
   cookies = GetAllCookies(cm.get());
   it = cookies.begin();
@@ -2665,8 +2726,8 @@
 TEST_F(MultiThreadedCookieMonsterTest, GetAllCookiesForURLEffectiveDomain) {
   std::vector<CanonicalCookie*> cookies;
   // This cookie will be freed by the CookieMonster.
-  cookies.push_back(CanonicalCookie::Create(url_google_, kValidCookieLine,
-                                            Time::Now(), CookieOptions()));
+  cookies.push_back(CanonicalCookie::Create(
+      http_www_google_.url(), kValidCookieLine, Time::Now(), CookieOptions()));
   CanonicalCookie cookie = *cookies[0];
   scoped_refptr<NewMockPersistentCookieStore> store(
       new NewMockPersistentCookieStore);
@@ -2674,8 +2735,8 @@
 
   CookieMonster::PersistentCookieStore::LoadedCallback loaded_callback;
   ::testing::StrictMock<::testing::MockFunction<void(int)>> checkpoint;
-  const std::string key =
-      cookie_util::GetEffectiveDomain(url_google_.scheme(), url_google_.host());
+  const std::string key = cookie_util::GetEffectiveDomain(
+      http_www_google_.url().scheme(), http_www_google_.url().host());
 
   ::testing::InSequence s;
   EXPECT_CALL(checkpoint, Call(0));
@@ -2690,7 +2751,7 @@
 
   GetCookieListCallback callback;
   checkpoint.Call(0);
-  GetAllCookiesForURLTask(cm.get(), url_google_, &callback);
+  GetAllCookiesForURLTask(cm.get(), http_www_google_.url(), &callback);
   checkpoint.Call(1);
   ASSERT_FALSE(callback.did_run());
   // Pass the cookies to the CookieMonster.
@@ -2703,10 +2764,8 @@
 
   // All urls in |urls| should share the same cookie domain.
   const GURL kUrls[] = {
-      url_google_,
-      url_google_secure_,
-      GURL(kUrlGoogleWebSocket),
-      GURL(kUrlGoogleWebSocketSecure),
+      http_www_google_.url(), https_www_google_.url(), ws_www_google_.url(),
+      wss_www_google_.url(),
   };
   for (const GURL& url : kUrls) {
     // Call the function with |url| and verify it is done synchronously without
@@ -2723,7 +2782,7 @@
   std::string cookie_line =
       std::string(kValidCookieLine) + "; expires=Blarg arg arg";
   scoped_ptr<CanonicalCookie> cookie(CanonicalCookie::Create(
-      url_google_, cookie_line, Time::Now(), CookieOptions()));
+      http_www_google_.url(), cookie_line, Time::Now(), CookieOptions()));
   ASSERT_FALSE(cookie->IsPersistent());
 }
 
@@ -2735,8 +2794,8 @@
   cm->SetPersistSessionCookies(true);
 
   // All cookies set with SetCookie are session cookies.
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
-  EXPECT_EQ("A=B", GetCookies(cm.get(), url_google_));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "A=B"));
+  EXPECT_EQ("A=B", GetCookies(cm.get(), http_www_google_.url()));
 
   // The cookie was written to the backing store.
   EXPECT_EQ(1u, store->commands().size());
@@ -2745,8 +2804,8 @@
   EXPECT_EQ("B", store->commands()[0].cookie.Value());
 
   // Modify the cookie.
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=C"));
-  EXPECT_EQ("A=C", GetCookies(cm.get(), url_google_));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "A=C"));
+  EXPECT_EQ("A=C", GetCookies(cm.get(), http_www_google_.url()));
   EXPECT_EQ(3u, store->commands().size());
   EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
   EXPECT_EQ("A", store->commands()[1].cookie.Name());
@@ -2756,8 +2815,8 @@
   EXPECT_EQ("C", store->commands()[2].cookie.Value());
 
   // Delete the cookie.
-  DeleteCookie(cm.get(), url_google_, "A");
-  EXPECT_EQ("", GetCookies(cm.get(), url_google_));
+  DeleteCookie(cm.get(), http_www_google_.url(), "A");
+  EXPECT_EQ("", GetCookies(cm.get(), http_www_google_.url()));
   EXPECT_EQ(4u, store->commands().size());
   EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type);
   EXPECT_EQ("A", store->commands()[3].cookie.Name());
@@ -2770,35 +2829,37 @@
   scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
 
   // Add a cookie.
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_,
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(),
                         "A=B; expires=Mon, 18-Apr-22 22:50:13 GMT"));
-  this->MatchCookieLines("A=B", GetCookies(cm.get(), url_google_));
+  this->MatchCookieLines("A=B", GetCookies(cm.get(), http_www_google_.url()));
   ASSERT_EQ(1u, store->commands().size());
   EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type);
   // Remove it.
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B; max-age=0"));
-  this->MatchCookieLines(std::string(), GetCookies(cm.get(), url_google_));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "A=B; max-age=0"));
+  this->MatchCookieLines(std::string(),
+                         GetCookies(cm.get(), http_www_google_.url()));
   ASSERT_EQ(2u, store->commands().size());
   EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
 
   // Add a cookie.
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_,
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(),
                         "A=B; expires=Mon, 18-Apr-22 22:50:13 GMT"));
-  this->MatchCookieLines("A=B", GetCookies(cm.get(), url_google_));
+  this->MatchCookieLines("A=B", GetCookies(cm.get(), http_www_google_.url()));
   ASSERT_EQ(3u, store->commands().size());
   EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[2].type);
   // Overwrite it.
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_,
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(),
                         "A=Foo; expires=Mon, 18-Apr-22 22:50:14 GMT"));
-  this->MatchCookieLines("A=Foo", GetCookies(cm.get(), url_google_));
+  this->MatchCookieLines("A=Foo", GetCookies(cm.get(), http_www_google_.url()));
   ASSERT_EQ(5u, store->commands().size());
   EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type);
   EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[4].type);
 
   // Create some non-persistent cookies and check that they don't go to the
   // persistent storage.
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=Bar"));
-  this->MatchCookieLines("A=Foo; B=Bar", GetCookies(cm.get(), url_google_));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "B=Bar"));
+  this->MatchCookieLines("A=Foo; B=Bar",
+                         GetCookies(cm.get(), http_www_google_.url()));
   EXPECT_EQ(5u, store->commands().size());
 }
 
@@ -2850,21 +2911,23 @@
   histograms.ExpectTotalCount(cookie_source_histogram, 0);
 
   // Set a Secure cookie on a cryptographic scheme.
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_secure_, "A=B; path=/; Secure"));
+  EXPECT_TRUE(
+      SetCookie(cm.get(), https_www_google_.url(), "A=B; path=/; Secure"));
   histograms.ExpectTotalCount(cookie_source_histogram, 1);
   histograms.ExpectBucketCount(
       cookie_source_histogram,
       CookieMonster::COOKIE_SOURCE_SECURE_COOKIE_CRYPTOGRAPHIC_SCHEME, 1);
 
   // Set a non-Secure cookie on a cryptographic scheme.
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_secure_, "C=D; path=/;"));
+  EXPECT_TRUE(SetCookie(cm.get(), https_www_google_.url(), "C=D; path=/;"));
   histograms.ExpectTotalCount(cookie_source_histogram, 2);
   histograms.ExpectBucketCount(
       cookie_source_histogram,
       CookieMonster::COOKIE_SOURCE_NONSECURE_COOKIE_CRYPTOGRAPHIC_SCHEME, 1);
 
   // Set a Secure cookie on a non-cryptographic scheme.
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "D=E; path=/; Secure"));
+  EXPECT_TRUE(
+      SetCookie(cm.get(), http_www_google_.url(), "D=E; path=/; Secure"));
   histograms.ExpectTotalCount(cookie_source_histogram, 3);
   histograms.ExpectBucketCount(
       cookie_source_histogram,
@@ -2872,7 +2935,8 @@
 
   // Overwrite a Secure cookie (set by a cryptographic scheme) on a
   // non-cryptographic scheme.
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B; path=/; Secure"));
+  EXPECT_TRUE(
+      SetCookie(cm.get(), http_www_google_.url(), "A=B; path=/; Secure"));
   histograms.ExpectTotalCount(cookie_source_histogram, 4);
   histograms.ExpectBucketCount(
       cookie_source_histogram,
@@ -2883,18 +2947,19 @@
 
   // Test that clearing a Secure cookie on a http:// URL does not get
   // counted.
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_secure_, "F=G; path=/; Secure"));
+  EXPECT_TRUE(
+      SetCookie(cm.get(), https_www_google_.url(), "F=G; path=/; Secure"));
   histograms.ExpectTotalCount(cookie_source_histogram, 5);
-  std::string cookies1 = GetCookies(cm.get(), url_google_secure_);
+  std::string cookies1 = GetCookies(cm.get(), https_www_google_.url());
   EXPECT_NE(std::string::npos, cookies1.find("F=G"));
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_,
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(),
                         "F=G; path=/; Expires=Thu, 01-Jan-1970 00:00:01 GMT"));
-  std::string cookies2 = GetCookies(cm.get(), url_google_secure_);
+  std::string cookies2 = GetCookies(cm.get(), https_www_google_.url());
   EXPECT_EQ(std::string::npos, cookies2.find("F=G"));
   histograms.ExpectTotalCount(cookie_source_histogram, 5);
 
   // Set a non-Secure cookie on a non-cryptographic scheme.
-  EXPECT_TRUE(SetCookie(cm.get(), url_google_, "H=I; path=/"));
+  EXPECT_TRUE(SetCookie(cm.get(), http_www_google_.url(), "H=I; path=/"));
   histograms.ExpectTotalCount(cookie_source_histogram, 6);
   histograms.ExpectBucketCount(
       cookie_source_histogram,
diff --git a/net/cookies/cookie_store_test_helpers.cc b/net/cookies/cookie_store_test_helpers.cc
index 49f9d9ac..e75039c 100644
--- a/net/cookies/cookie_store_test_helpers.cc
+++ b/net/cookies/cookie_store_test_helpers.cc
@@ -7,7 +7,27 @@
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/single_thread_task_runner.h"
+#include "base/strings/string_util.h"
 #include "base/thread_task_runner_handle.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+
+using net::registry_controlled_domains::GetDomainAndRegistry;
+using net::registry_controlled_domains::GetRegistryLength;
+using net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES;
+using net::registry_controlled_domains::INCLUDE_UNKNOWN_REGISTRIES;
+
+namespace {
+
+std::string GetRegistry(const GURL& url) {
+  size_t registry_length = GetRegistryLength(url, INCLUDE_UNKNOWN_REGISTRIES,
+                                             INCLUDE_PRIVATE_REGISTRIES);
+  if (registry_length == 0)
+    return std::string();
+  return std::string(url.host(), url.host().length() - registry_length,
+                     registry_length);
+}
+
+}  // namespace
 
 namespace net {
 
@@ -143,4 +163,25 @@
   return scoped_ptr<CookieStore::CookieChangedSubscription>();
 }
 
+//
+// CookieURLHelper
+//
+CookieURLHelper::CookieURLHelper(const std::string& url_string)
+    : url_(url_string),
+      registry_(GetRegistry(url_)),
+      domain_and_registry_(
+          GetDomainAndRegistry(url_, INCLUDE_PRIVATE_REGISTRIES)) {}
+
+const GURL CookieURLHelper::AppendPath(const std::string& path) const {
+  return GURL(url_.spec() + path);
+}
+
+std::string CookieURLHelper::Format(const std::string& format_string) const {
+  std::string new_string = format_string;
+  base::ReplaceSubstringsAfterOffset(&new_string, 0, "%D",
+                                     domain_and_registry_);
+  base::ReplaceSubstringsAfterOffset(&new_string, 0, "%R", registry_);
+  return new_string;
+}
+
 }  // namespace net
diff --git a/net/cookies/cookie_store_test_helpers.h b/net/cookies/cookie_store_test_helpers.h
index 760b847..1750c7f 100644
--- a/net/cookies/cookie_store_test_helpers.h
+++ b/net/cookies/cookie_store_test_helpers.h
@@ -70,7 +70,6 @@
                        const CookieChangedCallback& callback) override;
 
  private:
-
   // Be called immediately from CookieMonster.
 
   void SetCookiesInternalCallback(bool result);
@@ -96,6 +95,26 @@
   std::string cookie_line_;
 };
 
+class CookieURLHelper {
+ public:
+  explicit CookieURLHelper(const std::string& url_string);
+
+  const std::string& domain() const { return domain_and_registry_; }
+  std::string host() const { return url_.host(); }
+  const GURL& url() const { return url_; }
+  const GURL AppendPath(const std::string& path) const;
+
+  // Return a new string with the following substitutions:
+  // 1. "%R" -> Domain registry (i.e. "com")
+  // 2. "%D" -> Domain + registry (i.e. "google.com")
+  std::string Format(const std::string& format_string) const;
+
+ private:
+  const GURL url_;
+  const std::string registry_;
+  const std::string domain_and_registry_;
+};
+
 }  // namespace net
 
 #endif  // NET_COOKIES_COOKIE_STORE_TEST_HELPERS_H_
diff --git a/net/cookies/cookie_store_unittest.h b/net/cookies/cookie_store_unittest.h
index 9892fae..b380fbc 100644
--- a/net/cookies/cookie_store_unittest.h
+++ b/net/cookies/cookie_store_unittest.h
@@ -5,6 +5,10 @@
 #ifndef NET_COOKIES_COOKIE_STORE_UNITTEST_H_
 #define NET_COOKIES_COOKIE_STORE_UNITTEST_H_
 
+#include <set>
+#include <string>
+#include <vector>
+
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/message_loop/message_loop.h"
@@ -15,6 +19,7 @@
 #include "net/cookies/cookie_monster.h"
 #include "net/cookies/cookie_store.h"
 #include "net/cookies/cookie_store_test_callbacks.h"
+#include "net/cookies/cookie_store_test_helpers.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
@@ -32,15 +37,7 @@
 
 const int kTimeout = 1000;
 
-const char kUrlFtp[] = "ftp://ftp.google.izzle/";
-const char kUrlGoogle[] = "http://www.google.izzle";
-const char kUrlGoogleFoo[] = "http://www.google.izzle/foo";
-const char kUrlGoogleBar[] = "http://www.google.izzle/bar";
-const char kUrlGoogleSecure[] = "https://www.google.izzle";
-const char kUrlGoogleWebSocket[] = "ws://www.google.izzle";
-const char kUrlGoogleWebSocketSecure[] = "wss://www.google.izzle";
 const char kValidCookieLine[] = "A=B; path=/";
-const char kValidDomainCookieLine[] = "A=B; path=/; domain=google.izzle";
 
 // The CookieStoreTestTraits must have the following members:
 // struct CookieStoreTestTraits {
@@ -78,10 +75,13 @@
 class CookieStoreTest : public testing::Test {
  protected:
   CookieStoreTest()
-      : url_google_(kUrlGoogle),
-        url_google_secure_(kUrlGoogleSecure),
-        url_google_foo_(kUrlGoogleFoo),
-        url_google_bar_(kUrlGoogleBar) {
+      : http_www_google_("http://www.google.izzle"),
+        https_www_google_("https://www.google.izzle"),
+        ftp_google_("ftp://ftp.google.izzle/"),
+        ws_www_google_("ws://www.google.izzle"),
+        wss_www_google_("wss://www.google.izzle"),
+        www_google_foo_("http://www.google.izzle/foo"),
+        www_google_bar_("http://www.google.izzle/bar") {
     // This test may be used outside of the net test suite, and thus may not
     // have a message loop.
     if (!base::MessageLoop::current())
@@ -252,10 +252,13 @@
                          << "\" does not match \"" << line << "\"";
   }
 
-  GURL url_google_;
-  GURL url_google_secure_;
-  GURL url_google_foo_;
-  GURL url_google_bar_;
+  const CookieURLHelper http_www_google_;
+  const CookieURLHelper https_www_google_;
+  const CookieURLHelper ftp_google_;
+  const CookieURLHelper ws_www_google_;
+  const CookieURLHelper wss_www_google_;
+  const CookieURLHelper www_google_foo_;
+  const CookieURLHelper www_google_bar_;
 
   scoped_ptr<base::WeakPtrFactory<base::MessageLoop> > weak_factory_;
   scoped_ptr<base::MessageLoop> message_loop_;
@@ -282,55 +285,69 @@
 
 TYPED_TEST_P(CookieStoreTest, DomainTest) {
   scoped_refptr<CookieStore> cs(this->GetCookieStore());
-  EXPECT_TRUE(this->SetCookie(cs.get(), this->url_google_, "A=B"));
-  this->MatchCookieLines("A=B", this->GetCookies(cs.get(), this->url_google_));
-  EXPECT_TRUE(this->SetCookie(
-      cs.get(), this->url_google_, "C=D; domain=.google.izzle"));
-  this->MatchCookieLines("A=B; C=D",
-                         this->GetCookies(cs.get(), this->url_google_));
+  EXPECT_TRUE(this->SetCookie(cs.get(), this->http_www_google_.url(), "A=B"));
+  this->MatchCookieLines(
+      "A=B", this->GetCookies(cs.get(), this->http_www_google_.url()));
+  EXPECT_TRUE(
+      this->SetCookie(cs.get(), this->http_www_google_.url(),
+                      this->http_www_google_.Format("C=D; domain=.%D")));
+  this->MatchCookieLines(
+      "A=B; C=D", this->GetCookies(cs.get(), this->http_www_google_.url()));
 
   // Verify that A=B was set as a host cookie rather than a domain
   // cookie -- should not be accessible from a sub sub-domain.
   this->MatchCookieLines(
-      "C=D", this->GetCookies(cs.get(), GURL("http://foo.www.google.izzle")));
+      "C=D",
+      this->GetCookies(
+          cs.get(), GURL(this->http_www_google_.Format("http://foo.www.%D"))));
 
   // Test and make sure we find domain cookies on the same domain.
-  EXPECT_TRUE(this->SetCookie(
-      cs.get(), this->url_google_, "E=F; domain=.www.google.izzle"));
-  this->MatchCookieLines("A=B; C=D; E=F",
-                         this->GetCookies(cs.get(), this->url_google_));
+  EXPECT_TRUE(
+      this->SetCookie(cs.get(), this->http_www_google_.url(),
+                      this->http_www_google_.Format("E=F; domain=.www.%D")));
+  this->MatchCookieLines(
+      "A=B; C=D; E=F",
+      this->GetCookies(cs.get(), this->http_www_google_.url()));
 
   // Test setting a domain= that doesn't start w/ a dot, should
   // treat it as a domain cookie, as if there was a pre-pended dot.
-  EXPECT_TRUE(this->SetCookie(
-      cs.get(), this->url_google_, "G=H; domain=www.google.izzle"));
-  this->MatchCookieLines("A=B; C=D; E=F; G=H",
-                         this->GetCookies(cs.get(), this->url_google_));
+  EXPECT_TRUE(
+      this->SetCookie(cs.get(), this->http_www_google_.url(),
+                      this->http_www_google_.Format("G=H; domain=www.%D")));
+  this->MatchCookieLines(
+      "A=B; C=D; E=F; G=H",
+      this->GetCookies(cs.get(), this->http_www_google_.url()));
 
   // Test domain enforcement, should fail on a sub-domain or something too deep.
   EXPECT_FALSE(
-      this->SetCookie(cs.get(), this->url_google_, "I=J; domain=.izzle"));
-  this->MatchCookieLines(std::string(),
-                         this->GetCookies(cs.get(), GURL("http://a.izzle")));
+      this->SetCookie(cs.get(), this->http_www_google_.url(),
+                      this->http_www_google_.Format("I=J; domain=.%R")));
+  this->MatchCookieLines(
+      std::string(),
+      this->GetCookies(cs.get(),
+                       GURL(this->http_www_google_.Format("http://a.%R"))));
   EXPECT_FALSE(this->SetCookie(
-      cs.get(), this->url_google_, "K=L; domain=.bla.www.google.izzle"));
+      cs.get(), this->http_www_google_.url(),
+      this->http_www_google_.Format("K=L; domain=.bla.www.%D")));
   this->MatchCookieLines(
       "C=D; E=F; G=H",
-      this->GetCookies(cs.get(), GURL("http://bla.www.google.izzle")));
-  this->MatchCookieLines("A=B; C=D; E=F; G=H",
-                         this->GetCookies(cs.get(), this->url_google_));
+      this->GetCookies(
+          cs.get(), GURL(this->http_www_google_.Format("http://bla.www.%D"))));
+  this->MatchCookieLines(
+      "A=B; C=D; E=F; G=H",
+      this->GetCookies(cs.get(), this->http_www_google_.url()));
 }
 
 // FireFox recognizes domains containing trailing periods as valid.
 // IE and Safari do not. Assert the expected policy here.
 TYPED_TEST_P(CookieStoreTest, DomainWithTrailingDotTest) {
   scoped_refptr<CookieStore> cs(this->GetCookieStore());
-  EXPECT_FALSE(this->SetCookie(
-      cs.get(), this->url_google_, "a=1; domain=.www.google.com."));
-  EXPECT_FALSE(this->SetCookie(
-      cs.get(), this->url_google_, "b=2; domain=.www.google.com.."));
-  this->MatchCookieLines(std::string(),
-                         this->GetCookies(cs.get(), this->url_google_));
+  EXPECT_FALSE(this->SetCookie(cs.get(), this->http_www_google_.url(),
+                               "a=1; domain=.www.google.com."));
+  EXPECT_FALSE(this->SetCookie(cs.get(), this->http_www_google_.url(),
+                               "b=2; domain=.www.google.com.."));
+  this->MatchCookieLines(
+      std::string(), this->GetCookies(cs.get(), this->http_www_google_.url()));
 }
 
 // Test that cookies can bet set on higher level domains.
@@ -599,18 +616,22 @@
     return;
 
   scoped_refptr<CookieStore> cs(this->GetCookieStore());
-  EXPECT_FALSE(this->SetCookie(cs.get(), GURL(kUrlFtp), kValidCookieLine));
+  EXPECT_FALSE(
+      this->SetCookie(cs.get(), this->ftp_google_.url(), kValidCookieLine));
 }
 
 TYPED_TEST_P(CookieStoreTest, InvalidScheme_Read) {
   if (!TypeParam::filters_schemes)
     return;
 
+  const std::string kValidDomainCookieLine =
+      this->http_www_google_.Format("A=B; path=/; domain=%D");
+
   scoped_refptr<CookieStore> cs(this->GetCookieStore());
-  EXPECT_TRUE(
-      this->SetCookie(cs.get(), GURL(kUrlGoogle), kValidDomainCookieLine));
+  EXPECT_TRUE(this->SetCookie(cs.get(), this->http_www_google_.url(),
+                              kValidDomainCookieLine));
   this->MatchCookieLines(std::string(),
-                         this->GetCookies(cs.get(), GURL(kUrlFtp)));
+                         this->GetCookies(cs.get(), this->ftp_google_.url()));
 }
 
 TYPED_TEST_P(CookieStoreTest, PathTest) {
@@ -671,117 +692,124 @@
   options.set_include_httponly();
 
   // Create a httponly cookie.
-  EXPECT_TRUE(this->SetCookieWithOptions(
-      cs.get(), this->url_google_, "A=B; httponly", options));
+  EXPECT_TRUE(this->SetCookieWithOptions(cs.get(), this->http_www_google_.url(),
+                                         "A=B; httponly", options));
 
   // Check httponly read protection.
-  this->MatchCookieLines(std::string(),
-                         this->GetCookies(cs.get(), this->url_google_));
   this->MatchCookieLines(
-      "A=B", this->GetCookiesWithOptions(cs.get(), this->url_google_, options));
+      std::string(), this->GetCookies(cs.get(), this->http_www_google_.url()));
+  this->MatchCookieLines(
+      "A=B", this->GetCookiesWithOptions(cs.get(), this->http_www_google_.url(),
+                                         options));
 
   // Check httponly overwrite protection.
-  EXPECT_FALSE(this->SetCookie(cs.get(), this->url_google_, "A=C"));
-  this->MatchCookieLines(std::string(),
-                         this->GetCookies(cs.get(), this->url_google_));
+  EXPECT_FALSE(this->SetCookie(cs.get(), this->http_www_google_.url(), "A=C"));
   this->MatchCookieLines(
-      "A=B", this->GetCookiesWithOptions(cs.get(), this->url_google_, options));
-  EXPECT_TRUE(
-      this->SetCookieWithOptions(cs.get(), this->url_google_, "A=C", options));
-  this->MatchCookieLines("A=C", this->GetCookies(cs.get(), this->url_google_));
+      std::string(), this->GetCookies(cs.get(), this->http_www_google_.url()));
+  this->MatchCookieLines(
+      "A=B", this->GetCookiesWithOptions(cs.get(), this->http_www_google_.url(),
+                                         options));
+  EXPECT_TRUE(this->SetCookieWithOptions(cs.get(), this->http_www_google_.url(),
+                                         "A=C", options));
+  this->MatchCookieLines(
+      "A=C", this->GetCookies(cs.get(), this->http_www_google_.url()));
 
   // Check httponly create protection.
-  EXPECT_FALSE(this->SetCookie(cs.get(), this->url_google_, "B=A; httponly"));
+  EXPECT_FALSE(
+      this->SetCookie(cs.get(), this->http_www_google_.url(), "B=A; httponly"));
   this->MatchCookieLines(
-      "A=C", this->GetCookiesWithOptions(cs.get(), this->url_google_, options));
-  EXPECT_TRUE(this->SetCookieWithOptions(
-      cs.get(), this->url_google_, "B=A; httponly", options));
+      "A=C", this->GetCookiesWithOptions(cs.get(), this->http_www_google_.url(),
+                                         options));
+  EXPECT_TRUE(this->SetCookieWithOptions(cs.get(), this->http_www_google_.url(),
+                                         "B=A; httponly", options));
+  this->MatchCookieLines("A=C; B=A",
+                         this->GetCookiesWithOptions(
+                             cs.get(), this->http_www_google_.url(), options));
   this->MatchCookieLines(
-      "A=C; B=A",
-      this->GetCookiesWithOptions(cs.get(), this->url_google_, options));
-  this->MatchCookieLines("A=C", this->GetCookies(cs.get(), this->url_google_));
+      "A=C", this->GetCookies(cs.get(), this->http_www_google_.url()));
 }
 
 TYPED_TEST_P(CookieStoreTest, TestCookieDeletion) {
   scoped_refptr<CookieStore> cs(this->GetCookieStore());
 
   // Create a session cookie.
-  EXPECT_TRUE(this->SetCookie(cs.get(), this->url_google_, kValidCookieLine));
-  this->MatchCookieLines("A=B", this->GetCookies(cs.get(), this->url_google_));
+  EXPECT_TRUE(this->SetCookie(cs.get(), this->http_www_google_.url(),
+                              kValidCookieLine));
+  this->MatchCookieLines(
+      "A=B", this->GetCookies(cs.get(), this->http_www_google_.url()));
   // Delete it via Max-Age.
-  EXPECT_TRUE(this->SetCookie(cs.get(),
-                              this->url_google_,
+  EXPECT_TRUE(this->SetCookie(cs.get(), this->http_www_google_.url(),
                               std::string(kValidCookieLine) + "; max-age=0"));
-  this->MatchCookieLineWithTimeout(cs.get(), this->url_google_, std::string());
+  this->MatchCookieLineWithTimeout(cs.get(), this->http_www_google_.url(),
+                                   std::string());
 
   // Create a session cookie.
-  EXPECT_TRUE(this->SetCookie(cs.get(), this->url_google_, kValidCookieLine));
-  this->MatchCookieLines("A=B", this->GetCookies(cs.get(), this->url_google_));
+  EXPECT_TRUE(this->SetCookie(cs.get(), this->http_www_google_.url(),
+                              kValidCookieLine));
+  this->MatchCookieLines(
+      "A=B", this->GetCookies(cs.get(), this->http_www_google_.url()));
   // Delete it via Expires.
-  EXPECT_TRUE(this->SetCookie(cs.get(),
-                              this->url_google_,
+  EXPECT_TRUE(this->SetCookie(cs.get(), this->http_www_google_.url(),
                               std::string(kValidCookieLine) +
                                   "; expires=Mon, 18-Apr-1977 22:50:13 GMT"));
-  this->MatchCookieLines(std::string(),
-                         this->GetCookies(cs.get(), this->url_google_));
+  this->MatchCookieLines(
+      std::string(), this->GetCookies(cs.get(), this->http_www_google_.url()));
 
   // Create a persistent cookie.
   EXPECT_TRUE(this->SetCookie(
-      cs.get(),
-      this->url_google_,
+      cs.get(), this->http_www_google_.url(),
       std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-22 22:50:13 GMT"));
 
-  this->MatchCookieLines("A=B", this->GetCookies(cs.get(), this->url_google_));
+  this->MatchCookieLines(
+      "A=B", this->GetCookies(cs.get(), this->http_www_google_.url()));
   // Delete it via Max-Age.
-  EXPECT_TRUE(this->SetCookie(cs.get(),
-                              this->url_google_,
+  EXPECT_TRUE(this->SetCookie(cs.get(), this->http_www_google_.url(),
                               std::string(kValidCookieLine) + "; max-age=0"));
-  this->MatchCookieLineWithTimeout(cs.get(), this->url_google_, std::string());
+  this->MatchCookieLineWithTimeout(cs.get(), this->http_www_google_.url(),
+                                   std::string());
 
   // Create a persistent cookie.
   EXPECT_TRUE(this->SetCookie(
-      cs.get(),
-      this->url_google_,
+      cs.get(), this->http_www_google_.url(),
       std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-22 22:50:13 GMT"));
-  this->MatchCookieLines("A=B", this->GetCookies(cs.get(), this->url_google_));
+  this->MatchCookieLines(
+      "A=B", this->GetCookies(cs.get(), this->http_www_google_.url()));
   // Delete it via Expires.
-  EXPECT_TRUE(this->SetCookie(cs.get(),
-                              this->url_google_,
+  EXPECT_TRUE(this->SetCookie(cs.get(), this->http_www_google_.url(),
                               std::string(kValidCookieLine) +
                                   "; expires=Mon, 18-Apr-1977 22:50:13 GMT"));
-  this->MatchCookieLines(std::string(),
-                         this->GetCookies(cs.get(), this->url_google_));
+  this->MatchCookieLines(
+      std::string(), this->GetCookies(cs.get(), this->http_www_google_.url()));
 
   // Create a persistent cookie.
   EXPECT_TRUE(this->SetCookie(
-      cs.get(),
-      this->url_google_,
+      cs.get(), this->http_www_google_.url(),
       std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-22 22:50:13 GMT"));
-  this->MatchCookieLines("A=B", this->GetCookies(cs.get(), this->url_google_));
+  this->MatchCookieLines(
+      "A=B", this->GetCookies(cs.get(), this->http_www_google_.url()));
   // Check that it is not deleted with significant enough clock skew.
   base::Time server_time;
   EXPECT_TRUE(base::Time::FromString("Sun, 17-Apr-1977 22:50:13 GMT",
                                      &server_time));
   EXPECT_TRUE(this->SetCookieWithServerTime(
-      cs.get(),
-      this->url_google_,
+      cs.get(), this->http_www_google_.url(),
       std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-1977 22:50:13 GMT",
       server_time));
-  this->MatchCookieLines("A=B", this->GetCookies(cs.get(), this->url_google_));
+  this->MatchCookieLines(
+      "A=B", this->GetCookies(cs.get(), this->http_www_google_.url()));
 
   // Create a persistent cookie.
   EXPECT_TRUE(this->SetCookie(
-      cs.get(),
-      this->url_google_,
+      cs.get(), this->http_www_google_.url(),
       std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-22 22:50:13 GMT"));
-  this->MatchCookieLines("A=B", this->GetCookies(cs.get(), this->url_google_));
+  this->MatchCookieLines(
+      "A=B", this->GetCookies(cs.get(), this->http_www_google_.url()));
   // Delete it via Expires, with a unix epoch of 0.
-  EXPECT_TRUE(this->SetCookie(cs.get(),
-                              this->url_google_,
+  EXPECT_TRUE(this->SetCookie(cs.get(), this->http_www_google_.url(),
                               std::string(kValidCookieLine) +
                                   "; expires=Thu, 1-Jan-1970 00:00:00 GMT"));
-  this->MatchCookieLines(std::string(),
-                         this->GetCookies(cs.get(), this->url_google_));
+  this->MatchCookieLines(
+      std::string(), this->GetCookies(cs.get(), this->http_www_google_.url()));
 }
 
 TYPED_TEST_P(CookieStoreTest, TestDeleteAllCreatedBetween) {
@@ -796,32 +824,35 @@
                                 base::TimeDelta::FromDays(30);
 
   // Add a cookie.
-  EXPECT_TRUE(this->SetCookie(cs.get(), this->url_google_, "A=B"));
+  EXPECT_TRUE(this->SetCookie(cs.get(), this->http_www_google_.url(), "A=B"));
   // Check that the cookie is in the store.
-  this->MatchCookieLines("A=B", this->GetCookies(cs.get(), this->url_google_));
+  this->MatchCookieLines(
+      "A=B", this->GetCookies(cs.get(), this->http_www_google_.url()));
 
   // Remove cookies in empty intervals.
   EXPECT_EQ(0, this->DeleteCreatedBetween(cs.get(), last_month, last_minute));
   EXPECT_EQ(0, this->DeleteCreatedBetween(cs.get(), next_minute, next_month));
   // Check that the cookie is still there.
-  this->MatchCookieLines("A=B", this->GetCookies(cs.get(), this->url_google_));
+  this->MatchCookieLines(
+      "A=B", this->GetCookies(cs.get(), this->http_www_google_.url()));
 
   // Remove the cookie with an interval defined by two dates.
   EXPECT_EQ(1, this->DeleteCreatedBetween(cs.get(), last_minute, next_minute));
   // Check that the cookie disappeared.
-  this->MatchCookieLines(std::string(),
-                         this->GetCookies(cs.get(), this->url_google_));
+  this->MatchCookieLines(
+      std::string(), this->GetCookies(cs.get(), this->http_www_google_.url()));
 
   // Add another cookie.
-  EXPECT_TRUE(this->SetCookie(cs.get(), this->url_google_, "C=D"));
+  EXPECT_TRUE(this->SetCookie(cs.get(), this->http_www_google_.url(), "C=D"));
   // Check that the cookie is in the store.
-  this->MatchCookieLines("C=D", this->GetCookies(cs.get(), this->url_google_));
+  this->MatchCookieLines(
+      "C=D", this->GetCookies(cs.get(), this->http_www_google_.url()));
 
   // Remove the cookie with a null ending time.
   EXPECT_EQ(1, this->DeleteCreatedBetween(cs.get(), last_minute, base::Time()));
   // Check that the cookie disappeared.
-  this->MatchCookieLines(std::string(),
-                         this->GetCookies(cs.get(), this->url_google_));
+  this->MatchCookieLines(
+      std::string(), this->GetCookies(cs.get(), this->http_www_google_.url()));
 }
 
 TYPED_TEST_P(CookieStoreTest, TestDeleteAllCreatedBetweenForHost) {
@@ -830,9 +861,9 @@
   base::Time now = base::Time::Now();
 
   // These 3 cookies match the time range and host.
-  EXPECT_TRUE(this->SetCookie(cs.get(), this->url_google_, "A=B"));
-  EXPECT_TRUE(this->SetCookie(cs.get(), this->url_google_, "C=D"));
-  EXPECT_TRUE(this->SetCookie(cs.get(), this->url_google_, "Y=Z"));
+  EXPECT_TRUE(this->SetCookie(cs.get(), this->http_www_google_.url(), "A=B"));
+  EXPECT_TRUE(this->SetCookie(cs.get(), this->http_www_google_.url(), "C=D"));
+  EXPECT_TRUE(this->SetCookie(cs.get(), this->http_www_google_.url(), "Y=Z"));
 
   // This cookie does not match host.
   EXPECT_TRUE(this->SetCookie(cs.get(), url_not_google, "E=F"));
@@ -840,39 +871,43 @@
   // Delete cookies.
   EXPECT_EQ(
       3,  // Deletes A=B, C=D, Y=Z
-      this->DeleteAllCreatedBetweenForHost(
-          cs.get(), now, base::Time::Max(), this->url_google_));
+      this->DeleteAllCreatedBetweenForHost(cs.get(), now, base::Time::Max(),
+                                           this->http_www_google_.url()));
 }
 
 TYPED_TEST_P(CookieStoreTest, TestSecure) {
     scoped_refptr<CookieStore> cs(this->GetCookieStore());
 
-    EXPECT_TRUE(this->SetCookie(cs.get(), this->url_google_, "A=B"));
-    this->MatchCookieLines("A=B",
-                           this->GetCookies(cs.get(), this->url_google_));
+    EXPECT_TRUE(this->SetCookie(cs.get(), this->http_www_google_.url(), "A=B"));
     this->MatchCookieLines(
-        "A=B", this->GetCookies(cs.get(), this->url_google_secure_));
+        "A=B", this->GetCookies(cs.get(), this->http_www_google_.url()));
+    this->MatchCookieLines(
+        "A=B", this->GetCookies(cs.get(), this->https_www_google_.url()));
 
-  EXPECT_TRUE(
-      this->SetCookie(cs.get(), this->url_google_secure_, "A=B; secure"));
+    EXPECT_TRUE(this->SetCookie(cs.get(), this->https_www_google_.url(),
+                                "A=B; secure"));
   // The secure should overwrite the non-secure.
-  this->MatchCookieLines(std::string(),
-                         this->GetCookies(cs.get(), this->url_google_));
-  this->MatchCookieLines("A=B",
-                         this->GetCookies(cs.get(), this->url_google_secure_));
+    this->MatchCookieLines(
+        std::string(),
+        this->GetCookies(cs.get(), this->http_www_google_.url()));
+    this->MatchCookieLines(
+        "A=B", this->GetCookies(cs.get(), this->https_www_google_.url()));
 
-  EXPECT_TRUE(
-      this->SetCookie(cs.get(), this->url_google_secure_, "D=E; secure"));
-  this->MatchCookieLines(std::string(),
-                         this->GetCookies(cs.get(), this->url_google_));
-  this->MatchCookieLines("A=B; D=E",
-                         this->GetCookies(cs.get(), this->url_google_secure_));
+    EXPECT_TRUE(this->SetCookie(cs.get(), this->https_www_google_.url(),
+                                "D=E; secure"));
+    this->MatchCookieLines(
+        std::string(),
+        this->GetCookies(cs.get(), this->http_www_google_.url()));
+    this->MatchCookieLines(
+        "A=B; D=E", this->GetCookies(cs.get(), this->https_www_google_.url()));
 
-  EXPECT_TRUE(this->SetCookie(cs.get(), this->url_google_secure_, "A=B"));
+    EXPECT_TRUE(
+        this->SetCookie(cs.get(), this->https_www_google_.url(), "A=B"));
   // The non-secure should overwrite the secure.
-  this->MatchCookieLines("A=B", this->GetCookies(cs.get(), this->url_google_));
-  this->MatchCookieLines("D=E; A=B",
-                         this->GetCookies(cs.get(), this->url_google_secure_));
+    this->MatchCookieLines(
+        "A=B", this->GetCookies(cs.get(), this->http_www_google_.url()));
+    this->MatchCookieLines(
+        "D=E; A=B", this->GetCookies(cs.get(), this->https_www_google_.url()));
 }
 
 static const int kLastAccessThresholdMilliseconds = 200;
@@ -993,18 +1028,18 @@
 TYPED_TEST_P(CookieStoreTest, DeleteSessionCookie) {
   scoped_refptr<CookieStore> cs(this->GetCookieStore());
   // Create a session cookie and a persistent cookie.
+  EXPECT_TRUE(this->SetCookie(cs.get(), this->http_www_google_.url(),
+                              std::string(kValidCookieLine)));
   EXPECT_TRUE(this->SetCookie(
-      cs.get(), this->url_google_, std::string(kValidCookieLine)));
-  EXPECT_TRUE(this->SetCookie(cs.get(),
-                              this->url_google_,
-                              "C=D; path=/; domain=google.izzle;"
-                              "expires=Mon, 18-Apr-22 22:50:13 GMT"));
-  this->MatchCookieLines("A=B; C=D",
-                         this->GetCookies(cs.get(), this->url_google_));
+      cs.get(), this->http_www_google_.url(),
+      this->http_www_google_.Format("C=D; path=/; domain=%D;"
+                                    "expires=Mon, 18-Apr-22 22:50:13 GMT")));
+  this->MatchCookieLines(
+      "A=B; C=D", this->GetCookies(cs.get(), this->http_www_google_.url()));
   // Delete the session cookie.
   this->DeleteSessionCookies(cs.get());
   // Check that the session cookie has been deleted but not the persistent one.
-  EXPECT_EQ("C=D", this->GetCookies(cs.get(), this->url_google_));
+  EXPECT_EQ("C=D", this->GetCookies(cs.get(), this->http_www_google_.url()));
 }
 
 REGISTER_TYPED_TEST_CASE_P(CookieStoreTest,
@@ -1110,12 +1145,13 @@
 // thread).
 TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckGetCookies) {
   scoped_refptr<CookieStore> cs(this->GetCookieStore());
-  EXPECT_TRUE(this->SetCookie(cs.get(), this->url_google_, "A=B"));
-  this->MatchCookieLines("A=B", this->GetCookies(cs.get(), this->url_google_));
+  EXPECT_TRUE(this->SetCookie(cs.get(), this->http_www_google_.url(), "A=B"));
+  this->MatchCookieLines(
+      "A=B", this->GetCookies(cs.get(), this->http_www_google_.url()));
   StringResultCookieCallback callback(&this->other_thread_);
-  base::Closure task =
-      base::Bind(&MultiThreadedCookieStoreTest<TypeParam>::GetCookiesTask,
-                 base::Unretained(this), cs, this->url_google_, &callback);
+  base::Closure task = base::Bind(
+      &MultiThreadedCookieStoreTest<TypeParam>::GetCookiesTask,
+      base::Unretained(this), cs, this->http_www_google_.url(), &callback);
   this->RunOnOtherThread(task);
   EXPECT_TRUE(callback.did_run());
   EXPECT_EQ("A=B", callback.result());
@@ -1126,13 +1162,15 @@
   CookieOptions options;
   if (!TypeParam::supports_http_only)
     options.set_include_httponly();
-  EXPECT_TRUE(this->SetCookie(cs.get(), this->url_google_, "A=B"));
+  EXPECT_TRUE(this->SetCookie(cs.get(), this->http_www_google_.url(), "A=B"));
   this->MatchCookieLines(
-      "A=B", this->GetCookiesWithOptions(cs.get(), this->url_google_, options));
+      "A=B", this->GetCookiesWithOptions(cs.get(), this->http_www_google_.url(),
+                                         options));
   StringResultCookieCallback callback(&this->other_thread_);
   base::Closure task = base::Bind(
       &MultiThreadedCookieStoreTest<TypeParam>::GetCookiesWithOptionsTask,
-      base::Unretained(this), cs, this->url_google_, options, &callback);
+      base::Unretained(this), cs, this->http_www_google_.url(), options,
+      &callback);
   this->RunOnOtherThread(task);
   EXPECT_TRUE(callback.did_run());
   EXPECT_EQ("A=B", callback.result());
@@ -1143,12 +1181,13 @@
   CookieOptions options;
   if (!TypeParam::supports_http_only)
     options.set_include_httponly();
-  EXPECT_TRUE(
-      this->SetCookieWithOptions(cs.get(), this->url_google_, "A=B", options));
+  EXPECT_TRUE(this->SetCookieWithOptions(cs.get(), this->http_www_google_.url(),
+                                         "A=B", options));
   ResultSavingCookieCallback<bool> callback(&this->other_thread_);
   base::Closure task = base::Bind(
       &MultiThreadedCookieStoreTest<TypeParam>::SetCookieWithOptionsTask,
-      base::Unretained(this), cs, this->url_google_, "A=B", options, &callback);
+      base::Unretained(this), cs, this->http_www_google_.url(), "A=B", options,
+      &callback);
   this->RunOnOtherThread(task);
   EXPECT_TRUE(callback.did_run());
   EXPECT_TRUE(callback.result());
@@ -1159,15 +1198,15 @@
   CookieOptions options;
   if (!TypeParam::supports_http_only)
     options.set_include_httponly();
-  EXPECT_TRUE(
-      this->SetCookieWithOptions(cs.get(), this->url_google_, "A=B", options));
-  this->DeleteCookie(cs.get(), this->url_google_, "A");
-  EXPECT_TRUE(
-      this->SetCookieWithOptions(cs.get(), this->url_google_, "A=B", options));
+  EXPECT_TRUE(this->SetCookieWithOptions(cs.get(), this->http_www_google_.url(),
+                                         "A=B", options));
+  this->DeleteCookie(cs.get(), this->http_www_google_.url(), "A");
+  EXPECT_TRUE(this->SetCookieWithOptions(cs.get(), this->http_www_google_.url(),
+                                         "A=B", options));
   NoResultCookieCallback callback(&this->other_thread_);
-  base::Closure task =
-      base::Bind(&MultiThreadedCookieStoreTest<TypeParam>::DeleteCookieTask,
-                 base::Unretained(this), cs, this->url_google_, "A", &callback);
+  base::Closure task = base::Bind(
+      &MultiThreadedCookieStoreTest<TypeParam>::DeleteCookieTask,
+      base::Unretained(this), cs, this->http_www_google_.url(), "A", &callback);
   this->RunOnOtherThread(task);
   EXPECT_TRUE(callback.did_run());
 }
@@ -1177,17 +1216,15 @@
   CookieOptions options;
   if (!TypeParam::supports_http_only)
     options.set_include_httponly();
-  EXPECT_TRUE(
-      this->SetCookieWithOptions(cs.get(), this->url_google_, "A=B", options));
-  EXPECT_TRUE(
-      this->SetCookieWithOptions(cs.get(),
-                                 this->url_google_,
-                                 "B=C; expires=Mon, 18-Apr-22 22:50:13 GMT",
-                                 options));
+  EXPECT_TRUE(this->SetCookieWithOptions(cs.get(), this->http_www_google_.url(),
+                                         "A=B", options));
+  EXPECT_TRUE(this->SetCookieWithOptions(
+      cs.get(), this->http_www_google_.url(),
+      "B=C; expires=Mon, 18-Apr-22 22:50:13 GMT", options));
   EXPECT_EQ(1, this->DeleteSessionCookies(cs.get()));
   EXPECT_EQ(0, this->DeleteSessionCookies(cs.get()));
-  EXPECT_TRUE(
-      this->SetCookieWithOptions(cs.get(), this->url_google_, "A=B", options));
+  EXPECT_TRUE(this->SetCookieWithOptions(cs.get(), this->http_www_google_.url(),
+                                         "A=B", options));
   ResultSavingCookieCallback<int> callback(&this->other_thread_);
   base::Closure task = base::Bind(
       &MultiThreadedCookieStoreTest<TypeParam>::DeleteSessionCookiesTask,
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index c12f95d..a6655959 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -1078,7 +1078,7 @@
       NetLog::TYPE_HTTP_TRANSACTION_READ_RESPONSE_HEADERS,
       base::Bind(&HttpResponseHeaders::NetLogCallback, response_.headers));
 
-  if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0)) {
+  if (response_.headers->GetHttpVersion() < HttpVersion(1, 0)) {
     // HTTP/0.9 doesn't support the PUT method, so lack of response headers
     // indicates a buggy server.  See:
     // https://bugzilla.mozilla.org/show_bug.cgi?id=193921
diff --git a/net/http/http_proxy_client_socket.cc b/net/http/http_proxy_client_socket.cc
index ddcd2a4..e3e4e57 100644
--- a/net/http/http_proxy_client_socket.cc
+++ b/net/http/http_proxy_client_socket.cc
@@ -444,7 +444,7 @@
     return result;
 
   // Require the "HTTP/1.x" status line for SSL CONNECT.
-  if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0))
+  if (response_.headers->GetHttpVersion() < HttpVersion(1, 0))
     return ERR_TUNNEL_CONNECTION_FAILED;
 
   net_log_.AddEvent(
diff --git a/net/http/http_response_headers.cc b/net/http/http_response_headers.cc
index 24c8d3d..f89c30da 100644
--- a/net/http/http_response_headers.cc
+++ b/net/http/http_response_headers.cc
@@ -662,16 +662,16 @@
     std::string::const_iterator line_end,
     bool has_headers) {
   // Extract the version number
-  parsed_http_version_ = ParseVersion(line_begin, line_end);
+  HttpVersion parsed_http_version = ParseVersion(line_begin, line_end);
 
   // Clamp the version number to one of: {0.9, 1.0, 1.1, 2.0}
-  if (parsed_http_version_ == HttpVersion(0, 9) && !has_headers) {
+  if (parsed_http_version == HttpVersion(0, 9) && !has_headers) {
     http_version_ = HttpVersion(0, 9);
     raw_headers_ = "HTTP/0.9";
-  } else if (parsed_http_version_ == HttpVersion(2, 0)) {
+  } else if (parsed_http_version == HttpVersion(2, 0)) {
     http_version_ = HttpVersion(2, 0);
     raw_headers_ = "HTTP/2.0";
-  } else if (parsed_http_version_ >= HttpVersion(1, 1)) {
+  } else if (parsed_http_version >= HttpVersion(1, 1)) {
     http_version_ = HttpVersion(1, 1);
     raw_headers_ = "HTTP/1.1";
   } else {
@@ -679,7 +679,7 @@
     http_version_ = HttpVersion(1, 0);
     raw_headers_ = "HTTP/1.0";
   }
-  if (parsed_http_version_ != http_version_) {
+  if (parsed_http_version != http_version_) {
     DVLOG(1) << "assuming HTTP/" << http_version_.major_value() << "."
              << http_version_.minor_value();
   }
diff --git a/net/http/http_response_headers.h b/net/http/http_response_headers.h
index 3d8e656..caab083b 100644
--- a/net/http/http_response_headers.h
+++ b/net/http/http_response_headers.h
@@ -153,11 +153,6 @@
     return http_version_;
   }
 
-  // Get the HTTP version determined while parsing; or (0,0) if parsing failed
-  HttpVersion GetParsedHttpVersion() const {
-    return parsed_http_version_;
-  }
-
   // Get the HTTP status text of the normalized status line.
   std::string GetStatusText() const;
 
@@ -406,9 +401,6 @@
   // The normalized http version (consistent with what GetStatusLine() returns).
   HttpVersion http_version_;
 
-  // The parsed http version number (not normalized).
-  HttpVersion parsed_http_version_;
-
   DISALLOW_COPY_AND_ASSIGN(HttpResponseHeaders);
 };
 
diff --git a/net/http/http_response_headers_unittest.cc b/net/http/http_response_headers_unittest.cc
index 35a6360..ead30dd1 100644
--- a/net/http/http_response_headers_unittest.cc
+++ b/net/http/http_response_headers_unittest.cc
@@ -23,7 +23,6 @@
   const char* raw_headers;
   const char* expected_headers;
   int expected_response_code;
-  HttpVersion expected_parsed_version;
   HttpVersion expected_version;
 };
 
@@ -112,7 +111,6 @@
 
   EXPECT_EQ(test.expected_response_code, parsed->response_code());
 
-  EXPECT_TRUE(test.expected_parsed_version == parsed->GetParsedHttpVersion());
   EXPECT_TRUE(test.expected_version == parsed->GetHttpVersion());
 }
 
@@ -129,7 +127,6 @@
      "Set-Cookie: a, b\n",
 
      202,
-     HttpVersion(1, 1),
      HttpVersion(1, 1)},
     {// Normalize leading whitespace.
 
@@ -143,7 +140,6 @@
      "Set-Cookie: a, b\n",
 
      202,
-     HttpVersion(1, 1),
      HttpVersion(1, 1)},
     {// Normalize blank headers.
 
@@ -161,7 +157,6 @@
      "Header5: \n",
 
      200,
-     HttpVersion(1, 1),
      HttpVersion(1, 1)},
     {// Don't believe the http/0.9 version if there are headers!
 
@@ -172,7 +167,6 @@
      "Content-TYPE: text/html; charset=utf-8\n",
 
      201,
-     HttpVersion(0, 9),
      HttpVersion(1, 0)},
     {// Accept the HTTP/0.9 version number if there are no headers.
      // This is how HTTP/0.9 responses get constructed from
@@ -183,7 +177,6 @@
      "HTTP/0.9 200 OK\n",
 
      200,
-     HttpVersion(0, 9),
      HttpVersion(0, 9)},
     {// Add missing OK.
 
@@ -194,7 +187,6 @@
      "Content-TYPE: text/html; charset=utf-8\n",
 
      201,
-     HttpVersion(1, 1),
      HttpVersion(1, 1)},
     {// Normalize bad status line.
 
@@ -205,7 +197,6 @@
      "Content-TYPE: text/html; charset=utf-8\n",
 
      200,
-     HttpVersion(0, 0),  // Parse error.
      HttpVersion(1, 0)},
     {// Normalize invalid status code.
 
@@ -214,7 +205,6 @@
      "HTTP/1.1 200 OK\n",
 
      200,
-     HttpVersion(1, 1),
      HttpVersion(1, 1)},
     {// Normalize empty header.
 
@@ -223,7 +213,6 @@
      "HTTP/1.0 200 OK\n",
 
      200,
-     HttpVersion(0, 0),  // Parse Error.
      HttpVersion(1, 0)},
     {// Normalize headers that start with a colon.
 
@@ -238,7 +227,6 @@
      "baz: blat\n",
 
      202,
-     HttpVersion(1, 1),
      HttpVersion(1, 1)},
     {// Normalize headers that end with a colon.
 
@@ -255,7 +243,6 @@
      "zip: \n",
 
      202,
-     HttpVersion(1, 1),
      HttpVersion(1, 1)},
     {// Normalize whitespace headers.
 
@@ -264,7 +251,6 @@
      "HTTP/1.0 200 OK\n",
 
      200,
-     HttpVersion(0, 0),  // Parse error.
      HttpVersion(1, 0)},
     {// Consolidate Set-Cookie headers.
 
@@ -276,7 +262,6 @@
      "Set-Cookie: x=1, y=2\n",
 
      200,
-     HttpVersion(1, 1),
      HttpVersion(1, 1)},
 };
 
diff --git a/net/spdy/spdy_proxy_client_socket.cc b/net/spdy/spdy_proxy_client_socket.cc
index 9f0d594..3f611d83 100644
--- a/net/spdy/spdy_proxy_client_socket.cc
+++ b/net/spdy/spdy_proxy_client_socket.cc
@@ -393,7 +393,7 @@
     return result;
 
   // Require the "HTTP/1.x" status line for SSL CONNECT.
-  if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0))
+  if (response_.headers->GetHttpVersion() < HttpVersion(1, 0))
     return ERR_TUNNEL_CONNECTION_FAILED;
 
   net_log_.AddEvent(
diff --git a/net/url_request/url_request_data_job_unittest.cc b/net/url_request/url_request_data_job_unittest.cc
index 8c6d0939..b12bcb7c 100644
--- a/net/url_request/url_request_data_job_unittest.cc
+++ b/net/url_request/url_request_data_job_unittest.cc
@@ -29,7 +29,7 @@
   EXPECT_EQ("US-ASCII", charset);
   EXPECT_EQ("Hello", data);
 
-  const HttpVersion& version = headers->GetParsedHttpVersion();
+  const HttpVersion& version = headers->GetHttpVersion();
   EXPECT_EQ(1, version.major_value());
   EXPECT_EQ(1, version.minor_value());
   EXPECT_EQ("OK", headers->GetStatusText());
diff --git a/remoting/remoting_android.gypi b/remoting/remoting_android.gypi
index 14ce25f..861a94b4 100644
--- a/remoting/remoting_android.gypi
+++ b/remoting/remoting_android.gypi
@@ -134,7 +134,7 @@
               },
             }],
           ],
-        },
+        },  # end of target 'remoting_android_client_java'
         {
           'target_name': 'remoting_apk',
           'type': 'none',
@@ -168,11 +168,6 @@
           },
           'includes': [ '../build/java_apk.gypi' ],
         },  # end of target 'remoting_test_apk'
-      ], # end of 'targets'
-    }],  # 'OS=="android"'
-
-    ['OS=="android"', {
-      'targets': [
         {
           'target_name': 'remoting_unittests_apk',
           'type': 'none',
@@ -183,8 +178,8 @@
             'test_suite_name': 'remoting_unittests',
           },
           'includes': [ '../build/apk_test.gypi' ],
-        },
-      ],
+        },  # end of target 'remoting_unittests_apk'
+      ],  # end of 'targets'
     }],  # 'OS=="android"
   ],  # end of 'conditions'
 }
diff --git a/third_party/WebKit/LayoutTests/fast/text/text-transform-lower-lithuanian-expected.html b/third_party/WebKit/LayoutTests/fast/text/text-transform-lower-lithuanian-expected.html
index 6f970ff2..cafc45a 100644
--- a/third_party/WebKit/LayoutTests/fast/text/text-transform-lower-lithuanian-expected.html
+++ b/third_party/WebKit/LayoutTests/fast/text/text-transform-lower-lithuanian-expected.html
@@ -2,6 +2,11 @@
 <html>
 <head><meta charset="utf-8">
 <style>
+ @font-face {
+ font-family: libertine;
+ src: url("../../third_party/Libertine/LinLibertine_R.woff");
+ }
+ body { font-family: libertine, sans-serif; }
  .lower {color: green;}
 </style>
 </head>
diff --git a/third_party/WebKit/LayoutTests/fast/text/text-transform-lower-lithuanian.html b/third_party/WebKit/LayoutTests/fast/text/text-transform-lower-lithuanian.html
index c3b22b7..c7ea4f0 100644
--- a/third_party/WebKit/LayoutTests/fast/text/text-transform-lower-lithuanian.html
+++ b/third_party/WebKit/LayoutTests/fast/text/text-transform-lower-lithuanian.html
@@ -2,6 +2,11 @@
 <html>
 <head><meta charset="utf-8">
 <style>
+ @font-face {
+ font-family: libertine;
+ src: url("../../third_party/Libertine/LinLibertine_R.woff");
+ }
+ body { font-family: libertine, sans-serif; }
  .lower {text-transform: lowercase; color: green;}
 </style>
 </head>
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt
index 69937364..b5f618b 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt
@@ -807,6 +807,7 @@
     property willValidate
 html element shadow
     property getDistributedNodes
+html element slot
 html element small
 html element source
     property media
diff --git a/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt
index 5ba3374..08251431 100644
--- a/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt
@@ -850,6 +850,8 @@
     property willValidate
 html element shadow
     property getDistributedNodes
+html element slot
+    property name
 html element small
 html element source
     property media
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index a8bb4f1..90cc7c7 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -2661,6 +2661,10 @@
 interface HTMLShadowElement
     method constructor
     method getDistributedNodes
+interface HTMLSlotElement
+    getter name
+    method constructor
+    setter name
 interface HTMLSourceElement
     getter media
     getter sizes
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptPromisePropertyBase.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptPromisePropertyBase.cpp
index fd3dc1a..3685a094 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptPromisePropertyBase.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptPromisePropertyBase.cpp
@@ -103,6 +103,7 @@
 
 void ScriptPromisePropertyBase::resetBase()
 {
+    checkThis();
     clearWrappers();
     m_state = Pending;
 }
@@ -152,6 +153,8 @@
 
 void ScriptPromisePropertyBase::clearWrappers()
 {
+    checkThis();
+    checkWrappers();
     v8::HandleScope handleScope(m_isolate);
     for (WeakPersistentSet::iterator i = m_wrappers.begin(); i != m_wrappers.end(); ++i) {
         v8::Local<v8::Object> wrapper = (*i)->newLocal(m_isolate);
@@ -163,6 +166,18 @@
     m_wrappers.clear();
 }
 
+void ScriptPromisePropertyBase::checkThis()
+{
+    RELEASE_ASSERT(this);
+}
+
+void ScriptPromisePropertyBase::checkWrappers()
+{
+    for (WeakPersistentSet::iterator i = m_wrappers.begin(); i != m_wrappers.end(); ++i) {
+        RELEASE_ASSERT(*i);
+    }
+}
+
 v8::Local<v8::String> ScriptPromisePropertyBase::promiseName()
 {
     switch (m_name) {
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptPromisePropertyBase.h b/third_party/WebKit/Source/bindings/core/v8/ScriptPromisePropertyBase.h
index ea35525..4a6ec8b 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptPromisePropertyBase.h
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptPromisePropertyBase.h
@@ -10,6 +10,7 @@
 #include "bindings/core/v8/ScriptPromiseProperties.h"
 #include "core/CoreExport.h"
 #include "core/dom/ContextLifecycleObserver.h"
+#include "wtf/Compiler.h"
 #include "wtf/OwnPtr.h"
 #include "wtf/RefCounted.h"
 #include "wtf/Vector.h"
@@ -21,6 +22,7 @@
 class ExecutionContext;
 class ScriptState;
 
+// TODO(yhirano): Remove NEVER_INLINE once we find the cause of crashes.
 class CORE_EXPORT ScriptPromisePropertyBase : public GarbageCollectedFinalized<ScriptPromisePropertyBase>, public ContextLifecycleObserver {
     WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(ScriptPromisePropertyBase);
 public:
@@ -58,14 +60,17 @@
     virtual v8::Local<v8::Value> resolvedValue(v8::Isolate*, v8::Local<v8::Object> creationContext) = 0;
     virtual v8::Local<v8::Value> rejectedValue(v8::Isolate*, v8::Local<v8::Object> creationContext) = 0;
 
-    void resetBase();
+    NEVER_INLINE void resetBase();
 
 private:
     typedef Vector<OwnPtr<ScopedPersistent<v8::Object>>> WeakPersistentSet;
 
     void resolveOrRejectInternal(v8::Local<v8::Promise::Resolver>);
     v8::Local<v8::Object> ensureHolderWrapper(ScriptState*);
-    void clearWrappers();
+    NEVER_INLINE void clearWrappers();
+    // TODO(yhirano): Remove these functions once we find the cause of crashes.
+    NEVER_INLINE void checkThis();
+    NEVER_INLINE void checkWrappers();
 
     v8::Local<v8::String> promiseName();
     v8::Local<v8::String> resolverName();
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseResolverTest.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseResolverTest.cpp
index 44cbc15..c49e1a3 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseResolverTest.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseResolverTest.cpp
@@ -241,11 +241,11 @@
         resolver = ScriptPromiseResolverKeepAlive::create(scriptState());
     }
     resolver->keepAliveWhilePending();
-    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithSweep, Heap::ForcedGC);
+    Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, Heap::ForcedGC);
     ASSERT_TRUE(ScriptPromiseResolverKeepAlive::isAlive());
 
     resolver->resolve("hello");
-    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithSweep, Heap::ForcedGC);
+    Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, Heap::ForcedGC);
     EXPECT_FALSE(ScriptPromiseResolverKeepAlive::isAlive());
 }
 
@@ -258,11 +258,11 @@
         resolver = ScriptPromiseResolverKeepAlive::create(scriptState());
     }
     resolver->keepAliveWhilePending();
-    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithSweep, Heap::ForcedGC);
+    Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, Heap::ForcedGC);
     ASSERT_TRUE(ScriptPromiseResolverKeepAlive::isAlive());
 
     resolver->reject("hello");
-    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithSweep, Heap::ForcedGC);
+    Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, Heap::ForcedGC);
     EXPECT_FALSE(ScriptPromiseResolverKeepAlive::isAlive());
 }
 
@@ -275,11 +275,11 @@
         resolver = ScriptPromiseResolverKeepAlive::create(scriptState());
     }
     resolver->keepAliveWhilePending();
-    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithSweep, Heap::ForcedGC);
+    Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, Heap::ForcedGC);
     EXPECT_TRUE(ScriptPromiseResolverKeepAlive::isAlive());
 
     executionContext()->stopActiveDOMObjects();
-    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithSweep, Heap::ForcedGC);
+    Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, Heap::ForcedGC);
     EXPECT_FALSE(ScriptPromiseResolverKeepAlive::isAlive());
 }
 
@@ -292,16 +292,16 @@
         resolver = ScriptPromiseResolverKeepAlive::create(scriptState());
     }
     resolver->keepAliveWhilePending();
-    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithSweep, Heap::ForcedGC);
+    Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, Heap::ForcedGC);
     ASSERT_TRUE(ScriptPromiseResolverKeepAlive::isAlive());
 
     executionContext()->suspendActiveDOMObjects();
     resolver->resolve("hello");
-    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithSweep, Heap::ForcedGC);
+    Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, Heap::ForcedGC);
     EXPECT_TRUE(ScriptPromiseResolverKeepAlive::isAlive());
 
     executionContext()->stopActiveDOMObjects();
-    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithSweep, Heap::ForcedGC);
+    Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, Heap::ForcedGC);
     EXPECT_FALSE(ScriptPromiseResolverKeepAlive::isAlive());
 }
 
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp b/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp
index d3751473..fda87a4dc 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp
@@ -431,7 +431,7 @@
             TRACE_EVENT_SET_NONCONST_SAMPLING_STATE(V8PerIsolateData::from(isolate)->previousSamplingState());
         }
         if (ThreadState::current())
-            ThreadState::current()->scheduleV8FollowupGCIfNeeded(ThreadState::V8MinorGC);
+            ThreadState::current()->scheduleV8FollowupGCIfNeeded(BlinkGC::V8MinorGC);
         break;
     case v8::kGCTypeMarkSweepCompact:
         TRACE_EVENT_END1("devtools.timeline,v8", "MajorGC", "usedHeapSizeAfter", usedHeapSize(isolate));
@@ -451,7 +451,7 @@
             TRACE_EVENT_SET_NONCONST_SAMPLING_STATE(V8PerIsolateData::from(isolate)->previousSamplingState());
         }
         if (ThreadState::current())
-            ThreadState::current()->scheduleV8FollowupGCIfNeeded(ThreadState::V8MajorGC);
+            ThreadState::current()->scheduleV8FollowupGCIfNeeded(BlinkGC::V8MajorGC);
         break;
     default:
         ASSERT_NOT_REACHED();
@@ -475,7 +475,7 @@
         // to collect all garbage, you need to wait until the next event loop.
         // Regarding (2), it would be OK in practice to trigger only one GC per gcEpilogue, because
         // GCController.collectAll() forces 7 V8's GC.
-        Heap::collectGarbage(ThreadState::HeapPointersOnStack, ThreadState::GCWithSweep, Heap::ForcedGC);
+        Heap::collectGarbage(BlinkGC::HeapPointersOnStack, BlinkGC::GCWithSweep, Heap::ForcedGC);
 
         // Forces a precise GC at the end of the current event loop.
         if (ThreadState::current())
diff --git a/third_party/WebKit/Source/core/core.gypi b/third_party/WebKit/Source/core/core.gypi
index 744d0642..5e3ab20 100644
--- a/third_party/WebKit/Source/core/core.gypi
+++ b/third_party/WebKit/Source/core/core.gypi
@@ -202,6 +202,7 @@
             'html/HTMLScriptElement.idl',
             'html/HTMLSelectElement.idl',
             'html/HTMLShadowElement.idl',
+            'html/HTMLSlotElement.idl',
             'html/HTMLSourceElement.idl',
             'html/HTMLSpanElement.idl',
             'html/HTMLStyleElement.idl',
@@ -2782,6 +2783,8 @@
             'html/HTMLSelectElement.h',
             'html/HTMLShadowElement.cpp',
             'html/HTMLShadowElement.h',
+            'html/HTMLSlotElement.cpp',
+            'html/HTMLSlotElement.h',
             'html/HTMLSourceElement.cpp',
             'html/HTMLSourceElement.h',
             'html/HTMLSpanElement.cpp',
diff --git a/third_party/WebKit/Source/core/css/CSSValue.h b/third_party/WebKit/Source/core/css/CSSValue.h
index fc982a07..7d063a50 100644
--- a/third_party/WebKit/Source/core/css/CSSValue.h
+++ b/third_party/WebKit/Source/core/css/CSSValue.h
@@ -44,7 +44,7 @@
     static void* allocateObject(size_t size, bool isEager)
     {
         ThreadState* state = ThreadStateFor<ThreadingTrait<CSSValue>::Affinity>::state();
-        return Heap::allocateOnHeapIndex(state, size, isEager ? ThreadState::EagerSweepHeapIndex : ThreadState::CSSValueHeapIndex, GCInfoTrait<CSSValue>::index());
+        return Heap::allocateOnHeapIndex(state, size, isEager ? BlinkGC::EagerSweepHeapIndex : BlinkGC::CSSValueHeapIndex, GCInfoTrait<CSSValue>::index());
     }
 #else
     // Override RefCounted's deref() to ensure operator delete is called on
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
index b0588832..1632103 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -835,6 +835,46 @@
     return CSSQuadValue::create(top.release(), right.release(), bottom.release(), left.release(), CSSQuadValue::SerializeAsRect);
 }
 
+static bool consumePan(CSSParserTokenRange& range, RefPtrWillBeRawPtr<CSSValue>& panX, RefPtrWillBeRawPtr<CSSValue>& panY)
+{
+    CSSValueID id = range.peek().id();
+    if ((id == CSSValuePanX || id == CSSValuePanRight || id == CSSValuePanLeft) && !panX) {
+        if (id != CSSValuePanX && !RuntimeEnabledFeatures::cssTouchActionPanDirectionsEnabled())
+            return false;
+        panX = consumeIdent(range);
+    } else if ((id == CSSValuePanY || id == CSSValuePanDown || id == CSSValuePanUp) && !panY) {
+        if (id != CSSValuePanY && !RuntimeEnabledFeatures::cssTouchActionPanDirectionsEnabled())
+            return false;
+        panY = consumeIdent(range);
+    } else {
+        return false;
+    }
+    return true;
+}
+
+static PassRefPtrWillBeRawPtr<CSSValue> consumeTouchAction(CSSParserTokenRange& range)
+{
+    RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
+    CSSValueID id = range.peek().id();
+    if (id == CSSValueAuto || id == CSSValueNone || id == CSSValueManipulation) {
+        list->append(consumeIdent(range));
+        return list.release();
+    }
+
+    RefPtrWillBeRawPtr<CSSValue> panX = nullptr;
+    RefPtrWillBeRawPtr<CSSValue> panY = nullptr;
+    if (!consumePan(range, panX, panY))
+        return nullptr;
+    if (!range.atEnd() && !consumePan(range, panX, panY))
+        return nullptr;
+
+    if (panX)
+        list->append(panX.release());
+    if (panY)
+        list->append(panY.release());
+    return list.release();
+}
+
 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSingleValue(CSSPropertyID propId)
 {
     m_range.consumeWhitespace();
@@ -896,6 +936,8 @@
         return consumeWidthOrHeight(m_range, m_context);
     case CSSPropertyClip:
         return consumeClip(m_range, m_context.mode());
+    case CSSPropertyTouchAction:
+        return consumeTouchAction(m_range);
     default:
         return nullptr;
     }
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
index e6750b4..cd3d014 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
@@ -258,8 +258,6 @@
 
     PassRefPtrWillBeRawPtr<CSSValue> parseTextEmphasisStyle();
 
-    PassRefPtrWillBeRawPtr<CSSValue> parseTouchAction();
-
     PassRefPtrWillBeRawPtr<CSSValue> parseTextDecoration();
 
     bool parseCalculation(CSSParserValue*, ValueRange);
diff --git a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
index ca14e73d..78094f5f 100644
--- a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
@@ -1236,10 +1236,6 @@
         validPrimitive = validUnit(value, FNumber);
         break;
 
-    case CSSPropertyTouchAction:
-        parsedValue = parseTouchAction();
-        break;
-
     case CSSPropertyAlignContent:
         ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
         parsedValue = parseContentDistributionOverflowPosition();
@@ -1302,6 +1298,7 @@
     case CSSPropertyWebkitLogicalWidth:
     case CSSPropertyWebkitLogicalHeight:
     case CSSPropertyClip:
+    case CSSPropertyTouchAction:
         validPrimitive = false;
         break;
 
@@ -6138,57 +6135,6 @@
     return list.release();
 }
 
-PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseTouchAction()
-{
-    CSSParserValue* value = m_valueList->current();
-    RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
-    if (m_valueList->size() == 1 && value && (value->id == CSSValueAuto || value->id == CSSValueNone || value->id == CSSValueManipulation)) {
-        list->append(cssValuePool().createIdentifierValue(value->id));
-        m_valueList->next();
-        return list.release();
-    }
-
-    bool xSet = false;
-    bool ySet = false;
-    while (value) {
-        switch (value->id) {
-        case CSSValuePanX:
-        case CSSValuePanRight:
-        case CSSValuePanLeft: {
-            if (xSet)
-                return nullptr;
-            xSet = true;
-            if (value->id != CSSValuePanX && !RuntimeEnabledFeatures::cssTouchActionPanDirectionsEnabled())
-                return nullptr;
-
-            RefPtrWillBeRawPtr<CSSValue> panValue = cssValuePool().createIdentifierValue(value->id);
-            list->append(panValue.release());
-            break;
-        }
-        case CSSValuePanY:
-        case CSSValuePanDown:
-        case CSSValuePanUp: {
-            if (ySet)
-                return nullptr;
-            ySet = true;
-            if (value->id != CSSValuePanY && !RuntimeEnabledFeatures::cssTouchActionPanDirectionsEnabled())
-                return nullptr;
-            RefPtrWillBeRawPtr<CSSValue> panValue = cssValuePool().createIdentifierValue(value->id);
-            list->append(panValue.release());
-            break;
-        }
-        default:
-            return nullptr;
-        }
-        value = m_valueList->next();
-    }
-
-    if (list->length())
-        return list.release();
-
-    return nullptr;
-}
-
 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseTextDecoration()
 {
     CSSParserValue* value = m_valueList->current();
diff --git a/third_party/WebKit/Source/core/dom/CrossThreadTaskTest.cpp b/third_party/WebKit/Source/core/dom/CrossThreadTaskTest.cpp
index 9d23917..6b23f82e 100644
--- a/third_party/WebKit/Source/core/dom/CrossThreadTaskTest.cpp
+++ b/third_party/WebKit/Source/core/dom/CrossThreadTaskTest.cpp
@@ -37,7 +37,7 @@
     }
     void TearDown() override
     {
-        Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithSweep, Heap::ForcedGC);
+        Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, Heap::ForcedGC);
         ASSERT_EQ(0, GCObject::s_counter);
     }
 };
@@ -46,7 +46,7 @@
 {
     OwnPtr<ExecutionContextTask> task1 = createCrossThreadTask(&GCObject::run, new GCObject, new GCObject);
     OwnPtr<ExecutionContextTask> task2 = createCrossThreadTask(&GCObject::run, RawPtr<GCObject>(new GCObject), RawPtr<GCObject>(new GCObject));
-    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithSweep, Heap::ForcedGC);
+    Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, Heap::ForcedGC);
     EXPECT_EQ(4, GCObject::s_counter);
 }
 
@@ -54,7 +54,7 @@
 {
     OwnPtr<ExecutionContextTask> task1 = createCrossThreadTask(&functionWithGarbageCollected, new GCObject);
     OwnPtr<ExecutionContextTask> task2 = createCrossThreadTask(&functionWithGarbageCollected, RawPtr<GCObject>(new GCObject));
-    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithSweep, Heap::ForcedGC);
+    Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, Heap::ForcedGC);
     EXPECT_EQ(2, GCObject::s_counter);
 }
 
@@ -62,7 +62,7 @@
 {
     OwnPtr<ExecutionContextTask> task1 = createCrossThreadTask(&functionWithExecutionContext, new GCObject);
     OwnPtr<ExecutionContextTask> task2 = createCrossThreadTask(&functionWithExecutionContext, RawPtr<GCObject>(new GCObject));
-    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithSweep, Heap::ForcedGC);
+    Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, Heap::ForcedGC);
     EXPECT_EQ(2, GCObject::s_counter);
 }
 
diff --git a/third_party/WebKit/Source/core/dom/Node.cpp b/third_party/WebKit/Source/core/dom/Node.cpp
index 6d51b6b..baf73812 100644
--- a/third_party/WebKit/Source/core/dom/Node.cpp
+++ b/third_party/WebKit/Source/core/dom/Node.cpp
@@ -1510,7 +1510,7 @@
 
 void Node::showNodePathForThis() const
 {
-    Vector<const Node*, 16> chain;
+    WillBeHeapVector<RawPtrWillBeMember<const Node>, 16> chain;
     const Node* node = this;
     while (node->parentOrShadowHostNode()) {
         chain.append(node);
diff --git a/third_party/WebKit/Source/core/dom/Node.h b/third_party/WebKit/Source/core/dom/Node.h
index c6fcd05..102e195 100644
--- a/third_party/WebKit/Source/core/dom/Node.h
+++ b/third_party/WebKit/Source/core/dom/Node.h
@@ -178,7 +178,7 @@
     static void* allocateObject(size_t size, bool isEager)
     {
         ThreadState* state = ThreadStateFor<ThreadingTrait<Node>::Affinity>::state();
-        return Heap::allocateOnHeapIndex(state, size, isEager ? ThreadState::EagerSweepHeapIndex : ThreadState::NodeHeapIndex, GCInfoTrait<EventTarget>::index());
+        return Heap::allocateOnHeapIndex(state, size, isEager ? BlinkGC::EagerSweepHeapIndex : BlinkGC::NodeHeapIndex, GCInfoTrait<EventTarget>::index());
     }
 #else // !ENABLE(OILPAN)
     // All Nodes are placed in their own heap partition for security.
diff --git a/third_party/WebKit/Source/core/frame/ImageBitmapTest.cpp b/third_party/WebKit/Source/core/frame/ImageBitmapTest.cpp
index af8544f84..4f4f25a 100644
--- a/third_party/WebKit/Source/core/frame/ImageBitmapTest.cpp
+++ b/third_party/WebKit/Source/core/frame/ImageBitmapTest.cpp
@@ -72,7 +72,7 @@
         // Garbage collection is required prior to switching out the
         // test's memory cache; image resources are released, evicting
         // them from the cache.
-        Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithSweep, Heap::ForcedGC);
+        Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, Heap::ForcedGC);
 
         replaceMemoryCacheForTesting(m_globalMemoryCache.release());
     }
@@ -170,7 +170,7 @@
         ASSERT_EQ(memoryCache()->priority(imageOutsideCrop->cachedImage()), MemoryCacheLiveResourcePriorityLow);
     }
     // Force a garbage collection to sweep out the local ImageBitmaps.
-    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithSweep, Heap::ForcedGC);
+    Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, Heap::ForcedGC);
 
     // CacheLiveResourcePriroity should return to CacheLiveResourcePriorityLow when no ImageBitmaps reference the image.
     ASSERT_EQ(memoryCache()->priority(imageNoCrop->cachedImage()), MemoryCacheLiveResourcePriorityLow);
diff --git a/third_party/WebKit/Source/core/html/HTMLSlotElement.cpp b/third_party/WebKit/Source/core/html/HTMLSlotElement.cpp
new file mode 100644
index 0000000..17097b9
--- /dev/null
+++ b/third_party/WebKit/Source/core/html/HTMLSlotElement.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "core/html/HTMLSlotElement.h"
+
+#include "core/HTMLNames.h"
+
+namespace blink {
+
+using namespace HTMLNames;
+
+PassRefPtrWillBeRawPtr<HTMLSlotElement> HTMLSlotElement::create(Document& document)
+{
+    return adoptRefWillBeNoop(new HTMLSlotElement(document));
+}
+
+inline HTMLSlotElement::HTMLSlotElement(Document& document)
+    : InsertionPoint(slotTag, document)
+{
+}
+
+HTMLSlotElement::~HTMLSlotElement()
+{
+}
+
+DEFINE_TRACE(HTMLSlotElement)
+{
+    InsertionPoint::trace(visitor);
+}
+
+}
diff --git a/third_party/WebKit/Source/platform/heap/glue/PendingGCRunner.h b/third_party/WebKit/Source/core/html/HTMLSlotElement.h
similarity index 60%
copy from third_party/WebKit/Source/platform/heap/glue/PendingGCRunner.h
copy to third_party/WebKit/Source/core/html/HTMLSlotElement.h
index 6d41f0b..3fc8e9d1 100644
--- a/third_party/WebKit/Source/platform/heap/glue/PendingGCRunner.h
+++ b/third_party/WebKit/Source/core/html/HTMLSlotElement.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Google Inc. All rights reserved.
+ * Copyright (C) 2015 Google Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -28,46 +28,28 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef PendingGCRunner_h
-#define PendingGCRunner_h
+#ifndef HTMLSlotElement_h
+#define HTMLSlotElement_h
 
-#include "platform/heap/ThreadState.h"
-#include "public/platform/WebThread.h"
+#include "core/CoreExport.h"
+#include "core/dom/shadow/InsertionPoint.h"
 
 namespace blink {
 
-class PendingGCRunner : public WebThread::TaskObserver {
+class CORE_EXPORT HTMLSlotElement final : public InsertionPoint {
+    DEFINE_WRAPPERTYPEINFO();
 public:
-    PendingGCRunner() : m_nesting(0) { }
+    static PassRefPtrWillBeRawPtr<HTMLSlotElement> create(Document&);
+    ~HTMLSlotElement() override;
 
-    ~PendingGCRunner()
-    {
-        // m_nesting can be 1 if this was unregistered in a task and
-        // didProcessTask was not called.
-        ASSERT(!m_nesting || m_nesting == 1);
-    }
-
-    virtual void willProcessTask()
-    {
-        m_nesting++;
-    }
-
-    virtual void didProcessTask()
-    {
-        // In the production code WebKit::initialize is called from inside the
-        // message loop so we can get didProcessTask() without corresponding
-        // willProcessTask once. This is benign.
-        if (m_nesting)
-            m_nesting--;
-
-        ThreadState* state = ThreadState::current();
-        state->safePoint(m_nesting ? ThreadState::HeapPointersOnStack : ThreadState::NoHeapPointersOnStack);
-    }
+    DECLARE_VIRTUAL_TRACE();
 
 private:
-    int m_nesting;
+    HTMLSlotElement(Document&);
+
+    AtomicString m_name;
 };
 
 } // namespace blink
 
-#endif
+#endif // HTMLSlotElement_h
diff --git a/third_party/WebKit/Source/core/html/HTMLSlotElement.idl b/third_party/WebKit/Source/core/html/HTMLSlotElement.idl
new file mode 100644
index 0000000..1ad6719f
--- /dev/null
+++ b/third_party/WebKit/Source/core/html/HTMLSlotElement.idl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// http://w3c.github.io/webcomponents/spec/shadow/#the-slot-element
+
+[
+    RuntimeEnabled=ShadowDOMV1,
+] interface HTMLSlotElement : HTMLElement {
+    [Reflect] attribute DOMString name;
+};
diff --git a/third_party/WebKit/Source/core/html/HTMLTagNames.in b/third_party/WebKit/Source/core/html/HTMLTagNames.in
index 923233c..d782dfb 100644
--- a/third_party/WebKit/Source/core/html/HTMLTagNames.in
+++ b/third_party/WebKit/Source/core/html/HTMLTagNames.in
@@ -114,6 +114,7 @@
 script constructorNeedsCreatedByParser
 section interfaceName=HTMLElement
 select constructorNeedsFormElement
+slot interfaceName=HTMLSlotElement
 small interfaceName=HTMLElement
 source runtimeEnabled=media
 span
diff --git a/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp b/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp
index 041a2644..1b28e4f 100644
--- a/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp
@@ -88,7 +88,7 @@
 
     WebWaitableEvent* signalled;
     {
-        SafePointScope scope(ThreadState::HeapPointersOnStack);
+        SafePointScope scope(BlinkGC::HeapPointersOnStack);
         signalled = Platform::current()->waitMultipleEvents(events);
     }
     if (signalled == shutdownEvent) {
diff --git a/third_party/WebKit/Source/core/workers/WorkerThread.cpp b/third_party/WebKit/Source/core/workers/WorkerThread.cpp
index 9a4ee35..22705956e 100644
--- a/third_party/WebKit/Source/core/workers/WorkerThread.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkerThread.cpp
@@ -365,7 +365,7 @@
 void WorkerThread::terminate()
 {
     // Prevent the deadlock between GC and an attempt to terminate a thread.
-    SafePointScope safePointScope(ThreadState::HeapPointersOnStack);
+    SafePointScope safePointScope(BlinkGC::HeapPointersOnStack);
     terminateInternal();
 }
 
@@ -525,7 +525,7 @@
     {
         if (waitMode == DontWaitForTask)
             absoluteTime = 0.0;
-        SafePointScope safePointScope(ThreadState::NoHeapPointersOnStack);
+        SafePointScope safePointScope(BlinkGC::NoHeapPointersOnStack);
         task = m_debuggerTaskQueue->waitWithTimeout(result, absoluteTime);
     }
 
diff --git a/third_party/WebKit/Source/modules/imagebitmap/ImageBitmapModuleTest.cpp b/third_party/WebKit/Source/modules/imagebitmap/ImageBitmapModuleTest.cpp
index 325fdddc..0a6dc61 100644
--- a/third_party/WebKit/Source/modules/imagebitmap/ImageBitmapModuleTest.cpp
+++ b/third_party/WebKit/Source/modules/imagebitmap/ImageBitmapModuleTest.cpp
@@ -28,7 +28,7 @@
         // Garbage collection is required prior to switching out the
         // test's memory cache; image resources are released, evicting
         // them from the cache.
-        Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithSweep, Heap::ForcedGC);
+        Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, Heap::ForcedGC);
 
         replaceMemoryCacheForTesting(m_globalMemoryCache.release());
     }
diff --git a/third_party/WebKit/Source/modules/webdatabase/DatabaseThread.cpp b/third_party/WebKit/Source/modules/webdatabase/DatabaseThread.cpp
index 810e198..cd1f6a7 100644
--- a/third_party/WebKit/Source/modules/webdatabase/DatabaseThread.cpp
+++ b/third_party/WebKit/Source/modules/webdatabase/DatabaseThread.cpp
@@ -35,8 +35,7 @@
 #include "modules/webdatabase/SQLTransactionCoordinator.h"
 #include "platform/Logging.h"
 #include "platform/ThreadSafeFunctional.h"
-#include "platform/heap/glue/MessageLoopInterruptor.h"
-#include "platform/heap/glue/PendingGCRunner.h"
+#include "platform/WebThreadSupportingGC.h"
 #include "public/platform/Platform.h"
 
 namespace blink {
diff --git a/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteFileSystem.cpp b/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteFileSystem.cpp
index bf00209..98ebdcf 100644
--- a/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteFileSystem.cpp
+++ b/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteFileSystem.cpp
@@ -46,7 +46,7 @@
 
 int SQLiteFileSystem::openDatabase(const String& filename, sqlite3** database)
 {
-    SafePointScope scope(ThreadState::HeapPointersOnStack);
+    SafePointScope scope(BlinkGC::HeapPointersOnStack);
     return sqlite3_open_v2(filename.utf8().data(), database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, "chromium_vfs");
 }
 
diff --git a/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteStatement.cpp b/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteStatement.cpp
index 8d73d15..01adc486 100644
--- a/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteStatement.cpp
+++ b/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteStatement.cpp
@@ -107,7 +107,7 @@
     *statement = nullptr;
     int error;
     {
-        SafePointScope scope(ThreadState::HeapPointersOnStack);
+        SafePointScope scope(BlinkGC::HeapPointersOnStack);
 
         WTF_LOG(SQLDatabase, "SQL - prepare - %s", query.data());
 
@@ -132,7 +132,7 @@
 
 int SQLiteStatement::step()
 {
-    SafePointScope scope(ThreadState::HeapPointersOnStack);
+    SafePointScope scope(BlinkGC::HeapPointersOnStack);
     //ASSERT(m_isPrepared);
 
     if (!m_statement)
diff --git a/third_party/WebKit/Source/modules/websockets/WorkerWebSocketChannel.cpp b/third_party/WebKit/Source/modules/websockets/WorkerWebSocketChannel.cpp
index a4f8bcf..8da3121 100644
--- a/third_party/WebKit/Source/modules/websockets/WorkerWebSocketChannel.cpp
+++ b/third_party/WebKit/Source/modules/websockets/WorkerWebSocketChannel.cpp
@@ -470,7 +470,7 @@
 
     // We wait for the syncHelper event even if a shutdown event is fired.
     // See https://codereview.chromium.org/267323004/#msg43 for why we need to wait this.
-    SafePointScope scope(ThreadState::HeapPointersOnStack);
+    SafePointScope scope(BlinkGC::HeapPointersOnStack);
     m_syncHelper->wait();
     // This is checking whether a shutdown event is fired or not.
     return !m_workerGlobalScope->thread()->terminated();
diff --git a/third_party/WebKit/Source/platform/TaskSynchronizer.cpp b/third_party/WebKit/Source/platform/TaskSynchronizer.cpp
index e4fbb92..075d3b1 100644
--- a/third_party/WebKit/Source/platform/TaskSynchronizer.cpp
+++ b/third_party/WebKit/Source/platform/TaskSynchronizer.cpp
@@ -44,7 +44,7 @@
     if (ThreadState::current()) {
         // Prevent the deadlock between park request by other threads and blocking
         // by m_synchronousCondition.
-        SafePointScope scope(ThreadState::HeapPointersOnStack);
+        SafePointScope scope(BlinkGC::HeapPointersOnStack);
         waitForTaskCompletionInternal();
     } else {
         // If this thread is already detached, we no longer need to enter a safe point scope.
diff --git a/third_party/WebKit/Source/platform/WebThreadSupportingGC.cpp b/third_party/WebKit/Source/platform/WebThreadSupportingGC.cpp
index f9c11fb..0902c7a 100644
--- a/third_party/WebKit/Source/platform/WebThreadSupportingGC.cpp
+++ b/third_party/WebKit/Source/platform/WebThreadSupportingGC.cpp
@@ -41,7 +41,7 @@
 {
     if (ThreadState::current() && m_owningThread) {
         // WebThread's destructor blocks until all the tasks are processed.
-        SafePointScope scope(ThreadState::HeapPointersOnStack);
+        SafePointScope scope(BlinkGC::HeapPointersOnStack);
         m_owningThread.clear();
     }
 }
diff --git a/third_party/WebKit/Source/platform/WebThreadSupportingGC.h b/third_party/WebKit/Source/platform/WebThreadSupportingGC.h
index fe831c20..c2afaf0 100644
--- a/third_party/WebKit/Source/platform/WebThreadSupportingGC.h
+++ b/third_party/WebKit/Source/platform/WebThreadSupportingGC.h
@@ -5,8 +5,8 @@
 #ifndef WebThreadSupportingGC_h
 #define WebThreadSupportingGC_h
 
-#include "platform/heap/glue/MessageLoopInterruptor.h"
-#include "platform/heap/glue/PendingGCRunner.h"
+#include "platform/heap/MessageLoopInterruptor.h"
+#include "platform/heap/PendingGCRunner.h"
 #include "public/platform/Platform.h"
 #include "public/platform/WebTaskRunner.h"
 #include "public/platform/WebThread.h"
diff --git a/third_party/WebKit/Source/platform/heap/BlinkGC.h b/third_party/WebKit/Source/platform/heap/BlinkGC.h
new file mode 100644
index 0000000..9ba6d51
--- /dev/null
+++ b/third_party/WebKit/Source/platform/heap/BlinkGC.h
@@ -0,0 +1,106 @@
+// Copyright 2015 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 BlinkGC_h
+#define BlinkGC_h
+
+// BlinkGC.h is a file that defines common things used by Blink GC.
+
+#include "wtf/Allocator.h"
+
+namespace blink {
+
+class Visitor;
+
+#define PRINT_HEAP_STATS 0 // Enable this macro to print heap stats to stderr.
+
+using Address = uint8_t*;
+
+using FinalizationCallback = void (*)(void*);
+using VisitorCallback = void (*)(Visitor*, void* self);
+using TraceCallback = VisitorCallback;
+using WeakCallback = VisitorCallback;
+using EphemeronCallback = VisitorCallback;
+using PreFinalizerCallback = bool(*)(void*);
+
+// List of typed heaps. The list is used to generate the implementation
+// of typed heap related methods.
+//
+// To create a new typed heap add a H(<ClassName>) to the
+// FOR_EACH_TYPED_HEAP macro below.
+#define FOR_EACH_TYPED_HEAP(H)              \
+    H(Node)                                 \
+    H(CSSValue)
+
+#define TypedHeapEnumName(Type) Type##HeapIndex,
+
+class PLATFORM_EXPORT BlinkGC final {
+    STATIC_ONLY(BlinkGC);
+public:
+    // When garbage collecting we need to know whether or not there
+    // can be pointers to Blink GC managed objects on the stack for
+    // each thread. When threads reach a safe point they record
+    // whether or not they have pointers on the stack.
+    enum StackState {
+        NoHeapPointersOnStack,
+        HeapPointersOnStack
+    };
+
+    enum GCType {
+        // Both of the marking task and the sweeping task run in
+        // Heap::collectGarbage().
+        GCWithSweep,
+        // Only the marking task runs in Heap::collectGarbage().
+        // The sweeping task is split into chunks and scheduled lazily.
+        GCWithoutSweep,
+        // Only the marking task runs just to take a heap snapshot.
+        // The sweeping task doesn't run. The marks added in the marking task
+        // are just cleared.
+        TakeSnapshot,
+        // The marking task does not mark objects outside the heap of the GCing
+        // thread.
+        ThreadTerminationGC,
+    };
+
+    enum HeapIndices {
+        EagerSweepHeapIndex = 0,
+        NormalPage1HeapIndex,
+        NormalPage2HeapIndex,
+        NormalPage3HeapIndex,
+        NormalPage4HeapIndex,
+        Vector1HeapIndex,
+        Vector2HeapIndex,
+        Vector3HeapIndex,
+        Vector4HeapIndex,
+        InlineVectorHeapIndex,
+        HashTableHeapIndex,
+        FOR_EACH_TYPED_HEAP(TypedHeapEnumName)
+        LargeObjectHeapIndex,
+        // Values used for iteration of heap segments.
+        NumberOfHeaps,
+    };
+
+#if defined(ADDRESS_SANITIZER)
+    // Heaps can have their object payloads be poisoned, or cleared
+    // of their poisoning.
+    enum Poisoning {
+        SetPoison,
+        ClearPoison,
+    };
+
+    enum ObjectsToPoison {
+        UnmarkedOnly,
+        MarkedAndUnmarked,
+    };
+#endif
+
+    enum V8GCType {
+        V8MinorGC,
+        V8MajorGC,
+    };
+};
+
+} // namespace blink
+
+#endif
diff --git a/third_party/WebKit/Source/platform/heap/BlinkGCMemoryDumpProvider.cpp b/third_party/WebKit/Source/platform/heap/BlinkGCMemoryDumpProvider.cpp
index 5fc5eb7..338fc28 100644
--- a/third_party/WebKit/Source/platform/heap/BlinkGCMemoryDumpProvider.cpp
+++ b/third_party/WebKit/Source/platform/heap/BlinkGCMemoryDumpProvider.cpp
@@ -48,7 +48,7 @@
         return true;
     }
 
-    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::TakeSnapshot, Heap::ForcedGC);
+    Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::TakeSnapshot, Heap::ForcedGC);
     dumpMemoryTotals(memoryDump);
 
     // Merge all dumps collected by Heap::collectGarbage.
diff --git a/third_party/WebKit/Source/platform/heap/Heap.cpp b/third_party/WebKit/Source/platform/heap/Heap.cpp
index 53e5a364..c5acc84 100644
--- a/third_party/WebKit/Source/platform/heap/Heap.cpp
+++ b/third_party/WebKit/Source/platform/heap/Heap.cpp
@@ -81,12 +81,12 @@
 
 class GCScope final {
 public:
-    GCScope(ThreadState* state, ThreadState::StackState stackState, ThreadState::GCType gcType)
+    GCScope(ThreadState* state, BlinkGC::StackState stackState, BlinkGC::GCType gcType)
         : m_state(state)
         , m_gcForbiddenScope(state)
         // See collectGarbageForTerminatingThread() comment on why a
         // safepoint scope isn't entered for its GCScope.
-        , m_safePointScope(stackState, gcType != ThreadState::ThreadTerminationGC ? state : nullptr)
+        , m_safePointScope(stackState, gcType != BlinkGC::ThreadTerminationGC ? state : nullptr)
         , m_gcType(gcType)
         , m_parkedAllThreads(false)
     {
@@ -100,18 +100,18 @@
         // TODO(haraken): In an unlikely coincidence that two threads decide
         // to collect garbage at the same time, avoid doing two GCs in
         // a row.
-        if (LIKELY(gcType != ThreadState::ThreadTerminationGC && ThreadState::stopThreads()))
+        if (LIKELY(gcType != BlinkGC::ThreadTerminationGC && ThreadState::stopThreads()))
             m_parkedAllThreads = true;
 
         switch (gcType) {
-        case ThreadState::GCWithSweep:
-        case ThreadState::GCWithoutSweep:
+        case BlinkGC::GCWithSweep:
+        case BlinkGC::GCWithoutSweep:
             m_visitor = adoptPtr(new MarkingVisitor<Visitor::GlobalMarking>());
             break;
-        case ThreadState::TakeSnapshot:
+        case BlinkGC::TakeSnapshot:
             m_visitor = adoptPtr(new MarkingVisitor<Visitor::SnapshotMarking>());
             break;
-        case ThreadState::ThreadTerminationGC:
+        case BlinkGC::ThreadTerminationGC:
             m_visitor = adoptPtr(new MarkingVisitor<Visitor::ThreadLocalMarking>());
             break;
         default:
@@ -129,7 +129,7 @@
     {
         // Only cleanup if we parked all threads in which case the GC happened
         // and we need to resume the other threads.
-        if (LIKELY(m_gcType != ThreadState::ThreadTerminationGC && m_parkedAllThreads))
+        if (LIKELY(m_gcType != BlinkGC::ThreadTerminationGC && m_parkedAllThreads))
             ThreadState::resumeThreads();
     }
 
@@ -141,7 +141,7 @@
     // to be in a GC forbidden scope when doing so.
     GCForbiddenScope m_gcForbiddenScope;
     SafePointScope m_safePointScope;
-    ThreadState::GCType m_gcType;
+    BlinkGC::GCType m_gcType;
     OwnPtr<Visitor> m_visitor;
     bool m_parkedAllThreads; // False if we fail to park all threads
 };
@@ -392,7 +392,7 @@
         state->preGC();
 }
 
-void Heap::postGC(ThreadState::GCType gcType)
+void Heap::postGC(BlinkGC::GCType gcType)
 {
     ASSERT(ThreadState::current()->isInGC());
     for (ThreadState* state : ThreadState::attachedThreads())
@@ -415,7 +415,7 @@
     return "<Unknown>";
 }
 
-void Heap::collectGarbage(ThreadState::StackState stackState, ThreadState::GCType gcType, GCReason reason)
+void Heap::collectGarbage(BlinkGC::StackState stackState, BlinkGC::GCType gcType, GCReason reason)
 {
     ThreadState* state = ThreadState::current();
     // Nested collectGarbage() invocations aren't supported.
@@ -432,12 +432,12 @@
         ScriptForbiddenScope::enter();
 
     TRACE_EVENT2("blink_gc", "Heap::collectGarbage",
-        "lazySweeping", gcType == ThreadState::GCWithoutSweep,
+        "lazySweeping", gcType == BlinkGC::GCWithoutSweep,
         "gcReason", gcReasonString(reason));
     TRACE_EVENT_SCOPED_SAMPLING_STATE("blink_gc", "BlinkGC");
     double timeStamp = WTF::currentTimeMS();
 
-    if (gcType == ThreadState::TakeSnapshot)
+    if (gcType == BlinkGC::TakeSnapshot)
         BlinkGCMemoryDumpProvider::instance()->clearProcessDumpForCurrentGC();
 
     // Disallow allocation during garbage collection (but not during the
@@ -449,7 +449,7 @@
     StackFrameDepthScope stackDepthScope;
 
     size_t totalObjectSize = Heap::allocatedObjectSize() + Heap::markedObjectSize();
-    if (gcType != ThreadState::TakeSnapshot)
+    if (gcType != BlinkGC::TakeSnapshot)
         Heap::resetHeapCounters();
 
     // 1. Trace persistent roots.
@@ -474,7 +474,7 @@
     s_estimatedMarkingTimePerByte = totalObjectSize ? (markingTimeInMilliseconds / 1000 / totalObjectSize) : 0;
 
 #if PRINT_HEAP_STATS
-    dataLogF("Heap::collectGarbage (gcReason=%s, lazySweeping=%d, time=%.1lfms)\n", gcReasonString(reason), gcType == ThreadState::GCWithoutSweep, markingTimeInMilliseconds);
+    dataLogF("Heap::collectGarbage (gcReason=%s, lazySweeping=%d, time=%.1lfms)\n", gcReasonString(reason), gcType == BlinkGC::GCWithoutSweep, markingTimeInMilliseconds);
 #endif
 
     Platform::current()->histogramCustomCounts("BlinkGC.CollectGarbage", markingTimeInMilliseconds, 0, 10 * 1000, 50);
@@ -497,7 +497,7 @@
         // ahead while it is running, hence the termination GC does not enter a
         // safepoint. GCScope will not enter also a safepoint scope for
         // ThreadTerminationGC.
-        GCScope gcScope(state, ThreadState::NoHeapPointersOnStack, ThreadState::ThreadTerminationGC);
+        GCScope gcScope(state, BlinkGC::NoHeapPointersOnStack, BlinkGC::ThreadTerminationGC);
 
         ThreadState::NoAllocationScope noAllocationScope(state);
 
@@ -523,7 +523,7 @@
         postMarkingProcessing(gcScope.visitor());
         globalWeakProcessing(gcScope.visitor());
 
-        state->postGC(ThreadState::GCWithSweep);
+        state->postGC(BlinkGC::GCWithSweep);
     }
     state->preSweep();
 }
@@ -584,7 +584,7 @@
     // We need to run multiple GCs to collect a chain of persistent handles.
     size_t previousLiveObjects = 0;
     for (int i = 0; i < 5; ++i) {
-        collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithSweep, ForcedGC);
+        collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, ForcedGC);
         size_t liveObjects = Heap::markedObjectSize();
         if (liveObjects == previousLiveObjects)
             break;
diff --git a/third_party/WebKit/Source/platform/heap/Heap.h b/third_party/WebKit/Source/platform/heap/Heap.h
index 355b1719..644e662a 100644
--- a/third_party/WebKit/Source/platform/heap/Heap.h
+++ b/third_party/WebKit/Source/platform/heap/Heap.h
@@ -205,7 +205,7 @@
         NumberOfGCReason,
     };
     static const char* gcReasonString(GCReason);
-    static void collectGarbage(ThreadState::StackState, ThreadState::GCType, GCReason);
+    static void collectGarbage(BlinkGC::StackState, BlinkGC::GCType, GCReason);
     static void collectGarbageForTerminatingThread(ThreadState*);
     static void collectAllGarbage();
 
@@ -215,7 +215,7 @@
     static void setForcePreciseGCForTesting();
 
     static void preGC();
-    static void postGC(ThreadState::GCType);
+    static void postGC(BlinkGC::GCType);
 
     // Conservatively checks whether an address is a pointer in any of the
     // thread heaps.  If so marks the object pointed to as live.
@@ -411,17 +411,17 @@
 {
     if (size < 64) {
         if (size < 32)
-            return ThreadState::NormalPage1HeapIndex;
-        return ThreadState::NormalPage2HeapIndex;
+            return BlinkGC::NormalPage1HeapIndex;
+        return BlinkGC::NormalPage2HeapIndex;
     }
     if (size < 128)
-        return ThreadState::NormalPage3HeapIndex;
-    return ThreadState::NormalPage4HeapIndex;
+        return BlinkGC::NormalPage3HeapIndex;
+    return BlinkGC::NormalPage4HeapIndex;
 }
 
 inline bool Heap::isNormalHeapIndex(int index)
 {
-    return index >= ThreadState::NormalPage1HeapIndex && index <= ThreadState::NormalPage4HeapIndex;
+    return index >= BlinkGC::NormalPage1HeapIndex && index <= BlinkGC::NormalPage4HeapIndex;
 }
 
 #define DECLARE_EAGER_FINALIZATION_OPERATOR_NEW() \
@@ -432,7 +432,7 @@
         return allocateObject(size, true);        \
     }
 
-#define IS_EAGERLY_FINALIZED() (pageFromObject(this)->heap()->heapIndex() == ThreadState::EagerSweepHeapIndex)
+#define IS_EAGERLY_FINALIZED() (pageFromObject(this)->heap()->heapIndex() == BlinkGC::EagerSweepHeapIndex)
 #if ENABLE(ASSERT) && ENABLE(OILPAN)
 class VerifyEagerFinalization {
 public:
@@ -467,7 +467,7 @@
 inline Address Heap::allocateOnHeapIndex(ThreadState* state, size_t size, int heapIndex, size_t gcInfoIndex)
 {
     ASSERT(state->isAllocationAllowed());
-    ASSERT(heapIndex != ThreadState::LargeObjectHeapIndex);
+    ASSERT(heapIndex != BlinkGC::LargeObjectHeapIndex);
     NormalPageHeap* heap = static_cast<NormalPageHeap*>(state->heap(heapIndex));
     return heap->allocateObject(allocationSizeFromSize(size), gcInfoIndex);
 }
@@ -476,7 +476,7 @@
 Address Heap::allocate(size_t size, bool eagerlySweep)
 {
     ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state();
-    return Heap::allocateOnHeapIndex(state, size, eagerlySweep ? ThreadState::EagerSweepHeapIndex : Heap::heapIndexForObjectSize(size), GCInfoTrait<T>::index());
+    return Heap::allocateOnHeapIndex(state, size, eagerlySweep ? BlinkGC::EagerSweepHeapIndex : Heap::heapIndexForObjectSize(size), GCInfoTrait<T>::index());
 }
 
 template<typename T>
@@ -498,7 +498,7 @@
     int heapIndex = page->heap()->heapIndex();
     // Recompute the effective heap index if previous allocation
     // was on the normal heaps or a large object.
-    if (isNormalHeapIndex(heapIndex) || heapIndex == ThreadState::LargeObjectHeapIndex)
+    if (isNormalHeapIndex(heapIndex) || heapIndex == BlinkGC::LargeObjectHeapIndex)
         heapIndex = heapIndexForObjectSize(size);
 
     // TODO(haraken): We don't support reallocate() for finalizable objects.
diff --git a/third_party/WebKit/Source/platform/heap/HeapAllocator.h b/third_party/WebKit/Source/platform/heap/HeapAllocator.h
index ece36a27..5765214 100644
--- a/third_party/WebKit/Source/platform/heap/HeapAllocator.h
+++ b/third_party/WebKit/Source/platform/heap/HeapAllocator.h
@@ -60,7 +60,7 @@
     {
         size_t gcInfoIndex = GCInfoTrait<HeapVectorBacking<T, VectorTraits<T>>>::index();
         ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state();
-        return reinterpret_cast<T*>(Heap::allocateOnHeapIndex(state, size, ThreadState::InlineVectorHeapIndex, gcInfoIndex));
+        return reinterpret_cast<T*>(Heap::allocateOnHeapIndex(state, size, BlinkGC::InlineVectorHeapIndex, gcInfoIndex));
     }
     static void freeInlineVectorBacking(void*);
     static bool expandInlineVectorBacking(void*, size_t);
@@ -71,7 +71,7 @@
     {
         size_t gcInfoIndex = GCInfoTrait<HeapHashTableBacking<HashTable>>::index();
         ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state();
-        return reinterpret_cast<T*>(Heap::allocateOnHeapIndex(state, size, ThreadState::HashTableHeapIndex, gcInfoIndex));
+        return reinterpret_cast<T*>(Heap::allocateOnHeapIndex(state, size, BlinkGC::HashTableHeapIndex, gcInfoIndex));
     }
     template <typename T, typename HashTable>
     static T* allocateZeroedHashTableBacking(size_t size)
diff --git a/third_party/WebKit/Source/platform/heap/HeapPage.cpp b/third_party/WebKit/Source/platform/heap/HeapPage.cpp
index a94679f..b4de4d6 100644
--- a/third_party/WebKit/Source/platform/heap/HeapPage.cpp
+++ b/third_party/WebKit/Source/platform/heap/HeapPage.cpp
@@ -314,10 +314,10 @@
 }
 
 #if defined(ADDRESS_SANITIZER)
-void BaseHeap::poisonHeap(ThreadState::ObjectsToPoison objectsToPoison, ThreadState::Poisoning poisoning)
+void BaseHeap::poisonHeap(BlinkGC::ObjectsToPoison objectsToPoison, BlinkGC::Poisoning poisoning)
 {
     // TODO(sof): support complete poisoning of all heaps.
-    ASSERT(objectsToPoison != ThreadState::MarkedAndUnmarked || heapIndex() == ThreadState::EagerSweepHeapIndex);
+    ASSERT(objectsToPoison != BlinkGC::MarkedAndUnmarked || heapIndex() == BlinkGC::EagerSweepHeapIndex);
 
     // This method may either be called to poison (SetPoison) heap
     // object payloads prior to sweeping, or it may be called at
@@ -325,7 +325,7 @@
     // objects remaining in the heap. Those will all be live and unmarked.
     //
     // Poisoning may be limited to unmarked objects only, or apply to all.
-    if (poisoning == ThreadState::SetPoison) {
+    if (poisoning == BlinkGC::SetPoison) {
         for (BasePage* page = m_firstUnsweptPage; page; page = page->next())
             page->poisonObjects(objectsToPoison, poisoning);
         return;
@@ -804,8 +804,8 @@
     // 1. If this allocation is big enough, allocate a large object.
     if (allocationSize >= largeObjectSizeThreshold) {
         // TODO(sof): support eagerly finalized large objects, if ever needed.
-        RELEASE_ASSERT(heapIndex() != ThreadState::EagerSweepHeapIndex);
-        LargeObjectHeap* largeObjectHeap = static_cast<LargeObjectHeap*>(threadState()->heap(ThreadState::LargeObjectHeapIndex));
+        RELEASE_ASSERT(heapIndex() != BlinkGC::EagerSweepHeapIndex);
+        LargeObjectHeap* largeObjectHeap = static_cast<LargeObjectHeap*>(threadState()->heap(BlinkGC::LargeObjectHeapIndex));
         Address largeObject = largeObjectHeap->allocateLargeObjectPage(allocationSize, gcInfoIndex);
         ASAN_MARK_LARGE_VECTOR_CONTAINER(this, largeObject);
         return largeObject;
@@ -1337,7 +1337,7 @@
 }
 
 #if defined(ADDRESS_SANITIZER)
-void NormalPage::poisonObjects(ThreadState::ObjectsToPoison objectsToPoison, ThreadState::Poisoning poisoning)
+void NormalPage::poisonObjects(BlinkGC::ObjectsToPoison objectsToPoison, BlinkGC::Poisoning poisoning)
 {
     for (Address headerAddress = payload(); headerAddress < payloadEnd();) {
         HeapObjectHeader* header = reinterpret_cast<HeapObjectHeader*>(headerAddress);
@@ -1349,8 +1349,8 @@
             continue;
         }
         ASSERT(header->checkHeader());
-        if (objectsToPoison == ThreadState::MarkedAndUnmarked || !header->isMarked()) {
-            if (poisoning == ThreadState::SetPoison)
+        if (objectsToPoison == BlinkGC::MarkedAndUnmarked || !header->isMarked()) {
+            if (poisoning == BlinkGC::SetPoison)
                 ASAN_POISON_MEMORY_REGION(header->payload(), header->payloadSize());
             else
                 ASAN_UNPOISON_MEMORY_REGION(header->payload(), header->payloadSize());
@@ -1677,11 +1677,11 @@
 }
 
 #if defined(ADDRESS_SANITIZER)
-void LargeObjectPage::poisonObjects(ThreadState::ObjectsToPoison objectsToPoison, ThreadState::Poisoning poisoning)
+void LargeObjectPage::poisonObjects(BlinkGC::ObjectsToPoison objectsToPoison, BlinkGC::Poisoning poisoning)
 {
     HeapObjectHeader* header = heapObjectHeader();
-    if (objectsToPoison == ThreadState::MarkedAndUnmarked || !header->isMarked()) {
-        if (poisoning == ThreadState::SetPoison)
+    if (objectsToPoison == BlinkGC::MarkedAndUnmarked || !header->isMarked()) {
+        if (poisoning == BlinkGC::SetPoison)
             ASAN_POISON_MEMORY_REGION(header->payload(), header->payloadSize());
         else
             ASAN_UNPOISON_MEMORY_REGION(header->payload(), header->payloadSize());
diff --git a/third_party/WebKit/Source/platform/heap/HeapPage.h b/third_party/WebKit/Source/platform/heap/HeapPage.h
index 29ddbd30..e8473d42 100644
--- a/third_party/WebKit/Source/platform/heap/HeapPage.h
+++ b/third_party/WebKit/Source/platform/heap/HeapPage.h
@@ -32,6 +32,7 @@
 #define HeapPage_h
 
 #include "platform/PlatformExport.h"
+#include "platform/heap/BlinkGC.h"
 #include "platform/heap/GCInfo.h"
 #include "platform/heap/ThreadState.h"
 #include "platform/heap/Visitor.h"
@@ -395,7 +396,7 @@
     virtual void makeConsistentForMutator() = 0;
 
 #if defined(ADDRESS_SANITIZER)
-    virtual void poisonObjects(ThreadState::ObjectsToPoison, ThreadState::Poisoning) = 0;
+    virtual void poisonObjects(BlinkGC::ObjectsToPoison, BlinkGC::Poisoning) = 0;
 #endif
     // Check if the given address points to an object in this
     // heap page. If so, find the start of that object and mark it
@@ -485,7 +486,7 @@
     void makeConsistentForGC() override;
     void makeConsistentForMutator() override;
 #if defined(ADDRESS_SANITIZER)
-    void poisonObjects(ThreadState::ObjectsToPoison, ThreadState::Poisoning) override;
+    void poisonObjects(BlinkGC::ObjectsToPoison, BlinkGC::Poisoning) override;
 #endif
     void checkAndMarkPointer(Visitor*, Address) override;
     void markOrphaned() override;
@@ -550,7 +551,7 @@
     void makeConsistentForGC() override;
     void makeConsistentForMutator() override;
 #if defined(ADDRESS_SANITIZER)
-    void poisonObjects(ThreadState::ObjectsToPoison, ThreadState::Poisoning) override;
+    void poisonObjects(BlinkGC::ObjectsToPoison, BlinkGC::Poisoning) override;
 #endif
     void checkAndMarkPointer(Visitor*, Address) override;
     void markOrphaned() override;
@@ -726,7 +727,7 @@
     void prepareHeapForTermination();
     void prepareForSweep();
 #if defined(ADDRESS_SANITIZER)
-    void poisonHeap(ThreadState::ObjectsToPoison, ThreadState::Poisoning);
+    void poisonHeap(BlinkGC::ObjectsToPoison, BlinkGC::Poisoning);
 #endif
     Address lazySweep(size_t, size_t gcInfoIndex);
     void sweepUnsweptPage();
diff --git a/third_party/WebKit/Source/platform/heap/HeapTest.cpp b/third_party/WebKit/Source/platform/heap/HeapTest.cpp
index cbd70dff..663b0b3 100644
--- a/third_party/WebKit/Source/platform/heap/HeapTest.cpp
+++ b/third_party/WebKit/Source/platform/heap/HeapTest.cpp
@@ -50,12 +50,12 @@
 
 static void preciselyCollectGarbage()
 {
-    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithSweep, Heap::ForcedGC);
+    Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, Heap::ForcedGC);
 }
 
 static void conservativelyCollectGarbage()
 {
-    Heap::collectGarbage(ThreadState::HeapPointersOnStack, ThreadState::GCWithSweep, Heap::ForcedGC);
+    Heap::collectGarbage(BlinkGC::HeapPointersOnStack, BlinkGC::GCWithSweep, Heap::ForcedGC);
 }
 
 class IntWrapper : public GarbageCollectedFinalized<IntWrapper> {
@@ -242,7 +242,7 @@
 
 class TestGCScope {
 public:
-    explicit TestGCScope(ThreadState::StackState state)
+    explicit TestGCScope(BlinkGC::StackState state)
         : m_state(ThreadState::current())
         , m_safePointScope(state)
         , m_parkedAllThreads(false)
@@ -261,7 +261,7 @@
         // Only cleanup if we parked all threads in which case the GC happened
         // and we need to resume the other threads.
         if (LIKELY(m_parkedAllThreads)) {
-            Heap::postGC(ThreadState::GCWithSweep);
+            Heap::postGC(BlinkGC::GCWithSweep);
             ThreadState::resumeThreads();
         }
     }
@@ -468,7 +468,7 @@
             m_threads.last()->taskRunner()->postTask(FROM_HERE, new Task(threadSafeBind(threadFunc, AllowCrossThreadAccess(tester))));
         }
         while (tester->m_threadsToFinish) {
-            SafePointScope scope(ThreadState::NoHeapPointersOnStack);
+            SafePointScope scope(BlinkGC::NoHeapPointersOnStack);
             Platform::current()->yieldCurrentThread();
         }
         delete tester;
@@ -524,7 +524,7 @@
         longLivingPersistent = createGlobalPersistent(0x2a2a2a2a);
         int gcCount = 0;
         while (!done()) {
-            ThreadState::current()->safePoint(ThreadState::NoHeapPointersOnStack);
+            ThreadState::current()->safePoint(BlinkGC::NoHeapPointersOnStack);
             {
                 Persistent<IntWrapper> wrapper;
 
@@ -535,7 +535,7 @@
                     if (!(i % 10)) {
                         globalPersistent = createGlobalPersistent(0x0ed0cabb);
                     }
-                    SafePointScope scope(ThreadState::NoHeapPointersOnStack);
+                    SafePointScope scope(BlinkGC::NoHeapPointersOnStack);
                     Platform::current()->yieldCurrentThread();
                 }
 
@@ -548,12 +548,12 @@
                 // Taking snapshot shouldn't have any bad side effect.
                 // TODO(haraken): This snapshot GC causes crashes, so disable
                 // it at the moment. Fix the crash and enable it.
-                // Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::TakeSnapshot, Heap::ForcedGC);
+                // Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::TakeSnapshot, Heap::ForcedGC);
                 preciselyCollectGarbage();
                 EXPECT_EQ(wrapper->value(), 0x0bbac0de);
                 EXPECT_EQ((*globalPersistent)->value(), 0x0ed0cabb);
             }
-            SafePointScope scope(ThreadState::NoHeapPointersOnStack);
+            SafePointScope scope(BlinkGC::NoHeapPointersOnStack);
             Platform::current()->yieldCurrentThread();
         }
 
@@ -582,7 +582,7 @@
 
         int gcCount = 0;
         while (!done()) {
-            ThreadState::current()->safePoint(ThreadState::NoHeapPointersOnStack);
+            ThreadState::current()->safePoint(BlinkGC::NoHeapPointersOnStack);
             {
                 Persistent<HeapHashMap<ThreadMarker, WeakMember<IntWrapper>>> weakMap = new HeapHashMap<ThreadMarker, WeakMember<IntWrapper>>;
                 PersistentHeapHashMap<ThreadMarker, WeakMember<IntWrapper>> weakMap2;
@@ -590,7 +590,7 @@
                 for (int i = 0; i < numberOfAllocations; i++) {
                     weakMap->add(static_cast<unsigned>(i), IntWrapper::create(0));
                     weakMap2.add(static_cast<unsigned>(i), IntWrapper::create(0));
-                    SafePointScope scope(ThreadState::NoHeapPointersOnStack);
+                    SafePointScope scope(BlinkGC::NoHeapPointersOnStack);
                     Platform::current()->yieldCurrentThread();
                 }
 
@@ -603,12 +603,12 @@
                 // Taking snapshot shouldn't have any bad side effect.
                 // TODO(haraken): This snapshot GC causes crashes, so disable
                 // it at the moment. Fix the crash and enable it.
-                // Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::TakeSnapshot, Heap::ForcedGC);
+                // Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::TakeSnapshot, Heap::ForcedGC);
                 preciselyCollectGarbage();
                 EXPECT_TRUE(weakMap->isEmpty());
                 EXPECT_TRUE(weakMap2.isEmpty());
             }
-            SafePointScope scope(ThreadState::NoHeapPointersOnStack);
+            SafePointScope scope(BlinkGC::NoHeapPointersOnStack);
             Platform::current()->yieldCurrentThread();
         }
         ThreadState::detach();
@@ -779,7 +779,7 @@
     void* operator new(size_t size)
     {
         ThreadState* state = ThreadState::current();
-        return Heap::allocateOnHeapIndex(state, size, ThreadState::NodeHeapIndex, GCInfoTrait<IntNode>::index());
+        return Heap::allocateOnHeapIndex(state, size, BlinkGC::NodeHeapIndex, GCInfoTrait<IntNode>::index());
     }
 
     static IntNode* create(int i)
@@ -1971,7 +1971,7 @@
     EXPECT_EQ(0, SimpleFinalizedObject::s_destructorCalls);
     for (int i = 0; i < 1000; i++)
         SimpleFinalizedObject::create();
-    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithoutSweep, Heap::ForcedGC);
+    Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithoutSweep, Heap::ForcedGC);
     EXPECT_EQ(0, SimpleFinalizedObject::s_destructorCalls);
     for (int i = 0; i < 10000; i++)
         SimpleFinalizedObject::create();
@@ -1998,7 +1998,7 @@
     EXPECT_EQ(0, LargeHeapObject::s_destructorCalls);
     for (int i = 0; i < 10; i++)
         LargeHeapObject::create();
-    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithoutSweep, Heap::ForcedGC);
+    Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithoutSweep, Heap::ForcedGC);
     EXPECT_EQ(0, LargeHeapObject::s_destructorCalls);
     for (int i = 0; i < 10; i++) {
         LargeHeapObject::create();
@@ -2007,7 +2007,7 @@
     LargeHeapObject::create();
     LargeHeapObject::create();
     EXPECT_EQ(10, LargeHeapObject::s_destructorCalls);
-    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithoutSweep, Heap::ForcedGC);
+    Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithoutSweep, Heap::ForcedGC);
     EXPECT_EQ(10, LargeHeapObject::s_destructorCalls);
     preciselyCollectGarbage();
     EXPECT_EQ(22, LargeHeapObject::s_destructorCalls);
@@ -2082,7 +2082,7 @@
         SimpleFinalizedEagerObject::create();
     for (int i = 0; i < 100; i++)
         SimpleFinalizedObjectInstanceOfTemplate::create();
-    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithoutSweep, Heap::ForcedGC);
+    Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithoutSweep, Heap::ForcedGC);
     EXPECT_EQ(0, SimpleFinalizedObject::s_destructorCalls);
     EXPECT_EQ(100, SimpleFinalizedEagerObject::s_destructorCalls);
     EXPECT_EQ(100, SimpleFinalizedObjectInstanceOfTemplate::s_destructorCalls);
@@ -3799,7 +3799,7 @@
     // to allocate anything again. We do this by forcing a GC after doing the
     // checkAndMarkPointer tests.
     {
-        TestGCScope scope(ThreadState::HeapPointersOnStack);
+        TestGCScope scope(BlinkGC::HeapPointersOnStack);
         EXPECT_TRUE(scope.allThreadsParked()); // Fail the test if we could not park all threads.
         Heap::flushHeapDoesNotContainCache();
         for (size_t i = 0; i < objectAddresses.size(); i++) {
@@ -3818,7 +3818,7 @@
     // however we don't rely on that below since we don't have any allocations.
     clearOutOldGarbage();
     {
-        TestGCScope scope(ThreadState::HeapPointersOnStack);
+        TestGCScope scope(BlinkGC::HeapPointersOnStack);
         EXPECT_TRUE(scope.allThreadsParked());
         Heap::flushHeapDoesNotContainCache();
         for (size_t i = 0; i < objectAddresses.size(); i++) {
@@ -4645,7 +4645,7 @@
 
         {
             // Expect the first attempt to park the sleeping thread to fail
-            TestGCScope scope(ThreadState::NoHeapPointersOnStack);
+            TestGCScope scope(BlinkGC::NoHeapPointersOnStack);
             EXPECT_FALSE(scope.allThreadsParked());
         }
 
@@ -4655,13 +4655,13 @@
         while (s_sleeperRunning) {
             // We enter the safepoint here since the sleeper thread will detach
             // causing it to GC.
-            ThreadState::current()->safePoint(ThreadState::NoHeapPointersOnStack);
+            ThreadState::current()->safePoint(BlinkGC::NoHeapPointersOnStack);
             Platform::current()->yieldCurrentThread();
         }
 
         {
             // Since the sleeper thread has detached this is the only thread.
-            TestGCScope scope(ThreadState::NoHeapPointersOnStack);
+            TestGCScope scope(BlinkGC::NoHeapPointersOnStack);
             EXPECT_TRUE(scope.allThreadsParked());
         }
     }
@@ -5375,7 +5375,7 @@
             // Wait for the main thread to do two GCs without sweeping this thread
             // heap. The worker waits within a safepoint, but there is no sweeping
             // until leaving the safepoint scope.
-            SafePointScope scope(ThreadState::NoHeapPointersOnStack);
+            SafePointScope scope(BlinkGC::NoHeapPointersOnStack);
             parkWorkerThread();
         }
 
@@ -5431,7 +5431,7 @@
 
         // Wait for the worker thread to sweep its heaps before checking.
         {
-            SafePointScope scope(ThreadState::NoHeapPointersOnStack);
+            SafePointScope scope(BlinkGC::NoHeapPointersOnStack);
             parkMainThread();
         }
     }
@@ -5469,7 +5469,7 @@
             // scope. If the weak collection backing is marked dead
             // because of this we will not get strongification in the
             // GC we force when we continue.
-            SafePointScope scope(ThreadState::NoHeapPointersOnStack);
+            SafePointScope scope(BlinkGC::NoHeapPointersOnStack);
             parkWorkerThread();
         }
 
@@ -5660,7 +5660,7 @@
         // to acquire the same global lock that the thread just got and deadlock
         // unless the global lock is recursive.
         parkWorkerThread();
-        SafePointAwareMutexLocker recursiveLocker(recursiveMutex(), ThreadState::NoHeapPointersOnStack);
+        SafePointAwareMutexLocker recursiveLocker(recursiveMutex(), BlinkGC::NoHeapPointersOnStack);
 
         // We won't get here unless the lock is recursive since the sweep done
         // in the constructor of SafePointAwareMutexLocker after
@@ -6381,7 +6381,7 @@
     parkWorkerThread();
 
     // Step 4: Run a GC.
-    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithSweep, Heap::ForcedGC);
+    Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, Heap::ForcedGC);
     wakeMainThread();
     parkWorkerThread();
 
@@ -6418,7 +6418,7 @@
 
     {
         // Pretend we have no pointers on stack during the step 4.
-        SafePointScope scope(ThreadState::NoHeapPointersOnStack);
+        SafePointScope scope(BlinkGC::NoHeapPointersOnStack);
         wakeWorkerThread();
         parkMainThread();
     }
diff --git a/third_party/WebKit/Source/platform/heap/glue/MessageLoopInterruptor.h b/third_party/WebKit/Source/platform/heap/MessageLoopInterruptor.h
similarity index 100%
rename from third_party/WebKit/Source/platform/heap/glue/MessageLoopInterruptor.h
rename to third_party/WebKit/Source/platform/heap/MessageLoopInterruptor.h
diff --git a/third_party/WebKit/Source/platform/heap/PagePool.cpp b/third_party/WebKit/Source/platform/heap/PagePool.cpp
index b46fc70..f88e90c 100644
--- a/third_party/WebKit/Source/platform/heap/PagePool.cpp
+++ b/third_party/WebKit/Source/platform/heap/PagePool.cpp
@@ -13,7 +13,7 @@
 
 FreePagePool::~FreePagePool()
 {
-    for (int index = 0; index < ThreadState::NumberOfHeaps; ++index) {
+    for (int index = 0; index < BlinkGC::NumberOfHeaps; ++index) {
         while (PoolEntry* entry = m_pool[index]) {
             m_pool[index] = entry->next;
             PageMemory* memory = entry->data;
@@ -54,7 +54,7 @@
 
 OrphanedPagePool::~OrphanedPagePool()
 {
-    for (int index = 0; index < ThreadState::NumberOfHeaps; ++index) {
+    for (int index = 0; index < BlinkGC::NumberOfHeaps; ++index) {
         while (PoolEntry* entry = m_pool[index]) {
             m_pool[index] = entry->next;
             BasePage* page = entry->data;
@@ -85,7 +85,7 @@
         ASSERT(state->isAtSafePoint());
 #endif
 
-    for (int index = 0; index < ThreadState::NumberOfHeaps; ++index) {
+    for (int index = 0; index < BlinkGC::NumberOfHeaps; ++index) {
         PoolEntry* entry = m_pool[index];
         PoolEntry** prevNext = &m_pool[index];
         while (entry) {
@@ -140,7 +140,7 @@
 #if ENABLE(ASSERT)
 bool OrphanedPagePool::contains(void* object)
 {
-    for (int index = 0; index < ThreadState::NumberOfHeaps; ++index) {
+    for (int index = 0; index < BlinkGC::NumberOfHeaps; ++index) {
         for (PoolEntry* entry = m_pool[index]; entry; entry = entry->next) {
             BasePage* page = entry->data;
             if (page->contains(reinterpret_cast<Address>(object)))
diff --git a/third_party/WebKit/Source/platform/heap/PagePool.h b/third_party/WebKit/Source/platform/heap/PagePool.h
index 9b4e8b5f..c33a8e2 100644
--- a/third_party/WebKit/Source/platform/heap/PagePool.h
+++ b/third_party/WebKit/Source/platform/heap/PagePool.h
@@ -18,7 +18,7 @@
 protected:
     PagePool()
     {
-        for (int i = 0; i < ThreadState::NumberOfHeaps; ++i)
+        for (int i = 0; i < BlinkGC::NumberOfHeaps; ++i)
             m_pool[i] = nullptr;
     }
 
@@ -33,7 +33,7 @@
         PoolEntry* next;
     };
 
-    PoolEntry* m_pool[ThreadState::NumberOfHeaps];
+    PoolEntry* m_pool[BlinkGC::NumberOfHeaps];
 };
 
 // Once pages have been used for one type of thread heap they will never be
@@ -51,7 +51,7 @@
     PageMemory* takeFreePage(int);
 
 private:
-    Mutex m_mutex[ThreadState::NumberOfHeaps];
+    Mutex m_mutex[BlinkGC::NumberOfHeaps];
 };
 
 class OrphanedPagePool : public PagePool<BasePage> {
diff --git a/third_party/WebKit/Source/platform/heap/glue/PendingGCRunner.h b/third_party/WebKit/Source/platform/heap/PendingGCRunner.h
similarity index 95%
rename from third_party/WebKit/Source/platform/heap/glue/PendingGCRunner.h
rename to third_party/WebKit/Source/platform/heap/PendingGCRunner.h
index 6d41f0b..9f6131c 100644
--- a/third_party/WebKit/Source/platform/heap/glue/PendingGCRunner.h
+++ b/third_party/WebKit/Source/platform/heap/PendingGCRunner.h
@@ -61,7 +61,7 @@
             m_nesting--;
 
         ThreadState* state = ThreadState::current();
-        state->safePoint(m_nesting ? ThreadState::HeapPointersOnStack : ThreadState::NoHeapPointersOnStack);
+        state->safePoint(m_nesting ? BlinkGC::HeapPointersOnStack : BlinkGC::NoHeapPointersOnStack);
     }
 
 private:
diff --git a/third_party/WebKit/Source/platform/heap/SafePoint.h b/third_party/WebKit/Source/platform/heap/SafePoint.h
index 982cbe3..0b96633b 100644
--- a/third_party/WebKit/Source/platform/heap/SafePoint.h
+++ b/third_party/WebKit/Source/platform/heap/SafePoint.h
@@ -13,7 +13,7 @@
 class SafePointScope final {
     WTF_MAKE_NONCOPYABLE(SafePointScope);
 public:
-    explicit SafePointScope(ThreadState::StackState stackState, ThreadState* state = ThreadState::current())
+    explicit SafePointScope(BlinkGC::StackState stackState, ThreadState* state = ThreadState::current())
         : m_state(state)
     {
         if (m_state) {
@@ -40,7 +40,7 @@
 class SafePointAwareMutexLocker final {
     WTF_MAKE_NONCOPYABLE(SafePointAwareMutexLocker);
 public:
-    explicit SafePointAwareMutexLocker(MutexBase& mutex, ThreadState::StackState stackState = ThreadState::HeapPointersOnStack)
+    explicit SafePointAwareMutexLocker(MutexBase& mutex, BlinkGC::StackState stackState = BlinkGC::HeapPointersOnStack)
         : m_mutex(mutex)
         , m_locked(false)
     {
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.cpp b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
index 7bfba54..63c9ecf 100644
--- a/third_party/WebKit/Source/platform/heap/ThreadState.cpp
+++ b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
@@ -98,7 +98,7 @@
     , m_sweepForbidden(false)
     , m_noAllocationCount(0)
     , m_gcForbiddenCount(0)
-    , m_vectorBackingHeapIndex(Vector1HeapIndex)
+    , m_vectorBackingHeapIndex(BlinkGC::Vector1HeapIndex)
     , m_currentHeapAges(0)
     , m_isTerminating(false)
     , m_gcMixinMarker(nullptr)
@@ -123,9 +123,9 @@
             s_mainThreadUnderestimatedStackSize = underestimatedStackSize - sizeof(void*);
     }
 
-    for (int heapIndex = 0; heapIndex < LargeObjectHeapIndex; heapIndex++)
+    for (int heapIndex = 0; heapIndex < BlinkGC::LargeObjectHeapIndex; heapIndex++)
         m_heaps[heapIndex] = new NormalPageHeap(this, heapIndex);
-    m_heaps[LargeObjectHeapIndex] = new LargeObjectHeap(this, LargeObjectHeapIndex);
+    m_heaps[BlinkGC::LargeObjectHeapIndex] = new LargeObjectHeap(this, BlinkGC::LargeObjectHeapIndex);
 
     m_likelyToBePromptlyFreed = adoptArrayPtr(new int[likelyToBePromptlyFreedArraySize]);
     clearHeapAges();
@@ -138,7 +138,7 @@
     ASSERT(checkThread());
     delete m_threadLocalWeakCallbackStack;
     m_threadLocalWeakCallbackStack = nullptr;
-    for (int i = 0; i < NumberOfHeaps; ++i)
+    for (int i = 0; i < BlinkGC::NumberOfHeaps; ++i)
         delete m_heaps[i];
 
     **s_threadSpecific = nullptr;
@@ -181,7 +181,7 @@
     // 1. Finish sweeping.
     state->completeSweep();
     {
-        SafePointAwareMutexLocker locker(threadAttachMutex(), NoHeapPointersOnStack);
+        SafePointAwareMutexLocker locker(threadAttachMutex(), BlinkGC::NoHeapPointersOnStack);
 
         // 2. Add the main thread's heap pages to the orphaned pool.
         state->cleanupPages();
@@ -217,7 +217,7 @@
 void ThreadState::cleanupPages()
 {
     ASSERT(checkThread());
-    for (int i = 0; i < NumberOfHeaps; ++i)
+    for (int i = 0; i < BlinkGC::NumberOfHeaps; ++i)
         m_heaps[i]->cleanupPages();
 }
 
@@ -231,7 +231,7 @@
         // thread local GC asserts. We enter a safepoint while waiting for the
         // lock to avoid a dead-lock where another thread has already requested
         // GC.
-        SafePointAwareMutexLocker locker(threadAttachMutex(), NoHeapPointersOnStack);
+        SafePointAwareMutexLocker locker(threadAttachMutex(), BlinkGC::NoHeapPointersOnStack);
 
         // Finish sweeping.
         completeSweep();
@@ -329,7 +329,7 @@
 NO_SANITIZE_ADDRESS
 void ThreadState::visitStack(Visitor* visitor)
 {
-    if (m_stackState == NoHeapPointersOnStack)
+    if (m_stackState == BlinkGC::NoHeapPointersOnStack)
         return;
 
     Address* start = reinterpret_cast<Address*>(m_startOfStack);
@@ -418,7 +418,7 @@
     {                                                              \
         json->beginDictionary();                                   \
         json->setString("name", #HeapType);                        \
-        m_heaps[HeapType##HeapIndex]->snapshot(json.get(), &info); \
+        m_heaps[BlinkGC::HeapType##HeapIndex]->snapshot(json.get(), &info); \
         json->endDictionary();                                     \
     }
     json->beginArray("heaps");
@@ -475,7 +475,7 @@
 
 void ThreadState::incrementMarkedObjectsAge()
 {
-    for (int i = 0; i < NumberOfHeaps; ++i)
+    for (int i = 0; i < BlinkGC::NumberOfHeaps; ++i)
         m_heaps[i]->incrementMarkedObjectsAge();
 }
 #endif
@@ -647,13 +647,13 @@
     return judgeGCThreshold(0, 1.5);
 }
 
-void ThreadState::scheduleV8FollowupGCIfNeeded(V8GCType gcType)
+void ThreadState::scheduleV8FollowupGCIfNeeded(BlinkGC::V8GCType gcType)
 {
     ASSERT(checkThread());
     Heap::reportMemoryUsageForTracing();
 
 #if PRINT_HEAP_STATS
-    dataLogF("ThreadState::scheduleV8FollowupGCIfNeeded (gcType=%s)\n", gcType == V8MajorGC ? "MajorGC" : "MinorGC");
+    dataLogF("ThreadState::scheduleV8FollowupGCIfNeeded (gcType=%s)\n", gcType == BlinkGC::V8MajorGC ? "MajorGC" : "MinorGC");
 #endif
 
     if (isGCForbidden())
@@ -667,11 +667,11 @@
 
     // TODO(haraken): Consider if we should trigger a memory pressure GC
     // for V8 minor GCs as well.
-    if (gcType == V8MajorGC && shouldForceMemoryPressureGC()) {
+    if (gcType == BlinkGC::V8MajorGC && shouldForceMemoryPressureGC()) {
 #if PRINT_HEAP_STATS
         dataLogF("Scheduled MemoryPressureGC\n");
 #endif
-        Heap::collectGarbage(HeapPointersOnStack, GCWithoutSweep, Heap::MemoryPressureGC);
+        Heap::collectGarbage(BlinkGC::HeapPointersOnStack, BlinkGC::GCWithoutSweep, Heap::MemoryPressureGC);
         return;
     }
     if (shouldScheduleV8FollowupGC()) {
@@ -681,7 +681,7 @@
         schedulePreciseGC();
         return;
     }
-    if (gcType == V8MajorGC) {
+    if (gcType == BlinkGC::V8MajorGC) {
 #if PRINT_HEAP_STATS
         dataLogF("Scheduled IdleGC\n");
 #endif
@@ -709,7 +709,7 @@
 #if PRINT_HEAP_STATS
         dataLogF("Scheduled PageNavigationGC\n");
 #endif
-        Heap::collectGarbage(HeapPointersOnStack, GCWithSweep, Heap::PageNavigationGC);
+        Heap::collectGarbage(BlinkGC::HeapPointersOnStack, BlinkGC::GCWithSweep, Heap::PageNavigationGC);
     }
 }
 
@@ -736,7 +736,7 @@
 #if PRINT_HEAP_STATS
         dataLogF("Scheduled MemoryPressureGC\n");
 #endif
-        Heap::collectGarbage(HeapPointersOnStack, GCWithoutSweep, Heap::MemoryPressureGC);
+        Heap::collectGarbage(BlinkGC::HeapPointersOnStack, BlinkGC::GCWithoutSweep, Heap::MemoryPressureGC);
         return;
     }
     if (shouldSchedulePageNavigationGC(estimatedRemovalRatio)) {
@@ -775,7 +775,7 @@
 #if PRINT_HEAP_STATS
             dataLogF("Scheduled MemoryPressureGC\n");
 #endif
-            Heap::collectGarbage(HeapPointersOnStack, GCWithoutSweep, Heap::MemoryPressureGC);
+            Heap::collectGarbage(BlinkGC::HeapPointersOnStack, BlinkGC::GCWithoutSweep, Heap::MemoryPressureGC);
             return;
         }
     }
@@ -790,7 +790,7 @@
 #if PRINT_HEAP_STATS
             dataLogF("Scheduled ConservativeGC\n");
 #endif
-            Heap::collectGarbage(HeapPointersOnStack, GCWithoutSweep, Heap::ConservativeGC);
+            Heap::collectGarbage(BlinkGC::HeapPointersOnStack, BlinkGC::GCWithoutSweep, Heap::ConservativeGC);
             return;
         }
     }
@@ -820,7 +820,7 @@
         return;
     }
 
-    Heap::collectGarbage(NoHeapPointersOnStack, GCWithoutSweep, Heap::IdleGC);
+    Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithoutSweep, Heap::IdleGC);
 }
 
 void ThreadState::performIdleLazySweep(double deadlineSeconds)
@@ -846,7 +846,7 @@
         if (isMainThread())
             ScriptForbiddenScope::enter();
 
-        for (int i = 0; i < NumberOfHeaps; i++) {
+        for (int i = 0; i < BlinkGC::NumberOfHeaps; i++) {
             // lazySweepWithDeadline() won't check the deadline until it sweeps
             // 10 pages. So we give a small slack for safety.
             double slack = 0.001;
@@ -977,15 +977,10 @@
 
 #undef VERIFY_STATE_TRANSITION
 
-ThreadState::GCState ThreadState::gcState() const
-{
-    return m_gcState;
-}
-
-void ThreadState::runScheduledGC(StackState stackState)
+void ThreadState::runScheduledGC(BlinkGC::StackState stackState)
 {
     ASSERT(checkThread());
-    if (stackState != NoHeapPointersOnStack)
+    if (stackState != BlinkGC::NoHeapPointersOnStack)
         return;
 
     // If a safe point is entered while initiating a GC, we clearly do
@@ -1001,10 +996,10 @@
         Heap::collectAllGarbage();
         break;
     case PreciseGCScheduled:
-        Heap::collectGarbage(NoHeapPointersOnStack, GCWithoutSweep, Heap::PreciseGC);
+        Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithoutSweep, Heap::PreciseGC);
         break;
     case PageNavigationGCScheduled:
-        Heap::collectGarbage(NoHeapPointersOnStack, GCWithSweep, Heap::PageNavigationGC);
+        Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, Heap::PageNavigationGC);
         break;
     case IdleGCScheduled:
         // Idle time GC will be scheduled by Blink Scheduler.
@@ -1026,14 +1021,14 @@
 {
     ASSERT(isInGC());
     TRACE_EVENT0("blink_gc", "ThreadState::makeConsistentForGC");
-    for (int i = 0; i < NumberOfHeaps; ++i)
+    for (int i = 0; i < BlinkGC::NumberOfHeaps; ++i)
         m_heaps[i]->makeConsistentForGC();
 }
 
 void ThreadState::makeConsistentForMutator()
 {
     ASSERT(isInGC());
-    for (int i = 0; i < NumberOfHeaps; ++i)
+    for (int i = 0; i < BlinkGC::NumberOfHeaps; ++i)
         m_heaps[i]->makeConsistentForMutator();
 }
 
@@ -1046,7 +1041,7 @@
     clearHeapAges();
 }
 
-void ThreadState::postGC(GCType gcType)
+void ThreadState::postGC(BlinkGC::GCType gcType)
 {
     ASSERT(isInGC());
 
@@ -1068,12 +1063,12 @@
     }
 #endif
 
-    for (int i = 0; i < NumberOfHeaps; i++)
+    for (int i = 0; i < BlinkGC::NumberOfHeaps; i++)
         m_heaps[i]->prepareForSweep();
 
-    if (gcType == GCWithSweep) {
+    if (gcType == BlinkGC::GCWithSweep) {
         setGCState(EagerSweepScheduled);
-    } else if (gcType == GCWithoutSweep) {
+    } else if (gcType == BlinkGC::GCWithoutSweep) {
         setGCState(LazySweepScheduled);
     } else {
         takeSnapshot(SnapshotType::HeapSnapshot);
@@ -1108,7 +1103,7 @@
     invokePreFinalizers();
 
 #if defined(ADDRESS_SANITIZER)
-    poisonEagerHeap(SetPoison);
+    poisonEagerHeap(BlinkGC::SetPoison);
 #endif
 
     eagerSweep();
@@ -1134,18 +1129,18 @@
     // TODO(Oilpan): enable the poisoning always.
 #if ENABLE(OILPAN)
     // Unpoison the live objects remaining in the eager heaps..
-    poisonEagerHeap(ClearPoison);
+    poisonEagerHeap(BlinkGC::ClearPoison);
     // ..along with poisoning all unmarked objects in the other heaps.
-    for (int i = 1; i < NumberOfHeaps; i++)
-        m_heaps[i]->poisonHeap(UnmarkedOnly, SetPoison);
+    for (int i = 1; i < BlinkGC::NumberOfHeaps; i++)
+        m_heaps[i]->poisonHeap(BlinkGC::UnmarkedOnly, BlinkGC::SetPoison);
 #endif
 }
 
-void ThreadState::poisonEagerHeap(Poisoning poisoning)
+void ThreadState::poisonEagerHeap(BlinkGC::Poisoning poisoning)
 {
     // TODO(Oilpan): enable the poisoning always.
 #if ENABLE(OILPAN)
-    m_heaps[EagerSweepHeapIndex]->poisonHeap(MarkedAndUnmarked, poisoning);
+    m_heaps[BlinkGC::EagerSweepHeapIndex]->poisonHeap(BlinkGC::MarkedAndUnmarked, poisoning);
 #endif
 }
 #endif
@@ -1167,7 +1162,7 @@
         if (isMainThread())
             ScriptForbiddenScope::enter();
 
-        m_heaps[EagerSweepHeapIndex]->completeSweep();
+        m_heaps[BlinkGC::EagerSweepHeapIndex]->completeSweep();
 
         if (isMainThread())
             ScriptForbiddenScope::exit();
@@ -1195,8 +1190,8 @@
         TRACE_EVENT0("blink_gc", "ThreadState::completeSweep");
         double timeStamp = WTF::currentTimeMS();
 
-        static_assert(EagerSweepHeapIndex == 0, "Eagerly swept heaps must be processed first.");
-        for (int i = 0; i < NumberOfHeaps; i++)
+        static_assert(BlinkGC::EagerSweepHeapIndex == 0, "Eagerly swept heaps must be processed first.");
+        for (int i = 0; i < BlinkGC::NumberOfHeaps; i++)
             m_heaps[i]->completeSweep();
 
         Platform::current()->histogramCustomCounts("BlinkGC.CompleteSweep", WTF::currentTimeMS() - timeStamp, 0, 10 * 1000, 50);
@@ -1247,14 +1242,14 @@
 void ThreadState::prepareForThreadStateTermination()
 {
     ASSERT(checkThread());
-    for (int i = 0; i < NumberOfHeaps; ++i)
+    for (int i = 0; i < BlinkGC::NumberOfHeaps; ++i)
         m_heaps[i]->prepareHeapForTermination();
 }
 
 #if ENABLE(ASSERT) || ENABLE(GC_PROFILING)
 BasePage* ThreadState::findPageFromAddress(Address address)
 {
-    for (int i = 0; i < NumberOfHeaps; ++i) {
+    for (int i = 0; i < BlinkGC::NumberOfHeaps; ++i) {
         if (BasePage* page = m_heaps[i]->findPageFromAddress(address))
             return page;
     }
@@ -1265,7 +1260,7 @@
 size_t ThreadState::objectPayloadSizeForTesting()
 {
     size_t objectPayloadSize = 0;
-    for (int i = 0; i < NumberOfHeaps; ++i)
+    for (int i = 0; i < BlinkGC::NumberOfHeaps; ++i)
         objectPayloadSize += m_heaps[i]->objectPayloadSizeForTesting();
     return objectPayloadSize;
 }
@@ -1280,7 +1275,7 @@
     s_safePointBarrier->resumeOthers();
 }
 
-void ThreadState::safePoint(StackState stackState)
+void ThreadState::safePoint(BlinkGC::StackState stackState)
 {
     ASSERT(checkThread());
     Heap::reportMemoryUsageForTracing();
@@ -1291,7 +1286,7 @@
     m_atSafePoint = true;
     s_safePointBarrier->checkAndPark(this);
     m_atSafePoint = false;
-    m_stackState = HeapPointersOnStack;
+    m_stackState = BlinkGC::HeapPointersOnStack;
     preSweep();
 }
 
@@ -1320,14 +1315,14 @@
 }
 #endif
 
-void ThreadState::enterSafePoint(StackState stackState, void* scopeMarker)
+void ThreadState::enterSafePoint(BlinkGC::StackState stackState, void* scopeMarker)
 {
     ASSERT(checkThread());
 #ifdef ADDRESS_SANITIZER
-    if (stackState == HeapPointersOnStack)
+    if (stackState == BlinkGC::HeapPointersOnStack)
         scopeMarker = adjustScopeMarkerForAdressSanitizer(scopeMarker);
 #endif
-    ASSERT(stackState == NoHeapPointersOnStack || scopeMarker);
+    ASSERT(stackState == BlinkGC::NoHeapPointersOnStack || scopeMarker);
     runScheduledGC(stackState);
     ASSERT(!m_atSafePoint);
     m_atSafePoint = true;
@@ -1342,14 +1337,14 @@
     ASSERT(m_atSafePoint);
     s_safePointBarrier->leaveSafePoint(this, locker);
     m_atSafePoint = false;
-    m_stackState = HeapPointersOnStack;
+    m_stackState = BlinkGC::HeapPointersOnStack;
     clearSafePointScopeMarker();
     preSweep();
 }
 
 void ThreadState::copyStackUntilSafePointScope()
 {
-    if (!m_safePointScopeMarker || m_stackState == NoHeapPointersOnStack)
+    if (!m_safePointScopeMarker || m_stackState == BlinkGC::NoHeapPointersOnStack)
         return;
 
     Address* to = reinterpret_cast<Address*>(m_safePointScopeMarker);
@@ -1376,7 +1371,7 @@
 void ThreadState::addInterruptor(PassOwnPtr<Interruptor> interruptor)
 {
     ASSERT(checkThread());
-    SafePointScope scope(HeapPointersOnStack);
+    SafePointScope scope(BlinkGC::HeapPointersOnStack);
     {
         MutexLocker locker(threadAttachMutex());
         m_interruptors.append(interruptor);
@@ -1386,7 +1381,7 @@
 void ThreadState::removeInterruptor(Interruptor* interruptor)
 {
     ASSERT(checkThread());
-    SafePointScope scope(HeapPointersOnStack);
+    SafePointScope scope(BlinkGC::HeapPointersOnStack);
     {
         MutexLocker locker(threadAttachMutex());
         size_t index = m_interruptors.find(interruptor);
@@ -1400,7 +1395,7 @@
     ThreadState* state = ThreadState::current();
     ASSERT(state);
     ASSERT(!state->isAtSafePoint());
-    state->safePoint(HeapPointersOnStack);
+    state->safePoint(BlinkGC::HeapPointersOnStack);
 }
 
 ThreadState::AttachedThreadStateSet& ThreadState::attachedThreads()
@@ -1446,7 +1441,7 @@
 
 void ThreadState::clearHeapAges()
 {
-    memset(m_heapAges, 0, sizeof(size_t) * NumberOfHeaps);
+    memset(m_heapAges, 0, sizeof(size_t) * BlinkGC::NumberOfHeaps);
     memset(m_likelyToBePromptlyFreed.get(), 0, sizeof(int) * likelyToBePromptlyFreedArraySize);
     m_currentHeapAges = 0;
 }
@@ -1472,7 +1467,7 @@
     --m_likelyToBePromptlyFreed[entryIndex];
     int heapIndex = m_vectorBackingHeapIndex;
     m_heapAges[heapIndex] = ++m_currentHeapAges;
-    m_vectorBackingHeapIndex = heapIndexOfVectorHeapLeastRecentlyExpanded(Vector1HeapIndex, Vector4HeapIndex);
+    m_vectorBackingHeapIndex = heapIndexOfVectorHeapLeastRecentlyExpanded(BlinkGC::Vector1HeapIndex, BlinkGC::Vector4HeapIndex);
     return m_heaps[heapIndex];
 }
 
@@ -1480,7 +1475,7 @@
 {
     m_heapAges[heapIndex] = ++m_currentHeapAges;
     if (m_vectorBackingHeapIndex == heapIndex)
-        m_vectorBackingHeapIndex = heapIndexOfVectorHeapLeastRecentlyExpanded(Vector1HeapIndex, Vector4HeapIndex);
+        m_vectorBackingHeapIndex = heapIndexOfVectorHeapLeastRecentlyExpanded(BlinkGC::Vector1HeapIndex, BlinkGC::Vector4HeapIndex);
 }
 
 void ThreadState::promptlyFreed(size_t gcInfoIndex)
@@ -1508,10 +1503,10 @@
         numberOfHeapsReported++;                                                               \
         switch (type) {                                                                        \
         case SnapshotType::HeapSnapshot:                                                       \
-            m_heaps[HeapType##HeapIndex]->takeSnapshot(heapsDumpName + "/" #HeapType, info);   \
+            m_heaps[BlinkGC::HeapType##HeapIndex]->takeSnapshot(heapsDumpName + "/" #HeapType, info);   \
             break;                                                                             \
         case SnapshotType::FreelistSnapshot:                                                   \
-            m_heaps[HeapType##HeapIndex]->takeFreelistSnapshot(heapsDumpName + "/" #HeapType); \
+            m_heaps[BlinkGC::HeapType##HeapIndex]->takeFreelistSnapshot(heapsDumpName + "/" #HeapType); \
             break;                                                                             \
         default:                                                                               \
             ASSERT_NOT_REACHED();                                                              \
@@ -1532,7 +1527,7 @@
     SNAPSHOT_HEAP(LargeObject);
     FOR_EACH_TYPED_HEAP(SNAPSHOT_HEAP);
 
-    ASSERT(numberOfHeapsReported == NumberOfHeaps);
+    ASSERT(numberOfHeapsReported == BlinkGC::NumberOfHeaps);
 
 #undef SNAPSHOT_HEAP
 
@@ -1613,7 +1608,7 @@
     {                                                          \
         json->beginDictionary();                               \
         json->setString("name", #HeapType);                    \
-        m_heaps[HeapType##HeapIndex]->snapshotFreeList(*json); \
+        m_heaps[BlinkGC::HeapType##HeapIndex]->snapshotFreeList(*json); \
         json->endDictionary();                                 \
     }
 
@@ -1644,12 +1639,12 @@
         return;
 
     ClassAgeCountsMap markingClassAgeCounts;
-    for (int i = 0; i < NumberOfHeaps; ++i)
+    for (int i = 0; i < BlinkGC::NumberOfHeaps; ++i)
         m_heaps[i]->countMarkedObjects(markingClassAgeCounts);
     reportMarkSweepStats("MarkingStats", markingClassAgeCounts);
 
     ClassAgeCountsMap sweepingClassAgeCounts;
-    for (int i = 0; i < NumberOfHeaps; ++i)
+    for (int i = 0; i < BlinkGC::NumberOfHeaps; ++i)
         m_heaps[i]->countObjectsToSweep(sweepingClassAgeCounts);
     reportMarkSweepStats("SweepingStats", sweepingClassAgeCounts);
 }
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.h b/third_party/WebKit/Source/platform/heap/ThreadState.h
index e740dd6..9bcef40 100644
--- a/third_party/WebKit/Source/platform/heap/ThreadState.h
+++ b/third_party/WebKit/Source/platform/heap/ThreadState.h
@@ -32,6 +32,7 @@
 #define ThreadState_h
 
 #include "platform/PlatformExport.h"
+#include "platform/heap/BlinkGC.h"
 #include "platform/heap/ThreadingTraits.h"
 #include "public/platform/WebThread.h"
 #include "wtf/AddressSanitizer.h"
@@ -50,8 +51,6 @@
 
 namespace blink {
 
-#define PRINT_HEAP_STATS 0 // Enable this macro to print heap stats to stderr.
-
 class BasePage;
 class CallbackStack;
 class CrossThreadPersistentRegion;
@@ -65,15 +64,6 @@
 class ThreadState;
 class Visitor;
 
-using Address = uint8_t*;
-
-using FinalizationCallback = void (*)(void*);
-using VisitorCallback = void (*)(Visitor*, void* self);
-using TraceCallback = VisitorCallback;
-using WeakCallback = VisitorCallback;
-using EphemeronCallback = VisitorCallback;
-using PreFinalizerCallback = bool(*)(void*);
-
 // Declare that a class has a pre-finalizer. The pre-finalizer is called
 // before any object gets swept, so it is safe to touch on-heap objects
 // that may be collected in the same GC cycle. If you cannot avoid touching
@@ -129,17 +119,6 @@
 #define WILL_BE_USING_PRE_FINALIZER(Class, method)
 #endif
 
-// List of typed heaps. The list is used to generate the implementation
-// of typed heap related methods.
-//
-// To create a new typed heap add a H(<ClassName>) to the
-// FOR_EACH_TYPED_HEAP macro below.
-#define FOR_EACH_TYPED_HEAP(H)              \
-    H(Node)                                 \
-    H(CSSValue)
-
-#define TypedHeapEnumName(Type) Type##HeapIndex,
-
 #if ENABLE(GC_PROFILING)
 const size_t numberOfGenerationsToTrack = 8;
 const size_t maxHeapObjectAge = numberOfGenerationsToTrack - 1;
@@ -156,31 +135,6 @@
 public:
     typedef std::pair<void*, PreFinalizerCallback> PreFinalizer;
 
-    // When garbage collecting we need to know whether or not there
-    // can be pointers to Blink GC managed objects on the stack for
-    // each thread. When threads reach a safe point they record
-    // whether or not they have pointers on the stack.
-    enum StackState {
-        NoHeapPointersOnStack,
-        HeapPointersOnStack
-    };
-
-    enum GCType {
-        // Both of the marking task and the sweeping task run in
-        // Heap::collectGarbage().
-        GCWithSweep,
-        // Only the marking task runs in Heap::collectGarbage().
-        // The sweeping task is split into chunks and scheduled lazily.
-        GCWithoutSweep,
-        // Only the marking task runs just to take a heap snapshot.
-        // The sweeping task doesn't run. The marks added in the marking task
-        // are just cleared.
-        TakeSnapshot,
-        // The marking task does not mark objects outside the heap of the GCing
-        // thread.
-        ThreadTerminationGC,
-    };
-
     // See setGCState() for possible state transitions.
     enum GCState {
         NoGCScheduled,
@@ -196,43 +150,6 @@
         SweepingAndPreciseGCScheduled,
     };
 
-    enum HeapIndices {
-        EagerSweepHeapIndex = 0,
-        NormalPage1HeapIndex,
-        NormalPage2HeapIndex,
-        NormalPage3HeapIndex,
-        NormalPage4HeapIndex,
-        Vector1HeapIndex,
-        Vector2HeapIndex,
-        Vector3HeapIndex,
-        Vector4HeapIndex,
-        InlineVectorHeapIndex,
-        HashTableHeapIndex,
-        FOR_EACH_TYPED_HEAP(TypedHeapEnumName)
-        LargeObjectHeapIndex,
-        // Values used for iteration of heap segments.
-        NumberOfHeaps,
-    };
-
-#if defined(ADDRESS_SANITIZER)
-    // Heaps can have their object payloads be poisoned, or cleared
-    // of their poisoning.
-    enum Poisoning {
-        SetPoison,
-        ClearPoison,
-    };
-
-    enum ObjectsToPoison {
-        UnmarkedOnly,
-        MarkedAndUnmarked,
-    };
-#endif
-
-    enum V8GCType {
-        V8MinorGC,
-        V8MajorGC,
-    };
-
     // The NoAllocationScope class is used in debug mode to catch unwanted
     // allocations. E.g. allocations during GC.
     class NoAllocationScope final {
@@ -335,13 +252,13 @@
     void scheduleIdleGC();
     void scheduleIdleLazySweep();
     void schedulePreciseGC();
-    void scheduleV8FollowupGCIfNeeded(V8GCType);
+    void scheduleV8FollowupGCIfNeeded(BlinkGC::V8GCType);
     void schedulePageNavigationGCIfNeeded(float estimatedRemovalRatio);
     void schedulePageNavigationGC();
     void scheduleGCIfNeeded();
     void willStartV8GC();
     void setGCState(GCState);
-    GCState gcState() const;
+    GCState gcState() const { return m_gcState; }
     bool isInGC() const { return gcState() == GCRunning; }
     bool isSweepingInProgress() const
     {
@@ -372,7 +289,7 @@
     //   and it marks all not-yet-swept objets as dead.
     void makeConsistentForGC();
     void preGC();
-    void postGC(GCType);
+    void postGC(BlinkGC::GCType);
     void preSweep();
     void completeSweep();
     void postSweep();
@@ -426,10 +343,10 @@
 
     // Check if GC is requested by another thread and pause this thread if this is the case.
     // Can only be called when current thread is in a consistent state.
-    void safePoint(StackState);
+    void safePoint(BlinkGC::StackState);
 
     // Mark current thread as running inside safepoint.
-    void enterSafePoint(StackState, void*);
+    void enterSafePoint(BlinkGC::StackState, void*);
     void leaveSafePoint(SafePointAwareMutexLocker* = nullptr);
     bool isAtSafePoint() const { return m_atSafePoint; }
 
@@ -469,7 +386,7 @@
     BaseHeap* heap(int heapIndex) const
     {
         ASSERT(0 <= heapIndex);
-        ASSERT(heapIndex < NumberOfHeaps);
+        ASSERT(heapIndex < BlinkGC::NumberOfHeaps);
         return m_heaps[heapIndex];
     }
 
@@ -646,7 +563,7 @@
         // since the last GC.
         if (m_likelyToBePromptlyFreed[entryIndex] > 0) {
             m_heapAges[heapIndex] = ++m_currentHeapAges;
-            m_vectorBackingHeapIndex = heapIndexOfVectorHeapLeastRecentlyExpanded(Vector1HeapIndex, Vector4HeapIndex);
+            m_vectorBackingHeapIndex = heapIndexOfVectorHeapLeastRecentlyExpanded(BlinkGC::Vector1HeapIndex, BlinkGC::Vector4HeapIndex);
         }
         ASSERT(isVectorHeapIndex(heapIndex));
         return m_heaps[heapIndex];
@@ -654,7 +571,7 @@
     BaseHeap* expandedVectorBackingHeap(size_t gcInfoIndex);
     static bool isVectorHeapIndex(int heapIndex)
     {
-        return Vector1HeapIndex <= heapIndex && heapIndex <= Vector4HeapIndex;
+        return BlinkGC::Vector1HeapIndex <= heapIndex && heapIndex <= BlinkGC::Vector4HeapIndex;
     }
     void allocationPointAdjusted(int heapIndex);
     void promptlyFreed(size_t gcInfoIndex);
@@ -710,12 +627,12 @@
     double partitionAllocGrowingRate();
     bool judgeGCThreshold(size_t allocatedObjectSizeThreshold, double heapGrowingRateThreshold);
 
-    void runScheduledGC(StackState);
+    void runScheduledGC(BlinkGC::StackState);
 
     void eagerSweep();
 
 #if defined(ADDRESS_SANITIZER)
-    void poisonEagerHeap(Poisoning);
+    void poisonEagerHeap(BlinkGC::Poisoning);
     void poisonAllHeaps();
 #endif
 
@@ -765,7 +682,7 @@
 
     ThreadIdentifier m_thread;
     OwnPtr<PersistentRegion> m_persistentRegion;
-    StackState m_stackState;
+    BlinkGC::StackState m_stackState;
     intptr_t* m_startOfStack;
     intptr_t* m_endOfStack;
     void* m_safePointScopeMarker;
@@ -775,10 +692,10 @@
     bool m_sweepForbidden;
     size_t m_noAllocationCount;
     size_t m_gcForbiddenCount;
-    BaseHeap* m_heaps[NumberOfHeaps];
+    BaseHeap* m_heaps[BlinkGC::NumberOfHeaps];
 
     int m_vectorBackingHeapIndex;
-    size_t m_heapAges[NumberOfHeaps];
+    size_t m_heapAges[BlinkGC::NumberOfHeaps];
     size_t m_currentHeapAges;
 
     bool m_isTerminating;
diff --git a/third_party/WebKit/Source/platform/heap/blink_heap.gypi b/third_party/WebKit/Source/platform/heap/blink_heap.gypi
index b099040..211d5c7 100644
--- a/third_party/WebKit/Source/platform/heap/blink_heap.gypi
+++ b/third_party/WebKit/Source/platform/heap/blink_heap.gypi
@@ -31,6 +31,7 @@
 {
   'variables': {
     'platform_heap_files': [
+      'BlinkGC.h',
       'BlinkGCMemoryDumpProvider.cpp',
       'BlinkGCMemoryDumpProvider.h',
       'CallbackStack.cpp',
@@ -48,9 +49,11 @@
       'InlinedGlobalMarkingVisitor.h',
       'MarkingVisitor.h',
       'MarkingVisitorImpl.h',
+      'MessageLoopInterruptor.h',
       'PageMemory.h',
       'PagePool.cpp',
       'PagePool.h',
+      'PendingGCRunner.h',
       'PersistentNode.cpp',
       'PersistentNode.h',
       'SafePoint.cpp',
diff --git a/third_party/WebKit/Source/web/WebHeap.cpp b/third_party/WebKit/Source/web/WebHeap.cpp
index 9556cd8d..257cef8e4 100644
--- a/third_party/WebKit/Source/web/WebHeap.cpp
+++ b/third_party/WebKit/Source/web/WebHeap.cpp
@@ -38,7 +38,7 @@
 WebHeap::SafePointScope::SafePointScope()
 {
     RELEASE_ASSERT(!ThreadState::current()->isAtSafePoint());
-    ThreadState::current()->enterSafePoint(ThreadState::HeapPointersOnStack, this);
+    ThreadState::current()->enterSafePoint(BlinkGC::HeapPointersOnStack, this);
 }
 
 WebHeap::SafePointScope::~SafePointScope()
@@ -48,7 +48,7 @@
 
 void WebHeap::collectGarbageForTesting()
 {
-    Heap::collectGarbage(ThreadState::HeapPointersOnStack, ThreadState::GCWithSweep, Heap::ForcedGC);
+    Heap::collectGarbage(BlinkGC::HeapPointersOnStack, BlinkGC::GCWithSweep, Heap::ForcedGC);
 }
 
 void WebHeap::collectAllGarbageForTesting()
diff --git a/third_party/WebKit/Source/web/WebKit.cpp b/third_party/WebKit/Source/web/WebKit.cpp
index 1a0ef8b..1a8baf7 100644
--- a/third_party/WebKit/Source/web/WebKit.cpp
+++ b/third_party/WebKit/Source/web/WebKit.cpp
@@ -48,8 +48,8 @@
 #include "platform/RuntimeEnabledFeatures.h"
 #include "platform/graphics/ImageDecodingStore.h"
 #include "platform/heap/Heap.h"
-#include "platform/heap/glue/MessageLoopInterruptor.h"
-#include "platform/heap/glue/PendingGCRunner.h"
+#include "platform/heap/MessageLoopInterruptor.h"
+#include "platform/heap/PendingGCRunner.h"
 #include "public/platform/Platform.h"
 #include "public/platform/WebPrerenderingSupport.h"
 #include "public/platform/WebThread.h"
diff --git a/third_party/WebKit/Source/wtf/HashSetTest.cpp b/third_party/WebKit/Source/wtf/HashSetTest.cpp
index f32fd800..da77dcc 100644
--- a/third_party/WebKit/Source/wtf/HashSetTest.cpp
+++ b/third_party/WebKit/Source/wtf/HashSetTest.cpp
@@ -46,7 +46,7 @@
     const unsigned initialCapacity = HashTableCapacityForSize<size>::value;
     HashSet<int, DefaultHash<int>::Hash, InitialCapacityTestHashTraits<initialCapacity>> testSet;
 
-    // Initial capacity is null.
+    // Initial capacity is zero.
     EXPECT_EQ(0UL, testSet.capacity());
 
     // Adding items up to size should never change the capacity.
@@ -62,7 +62,7 @@
         EXPECT_EQ(initialCapacity, testSet.capacity());
     }
 
-    // Adding one more item increase the capacity.
+    // Adding one more item increases the capacity.
     testSet.add(initialCapacity);
     EXPECT_GT(testSet.capacity(), initialCapacity);
 }
@@ -87,34 +87,33 @@
 template<unsigned size> void testReserveCapacity()
 {
     HashSet<int> testSet;
-    HashSet<int> sampleSet;
-    for (size_t i = 0; i < size; ++i) {
-        sampleSet.add(i + 1); // Avoid adding '0'.
-    }
-    const unsigned expectedInitialCapacity = sampleSet.capacity();
 
-    // Initial capacity is null.
+    // Initial capacity is zero.
     EXPECT_EQ(0UL, testSet.capacity());
 
     testSet.reserveCapacityForSize(size);
-    EXPECT_EQ(expectedInitialCapacity, testSet.capacity());
+    const unsigned initialCapacity = testSet.capacity();
+    const unsigned minimumTableSize = HashTraits<int>::minimumTableSize;
+
+    // reserveCapacityForSize should respect minimumTableSize.
+    EXPECT_GE(initialCapacity, minimumTableSize);
 
     // Adding items up to size should never change the capacity.
     for (size_t i = 0; i < size; ++i) {
         testSet.add(i + 1); // Avoid adding '0'.
-        EXPECT_EQ(expectedInitialCapacity, testSet.capacity());
+        EXPECT_EQ(initialCapacity, testSet.capacity());
     }
 
     // Adding items up to less than half the capacity should not change the capacity.
-    unsigned capacityLimit = expectedInitialCapacity / 2 - 1;
+    unsigned capacityLimit = initialCapacity / 2 - 1;
     for (size_t i = size; i < capacityLimit; ++i) {
         testSet.add(i + 1);
-        EXPECT_EQ(expectedInitialCapacity, testSet.capacity());
+        EXPECT_EQ(initialCapacity, testSet.capacity());
     }
 
-    // Adding one more item increase the capacity.
-    testSet.add(expectedInitialCapacity);
-    EXPECT_GT(testSet.capacity(), expectedInitialCapacity);
+    // Adding one more item increases the capacity.
+    testSet.add(capacityLimit + 1);
+    EXPECT_GT(testSet.capacity(), initialCapacity);
 
     testReserveCapacity<size-1>();
 }
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index cf7be26..38d7916 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -2068,6 +2068,9 @@
 </histogram>
 
 <histogram name="Autofill.AutomaticProfileCreation" enum="BooleanCreated">
+  <obsolete>
+    Deprecated as of 6/2015, replaced by Autofill.ProfileActionOnFormSubmitted.
+  </obsolete>
   <owner>sebsg@chromium.org</owner>
   <summary>
     Whether a new Autofill profile was created automatically. In the
@@ -2346,6 +2349,14 @@
   </summary>
 </histogram>
 
+<histogram name="Autofill.ProfileActionOnFormSubmitted"
+    enum="AutofillProfileAction">
+  <owner>sebsg@chromium.org</owner>
+  <summary>
+    The profile action that took place when a form was submitted.
+  </summary>
+</histogram>
+
 <histogram name="AutoFill.ProfileCount">
   <obsolete>
     Deprecated as of 3/2011, replaced by Autofill.StoredProfileCount.
@@ -52929,6 +52940,12 @@
   <int value="1" label="Selected popup entry"/>
 </enum>
 
+<enum name="AutofillProfileAction" type="int">
+  <int value="0" label="Existing profile used"/>
+  <int value="1" label="Existing profile updated"/>
+  <int value="2" label="New profile created"/>
+</enum>
+
 <enum name="AutofillQuality" type="int">
   <int value="0" label="Submitted"/>
   <int value="1" label="Autofilled"/>
diff --git a/tools/perf/benchmarks/benchmark_smoke_unittest.py b/tools/perf/benchmarks/benchmark_smoke_unittest.py
index 4b83e957..e8e7bd9c 100644
--- a/tools/perf/benchmarks/benchmark_smoke_unittest.py
+++ b/tools/perf/benchmarks/benchmark_smoke_unittest.py
@@ -23,6 +23,7 @@
 from benchmarks import jetstream
 from benchmarks import kraken
 from benchmarks import memory
+from benchmarks import new_tab
 from benchmarks import octane
 from benchmarks import rasterize_and_record_micro
 from benchmarks import repaint
@@ -78,6 +79,7 @@
 _BLACK_LIST_TEST_MODULES = {
     image_decoding, # Always fails on Mac10.9 Tests builder.
     indexeddb_perf,  # Always fails on Win7 & Android Tests builder.
+    new_tab,  # Fails fairly often on the Linux Tests builder, crbug.com/535664
     octane,  # Often fails & take long time to timeout on cq bot.
     rasterize_and_record_micro,  # Always fails on cq bot.
     repaint,  # Often fails & takes long time to timeout on cq bot.
diff --git a/tools/perf/benchmarks/ct_benchmarks_unittest.py b/tools/perf/benchmarks/ct_benchmarks_unittest.py
new file mode 100644
index 0000000..40c55d2a
--- /dev/null
+++ b/tools/perf/benchmarks/ct_benchmarks_unittest.py
@@ -0,0 +1,115 @@
+# Copyright 2015 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.
+
+from optparse import OptionParser
+import unittest
+
+from telemetry.page import shared_page_state
+
+from benchmarks import rasterize_and_record_micro
+from benchmarks import repaint
+from benchmarks import skpicture_printer
+
+
+class MockErrorParser(object):
+  def __init__(self):
+    self.err_msg = None
+
+  def error(self, err_msg):
+    self.err_msg = err_msg
+
+
+class CTBenchmarks(unittest.TestCase):
+
+  def setUp(self):
+    self.ct_benchmarks = [
+        rasterize_and_record_micro.RasterizeAndRecordMicroCT(),
+        repaint.RepaintCT(),
+        skpicture_printer.SkpicturePrinterCT(),
+    ]
+    self.shared_page_state_class = shared_page_state.SharedMobilePageState
+    self.archive_data_file = '/b/test'
+    self.urls_list = 'http://test1.com,http://test2.com,http://test3.net'
+    self.mock_parser = MockErrorParser()
+
+  def testCTBenchmarks(self):
+    for benchmark in self.ct_benchmarks:
+      parser = OptionParser()
+      parser.user_agent = 'mobile'
+      parser.archive_data_file = self.archive_data_file
+      parser.urls_list = self.urls_list
+
+      benchmark.AddBenchmarkCommandLineArgs(parser)
+      benchmark.ProcessCommandLineArgs(None, parser)
+      ct_page_set = benchmark.CreateStorySet(parser)
+
+      self.assertEquals(
+          len(self.urls_list.split(',')), len(ct_page_set.stories))
+      self.assertEquals(
+          self.archive_data_file, ct_page_set.archive_data_file)
+      for i in range(len(self.urls_list.split(','))):
+        url = self.urls_list.split(',')[i]
+        story = ct_page_set.stories[i]
+        self.assertEquals(url, story.url)
+        self.assertEquals(
+            self.shared_page_state_class, story.shared_state_class)
+        self.assertEquals(self.archive_data_file, story.archive_data_file)
+
+  def testCTBenchmarks_wrongAgent(self):
+    for benchmark in self.ct_benchmarks:
+      parser = OptionParser()
+      parser.user_agent = 'mobileeeeee'
+      parser.archive_data_file = self.archive_data_file
+      parser.urls_list = self.urls_list
+
+      benchmark.AddBenchmarkCommandLineArgs(parser)
+      benchmark.ProcessCommandLineArgs(None, parser)
+      try:
+        benchmark.CreateStorySet(parser)
+        self.fail('Expected ValueError')
+      except ValueError, e:
+        self.assertEquals('user_agent mobileeeeee is unrecognized', e.message)
+
+  def testCTBenchmarks_missingDataFile(self):
+    for benchmark in self.ct_benchmarks:
+      parser = OptionParser()
+      parser.user_agent = 'mobile'
+      parser.urls_list = self.urls_list
+      benchmark.AddBenchmarkCommandLineArgs(parser)
+
+      # Should fail due to missing archive_data_file.
+      try:
+        benchmark.ProcessCommandLineArgs(None, parser)
+        self.fail('Expected AttributeError')
+      except AttributeError, e:
+        self.assertEquals(
+            'OptionParser instance has no attribute \'archive_data_file\'',
+            e.message)
+
+      # Now add an empty archive_data_file.
+      parser.archive_data_file = ''
+      benchmark.ProcessCommandLineArgs(self.mock_parser, parser)
+      self.assertEquals(
+          'Please specify --archive_data_file.', self.mock_parser.err_msg)
+
+  def testCTBenchmarks_missingUrlsList(self):
+    for benchmark in self.ct_benchmarks:
+      parser = OptionParser()
+      parser.user_agent = 'mobile'
+      parser.archive_data_file = self.archive_data_file
+      benchmark.AddBenchmarkCommandLineArgs(parser)
+
+      # Should fail due to missing urls_list.
+      try:
+        benchmark.ProcessCommandLineArgs(None, parser)
+        self.fail('Expected AttributeError')
+      except AttributeError, e:
+        self.assertEquals(
+            'OptionParser instance has no attribute \'urls_list\'',
+            e.message)
+
+      # Now add an empty urls_list.
+      parser.urls_list = ''
+      benchmark.ProcessCommandLineArgs(self.mock_parser, parser)
+      self.assertEquals('Please specify --urls_list.', self.mock_parser.err_msg)
diff --git a/tools/perf/benchmarks/rasterize_and_record_micro.py b/tools/perf/benchmarks/rasterize_and_record_micro.py
index 9a5abab..75e95410 100644
--- a/tools/perf/benchmarks/rasterize_and_record_micro.py
+++ b/tools/perf/benchmarks/rasterize_and_record_micro.py
@@ -4,6 +4,7 @@
 
 from core import perf_benchmark
 
+import ct_benchmarks_util
 from measurements import rasterize_and_record_micro
 import page_sets
 from telemetry import benchmark
@@ -95,3 +96,27 @@
 
   def CreateStorySet(self, options):
     return page_sets.PolymerPageSet(run_no_page_interactions=True)
+
+
+# Disabled because we do not plan on running CT benchmarks on the perf
+# waterfall any time soon.
+@benchmark.Disabled
+class RasterizeAndRecordMicroCT(_RasterizeAndRecordMicro):
+  """Measures rasterize and record performance for Cluster Telemetry."""
+
+  @classmethod
+  def Name(cls):
+    return 'rasterize_and_record_micro_ct'
+
+  @classmethod
+  def AddBenchmarkCommandLineArgs(cls, parser):
+    _RasterizeAndRecordMicro.AddBenchmarkCommandLineArgs(parser)
+    ct_benchmarks_util.AddBenchmarkCommandLineArgs(parser)
+
+  @classmethod
+  def ProcessCommandLineArgs(cls, parser, args):
+    ct_benchmarks_util.ValidateCommandLineArgs(parser, args)
+
+  def CreateStorySet(self, options):
+    return page_sets.CTPageSet(
+        options.urls_list, options.user_agent, options.archive_data_file)
diff --git a/tools/perf/benchmarks/repaint.py b/tools/perf/benchmarks/repaint.py
index 2293c04..569d381 100644
--- a/tools/perf/benchmarks/repaint.py
+++ b/tools/perf/benchmarks/repaint.py
@@ -5,6 +5,7 @@
 from core import perf_benchmark
 
 from benchmarks import silk_flags
+import ct_benchmarks_util
 from measurements import smoothness
 import page_sets
 from telemetry import benchmark
@@ -64,3 +65,26 @@
   def Name(cls):
     return 'repaint.gpu_rasterization.key_mobile_sites_repaint'
 
+
+# Disabled because we do not plan on running CT benchmarks on the perf
+# waterfall any time soon.
+@benchmark.Disabled
+class RepaintCT(_Repaint):
+  """Measures repaint performance for Cluster Telemetry."""
+
+  @classmethod
+  def Name(cls):
+    return 'repaint_ct'
+
+  @classmethod
+  def AddBenchmarkCommandLineArgs(cls, parser):
+    _Repaint.AddBenchmarkCommandLineArgs(parser)
+    ct_benchmarks_util.AddBenchmarkCommandLineArgs(parser)
+
+  @classmethod
+  def ProcessCommandLineArgs(cls, parser, args):
+    ct_benchmarks_util.ValidateCommandLineArgs(parser, args)
+
+  def CreateStorySet(self, options):
+    return page_sets.CTPageSet(
+        options.urls_list, options.user_agent, options.archive_data_file)
diff --git a/tools/perf/benchmarks/skpicture_printer.py b/tools/perf/benchmarks/skpicture_printer.py
index 0247320f..3ba8834 100644
--- a/tools/perf/benchmarks/skpicture_printer.py
+++ b/tools/perf/benchmarks/skpicture_printer.py
@@ -4,6 +4,8 @@
 
 from core import perf_benchmark
 
+import ct_benchmarks_util
+import page_sets
 from telemetry import benchmark
 from telemetry.core import discover
 from telemetry import story
@@ -48,3 +50,32 @@
     story_set_class = _MatchPageSetName(options.page_set_name,
                                         options.page_set_base_dir)
     return story_set_class()
+
+
+# Disabled because we do not plan on running CT benchmarks on the perf
+# waterfall any time soon.
+@benchmark.Disabled
+class SkpicturePrinterCT(perf_benchmark.PerfBenchmark):
+  """Captures SKPs for Cluster Telemetry."""
+
+  @classmethod
+  def Name(cls):
+    return 'skpicture_printer_ct'
+
+  @classmethod
+  def AddBenchmarkCommandLineArgs(cls, parser):
+    ct_benchmarks_util.AddBenchmarkCommandLineArgs(parser)
+    parser.add_option('-s', '--skp-outdir',
+                      default=None,
+                      help='Output directory for the SKP files')
+
+  @classmethod
+  def ProcessCommandLineArgs(cls, parser, args):
+    ct_benchmarks_util.ValidateCommandLineArgs(parser, args)
+
+  def CreatePageTest(self, options):
+    return skpicture_printer.SkpicturePrinter(options.skp_outdir)
+
+  def CreateStorySet(self, options):
+    return page_sets.CTPageSet(
+        options.urls_list, options.user_agent, options.archive_data_file)
diff --git a/tools/perf/core/__init__.py b/tools/perf/core/__init__.py
index 50b23df..e967a35 100644
--- a/tools/perf/core/__init__.py
+++ b/tools/perf/core/__init__.py
@@ -1,3 +1,8 @@
 # Copyright 2015 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.
+import sys
+
+from core import path_util
+
+sys.path.append(path_util.GetTelemetryDir())
diff --git a/tools/perf/core/benchmark_finders.py b/tools/perf/core/benchmark_finders.py
new file mode 100644
index 0000000..ac800751
--- /dev/null
+++ b/tools/perf/core/benchmark_finders.py
@@ -0,0 +1,39 @@
+# Copyright 2015 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.
+import imp
+import inspect
+import os
+import sys
+
+from core import perf_benchmark
+
+
+def GetClassFilePath(clazz):
+  """ Return the absolute file path to |clazz|. """
+  assert inspect.isclass(clazz)
+  path = os.path.abspath(inspect.getfile(clazz))
+  if path.endswith('.pyc'):
+    return path[:-1]
+  return path
+
+
+def GetBenchmarkNamesForFile(top_level_dir, benchmark_file_dir):
+  """  Return the list of all benchmark names of benchmarks defined in
+    |benchmark_file_dir|.
+  """
+  original_sys_path = sys.path[:]
+  top_level_dir = os.path.abspath(top_level_dir)
+  original_sys_path = sys.path[:]
+  if top_level_dir not in sys.path:
+    sys.path.append(top_level_dir)
+  try:
+    module = imp.load_source('_tmp_module_name_', benchmark_file_dir)
+    benchmark_names = []
+    for _, obj in inspect.getmembers(module):
+      if (inspect.isclass(obj) and issubclass(obj, perf_benchmark.PerfBenchmark)
+         and GetClassFilePath(obj) == benchmark_file_dir):
+        benchmark_names.append(obj.Name())
+    return sorted(benchmark_names)
+  finally:
+    sys.path = original_sys_path
diff --git a/tools/perf/core/benchmark_finders_unittest.py b/tools/perf/core/benchmark_finders_unittest.py
new file mode 100644
index 0000000..54e5cbe
--- /dev/null
+++ b/tools/perf/core/benchmark_finders_unittest.py
@@ -0,0 +1,28 @@
+# Copyright 2015 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.
+import os
+import unittest
+
+from core import benchmark_finders
+
+
+class TestGetBenchmarkNamesForFile(unittest.TestCase):
+  def setUp(self):
+    self.top_level_dir = os.path.abspath(
+        os.path.join(os.path.dirname(__file__), 'test_data'))
+
+  def testListSimpleBenchmarksDefinedInOneFile(self):
+    self.assertEquals(
+        benchmark_finders.GetBenchmarkNamesForFile(self.top_level_dir,
+            os.path.join(self.top_level_dir, 'simple_benchmarks_case.py')),
+      ['test_benchmark_1', 'test_benchmark_2', 'test_benchmark_subclass_1',
+       'test_benchmark_subclass_2'])
+
+  def testListSimpleBenchmarksDefinedInOneFile(self):
+    self.assertEquals(
+        benchmark_finders.GetBenchmarkNamesForFile(self.top_level_dir,
+            os.path.join(self.top_level_dir, 'complex_benchmarks_case.py')),
+      ['test_benchmark_complex_1',
+       'test_benchmark_complex_subclass',
+       'test_benchmark_complex_subclass_from_other_module'])
diff --git a/tools/perf/core/test_data/complex_benchmarks_case.py b/tools/perf/core/test_data/complex_benchmarks_case.py
new file mode 100644
index 0000000..14236819
--- /dev/null
+++ b/tools/perf/core/test_data/complex_benchmarks_case.py
@@ -0,0 +1,27 @@
+# Copyright 2015 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.
+
+
+from core import perf_benchmark
+import simple_benchmarks_case
+
+
+class TestBenchmarkComplexFoo(perf_benchmark.PerfBenchmark):
+  @classmethod
+  def Name(cls):
+    return 'test_benchmark_complex_1'
+
+
+class TestBenchmarkComplexSubclass(TestBenchmarkComplexFoo):
+  @classmethod
+  def Name(cls):
+    return 'test_benchmark_complex_subclass'
+
+
+class TestBenchmarkComplexBar(simple_benchmarks_case.TestBenchmarkSubclassBar):
+  @classmethod
+  def Name(cls):
+    return 'test_benchmark_complex_subclass_from_other_module'
+
+
diff --git a/tools/perf/core/test_data/simple_benchmarks_case.py b/tools/perf/core/test_data/simple_benchmarks_case.py
new file mode 100644
index 0000000..26d2283b
--- /dev/null
+++ b/tools/perf/core/test_data/simple_benchmarks_case.py
@@ -0,0 +1,27 @@
+# Copyright 2015 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.
+
+from core import perf_benchmark
+
+class _TestBenchmarkFoo(perf_benchmark.PerfBenchmark):
+  @classmethod
+  def Name(cls):
+    return 'test_benchmark_1'
+
+class TestBenchmarkBar(perf_benchmark.PerfBenchmark):
+  @classmethod
+  def Name(cls):
+    return 'test_benchmark_2'
+
+
+class TestBenchmarkSubclassBar(_TestBenchmarkFoo):
+  @classmethod
+  def Name(cls):
+    return 'test_benchmark_subclass_1'
+
+
+class TestBenchmarkSubclassFoo(TestBenchmarkBar):
+  @classmethod
+  def Name(cls):
+    return 'test_benchmark_subclass_2'
diff --git a/tools/perf/ct_benchmarks_util.py b/tools/perf/ct_benchmarks_util.py
new file mode 100755
index 0000000..d82a8bfa
--- /dev/null
+++ b/tools/perf/ct_benchmarks_util.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+# Copyright (c) 2015 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.
+
+
+def AddBenchmarkCommandLineArgs(parser):
+  parser.add_option('--user-agent',  action='store', type='string',
+                    default=None, help='Options are mobile and desktop.')
+  parser.add_option('--archive-data-file',  action='store', type='string',
+                    default=None,
+                    help='The location of the WPR JSON archive file.')
+  parser.add_option('--urls-list',  action='store', type='string',
+                    default=None,
+                    help='This is a comma separated list of urls. '
+                         'Eg: http://www.google.com,http://www.gmail.com')
+
+
+def ValidateCommandLineArgs(parser, args):
+  if not args.user_agent:
+    parser.error('Please specify --user_agent.')
+  if not args.archive_data_file:
+    parser.error('Please specify --archive_data_file.')
+  if not args.urls_list:
+    parser.error('Please specify --urls_list.')
diff --git a/tools/perf/list_affected_benchmarks b/tools/perf/list_affected_benchmarks
new file mode 100755
index 0000000..63dbc80
--- /dev/null
+++ b/tools/perf/list_affected_benchmarks
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+# 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.
+
+import argparse
+import os
+import json
+import sys
+
+from core import path_util
+from core import benchmark_finders
+
+
+def main():
+  parser = argparse.ArgumentParser(
+      description=('List all benchmarks defined in a benchmark file as a json '
+                   'string.'))
+  parser.add_argument('benchmark_file_paths', type=str, nargs='+')
+  args = parser.parse_args()
+  benchmark_names = set()
+  for path in args.benchmark_file_paths:
+    assert os.path.isfile(path), '%s does not exist' % path
+    benchmark_names.update(benchmark_finders.GetBenchmarkNamesForFile(
+        path_util.GetPerfDir(), os.path.abspath(path)))
+  print json.dumps(list(benchmark_names))
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/tools/perf/page_sets/ct_page_set.py b/tools/perf/page_sets/ct_page_set.py
new file mode 100644
index 0000000..97debad
--- /dev/null
+++ b/tools/perf/page_sets/ct_page_set.py
@@ -0,0 +1,45 @@
+# Copyright 2015 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.
+
+
+from page_sets import repaint_helpers
+
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+from telemetry import story
+
+
+class CTPage(page_module.Page):
+
+  def __init__(self, url, page_set, shared_page_state_class, archive_data_file):
+    super(CTPage, self).__init__(
+        url=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state_class)
+    self.archive_data_file = archive_data_file
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(2)
+
+  def RunPageInteractions(self, action_runner):
+    repaint_helpers.Repaint(action_runner)
+
+
+class CTPageSet(story.StorySet):
+  """Page set used by CT Benchmarks."""
+
+  def __init__(self, urls_list, user_agent, archive_data_file):
+    if user_agent == 'mobile':
+      shared_page_state_class = shared_page_state.SharedMobilePageState
+    elif user_agent == 'desktop':
+      shared_page_state_class = shared_page_state.SharedDesktopPageState
+    else:
+      raise ValueError('user_agent %s is unrecognized' % user_agent)
+
+    super(CTPageSet, self).__init__(archive_data_file=archive_data_file)
+
+    for url in urls_list.split(','):
+      self.AddStory(
+          CTPage(url, self, shared_page_state_class, archive_data_file))
diff --git a/tools/telemetry/telemetry/internal/backends/android_command_line_backend.py b/tools/telemetry/telemetry/internal/backends/android_command_line_backend.py
index 6301831..307a03e 100644
--- a/tools/telemetry/telemetry/internal/backends/android_command_line_backend.py
+++ b/tools/telemetry/telemetry/internal/backends/android_command_line_backend.py
@@ -77,7 +77,8 @@
       # --host-resolver-rules borks people's browsers if something goes wrong
       # with Telemetry.
       self._saved_command_line_file_contents = self._ReadFile()
-      if '--host-resolver-rules' in self._saved_command_line_file_contents:
+      if (self._saved_command_line_file_contents and
+          '--host-resolver-rules' in self._saved_command_line_file_contents):
         self._saved_command_line_file_contents = None
     except device_errors.CommandFailedError:
       self._saved_command_line_file_contents = None
@@ -97,7 +98,10 @@
       self._WriteFile(self._saved_command_line_file_contents)
 
   def _ReadFile(self):
-    return self._device.ReadFile(self.command_line_file, as_root=True)
+    if self._device.PathExists(self.command_line_file):
+      return self._device.ReadFile(self.command_line_file, as_root=True)
+    else:
+      return None
 
   def _WriteFile(self, contents):
     self._device.WriteFile(self.command_line_file, contents, as_root=True)
diff --git a/tools/telemetry/telemetry/internal/backends/chrome/android_browser_finder.py b/tools/telemetry/telemetry/internal/backends/chrome/android_browser_finder.py
index f81b622..06e5cb2b 100644
--- a/tools/telemetry/telemetry/internal/backends/chrome/android_browser_finder.py
+++ b/tools/telemetry/telemetry/internal/backends/chrome/android_browser_finder.py
@@ -178,29 +178,32 @@
   # Add the exact APK if given.
   if (finder_options.browser_executable and
       CanPossiblyHandlePath(finder_options.browser_executable)):
-    normalized_path = os.path.expanduser(finder_options.browser_executable)
-
-    exact_package = apk_helper.GetPackageName(normalized_path)
-    if not exact_package:
-      raise exceptions.PackageDetectionError(
-          'Unable to find package for %s specified by --browser-executable' %
-          normalized_path)
-
+    apk_name = os.path.basename(finder_options.browser_executable)
     package_info = next((info for info in CHROME_PACKAGE_NAMES.itervalues()
-                         if info[0] == exact_package), None)
+                         if info[2] == apk_name), None)
+
+    # It is okay if the APK name doesn't match any of known chrome browser APKs,
+    # since it may be of a different browser (say, mandoline).
     if package_info:
+      normalized_path = os.path.expanduser(finder_options.browser_executable)
+      exact_package = apk_helper.GetPackageName(normalized_path)
+      if not exact_package:
+        raise exceptions.PackageDetectionError(
+            'Unable to find package for %s specified by --browser-executable' %
+            normalized_path)
+
       [package, backend_settings, _] = package_info
-      possible_browsers.append(
-          PossibleAndroidBrowser(
+      if package == exact_package:
+        possible_browsers.append(PossibleAndroidBrowser(
             'exact',
             finder_options,
             android_platform,
             backend_settings(package),
             normalized_path))
-    else:
-      raise exceptions.UnknownPackageError(
-          '%s specified by --browser-executable has an unknown package: %s' %
-          (normalized_path, exact_package))
+      else:
+        raise exceptions.UnknownPackageError(
+            '%s specified by --browser-executable has an unknown package: %s' %
+            (normalized_path, exact_package))
 
   for name, package_info in CHROME_PACKAGE_NAMES.iteritems():
     package, backend_settings, local_apk = package_info
diff --git a/tools/telemetry/telemetry/internal/backends/chrome/android_browser_finder_unittest.py b/tools/telemetry/telemetry/internal/backends/chrome/android_browser_finder_unittest.py
index 2497207..1aef6a2 100644
--- a/tools/telemetry/telemetry/internal/backends/chrome/android_browser_finder_unittest.py
+++ b/tools/telemetry/telemetry/internal/backends/chrome/android_browser_finder_unittest.py
@@ -53,8 +53,8 @@
 
   def testCanLaunchAlwaysTrueWithExactApkReturnsAll(self):
     self._android_browser_finder_stub.os.path.files.append(
-        '/foo/content-shell.apk')
-    self.finder_options.browser_executable = '/foo/content-shell.apk'
+        '/foo/ContentShell.apk')
+    self.finder_options.browser_executable = '/foo/ContentShell.apk'
     self._get_package_name_mock.return_value = 'org.chromium.content_shell_apk'
 
     fake_platform = FakeAndroidPlatform(can_launch=True)
@@ -68,8 +68,8 @@
 
   def testErrorWithUnknownExactApk(self):
     self._android_browser_finder_stub.os.path.files.append(
-        '/foo/content-shell.apk')
-    self.finder_options.browser_executable = '/foo/content-shell.apk'
+        '/foo/ContentShell.apk')
+    self.finder_options.browser_executable = '/foo/ContentShell.apk'
     self._get_package_name_mock.return_value = 'org.unknown.app'
 
     fake_platform = FakeAndroidPlatform(can_launch=True)
@@ -78,13 +78,24 @@
         self.finder_options, fake_platform)
 
   def testErrorWithNonExistantExactApk(self):
-    self.finder_options.browser_executable = '/foo/content-shell.apk'
+    self.finder_options.browser_executable = '/foo/ContentShell.apk'
+    self._get_package_name_mock.return_value = 'org.chromium.content_shell_apk'
 
     fake_platform = FakeAndroidPlatform(can_launch=True)
     self.assertRaises(Exception,
         android_browser_finder._FindAllPossibleBrowsers,
         self.finder_options, fake_platform)
 
+  def testNoErrorWithUnrecognizedApkName(self):
+    self._android_browser_finder_stub.os.path.files.append(
+        '/foo/unknown.apk')
+    self.finder_options.browser_executable = '/foo/unknown.apk'
+
+    fake_platform = FakeAndroidPlatform(can_launch=True)
+    possible_browsers = android_browser_finder._FindAllPossibleBrowsers(
+        self.finder_options, fake_platform)
+    self.assertNotIn('exact', [b.browser_type for b in possible_browsers])
+
 
 class FakePossibleBrowser(object):
   def __init__(self, last_modification_time):
diff --git a/tools/telemetry/telemetry/internal/backends/chrome/desktop_browser_finder.py b/tools/telemetry/telemetry/internal/backends/chrome/desktop_browser_finder.py
index e1ed430..ee9386e 100644
--- a/tools/telemetry/telemetry/internal/backends/chrome/desktop_browser_finder.py
+++ b/tools/telemetry/telemetry/internal/backends/chrome/desktop_browser_finder.py
@@ -169,17 +169,24 @@
   # Add the explicit browser executable if given and we can handle it.
   if (finder_options.browser_executable and
       CanPossiblyHandlePath(finder_options.browser_executable)):
-    normalized_executable = os.path.expanduser(
-        finder_options.browser_executable)
-    if path.IsExecutable(normalized_executable):
-      browser_directory = os.path.dirname(finder_options.browser_executable)
-      browsers.append(PossibleDesktopBrowser('exact', finder_options,
-                                             normalized_executable, flash_path,
-                                             False, browser_directory))
-    else:
-      raise exceptions.PathMissingError(
-          '%s specified by --browser-executable does not exist' %
-          normalized_executable)
+    app_name = os.path.basename(finder_options.browser_executable)
+
+    # It is okay if the executable name doesn't match any of known chrome
+    # browser executables, since it may be of a different browser (say,
+    # mandoline).
+    if app_name in chromium_app_names or app_name == content_shell_app_name:
+      normalized_executable = os.path.expanduser(
+          finder_options.browser_executable)
+      if path.IsExecutable(normalized_executable):
+        browser_directory = os.path.dirname(finder_options.browser_executable)
+        browsers.append(PossibleDesktopBrowser(
+            'exact', finder_options, normalized_executable, flash_path,
+            app_name == content_shell_app_name,
+            browser_directory))
+      else:
+        raise exceptions.PathMissingError(
+            '%s specified by --browser-executable does not exist' %
+            normalized_executable)
 
   def AddIfFound(browser_type, build_dir, type_dir, app_name, content_shell):
     browser_directory = os.path.join(chrome_root, build_dir, type_dir)
@@ -196,8 +203,8 @@
   # Add local builds
   for build_dir, build_type in path.GetBuildDirectories():
     for chromium_app_name in chromium_app_names:
-      AddIfFound(build_type.lower(), build_dir, build_type,
-                 chromium_app_name, False)
+      AddIfFound(build_type.lower(), build_dir, build_type, chromium_app_name,
+                 False)
     AddIfFound('content-shell-' + build_type.lower(), build_dir, build_type,
                content_shell_app_name, True)
 
diff --git a/tools/telemetry/telemetry/internal/backends/chrome/desktop_browser_finder_unittest.py b/tools/telemetry/telemetry/internal/backends/chrome/desktop_browser_finder_unittest.py
index 89476129..746deb27 100644
--- a/tools/telemetry/telemetry/internal/backends/chrome/desktop_browser_finder_unittest.py
+++ b/tools/telemetry/telemetry/internal/backends/chrome/desktop_browser_finder_unittest.py
@@ -191,6 +191,14 @@
     self._finder_options.browser_executable = '/foo/chrome.apk'
     self.assertNotIn('exact', self.DoFindAllTypes())
 
+  def testNoErrorWithUnrecognizedExecutableName(self):
+    if not self.CanFindAvailableBrowsers():
+      return
+
+    self._files.append('/foo/mandoline')
+    self._finder_options.browser_executable = '/foo/mandoline'
+    self.assertNotIn('exact', self.DoFindAllTypes())
+
   def testFindUsingDefaults(self):
     if not self.CanFindAvailableBrowsers():
       return
@@ -264,3 +272,11 @@
              'debug', 'release',
              'content-shell-debug', 'content-shell-release',
              'system', 'canary']))
+
+  def testNoErrorWithUnrecognizedExecutableName(self):
+    if not self.CanFindAvailableBrowsers():
+      return
+
+    self._files.append('c:\\foo\\mandoline.exe')
+    self._finder_options.browser_dir = 'c:\\foo\\mandoline.exe'
+    self.assertNotIn('exact', self.DoFindAllTypes())
diff --git a/tools/telemetry/telemetry/internal/backends/mandoline/desktop_mandoline_finder.py b/tools/telemetry/telemetry/internal/backends/mandoline/desktop_mandoline_finder.py
index b88b2a27..322a6dc 100644
--- a/tools/telemetry/telemetry/internal/backends/mandoline/desktop_mandoline_finder.py
+++ b/tools/telemetry/telemetry/internal/backends/mandoline/desktop_mandoline_finder.py
@@ -83,6 +83,7 @@
 
 def FindAllBrowserTypes(_):
   return [
+      'exact',
       'mandoline-debug',
       'mandoline-debug_x64',
       'mandoline-default',
@@ -115,17 +116,23 @@
   # Add the explicit browser executable if given and we can handle it.
   if (finder_options.browser_executable and
       CanPossiblyHandlePath(finder_options.browser_executable)):
-    normalized_executable = os.path.expanduser(
-        finder_options.browser_executable)
-    if path.IsExecutable(normalized_executable):
-      browser_directory = os.path.dirname(finder_options.browser_executable)
-      browsers.append(PossibleDesktopMandolineBrowser('exact', finder_options,
-                                                      normalized_executable,
-                                                      browser_directory))
-    else:
-      raise exceptions.PathMissingError(
-          '%s specified by --browser-executable does not exist',
-          normalized_executable)
+    app_name = os.path.basename(finder_options.browser_executable)
+
+    # It is okay if the executable name doesn't match any of known chrome
+    # browser executables, since it may be of a different browser (say,
+    # chrome).
+    if app_name == mandoline_app_name:
+      normalized_executable = os.path.expanduser(
+          finder_options.browser_executable)
+      if path.IsExecutable(normalized_executable):
+        browser_directory = os.path.dirname(finder_options.browser_executable)
+        browsers.append(PossibleDesktopMandolineBrowser('exact', finder_options,
+                                                        normalized_executable,
+                                                        browser_directory))
+      else:
+        raise exceptions.PathMissingError(
+            '%s specified by --browser-executable does not exist',
+            normalized_executable)
 
   def AddIfFound(browser_type, build_dir, type_dir, app_name):
     browser_directory = os.path.join(chrome_root, build_dir, type_dir)
diff --git a/tools/telemetry/telemetry/internal/backends/mandoline/desktop_mandoline_finder_unittest.py b/tools/telemetry/telemetry/internal/backends/mandoline/desktop_mandoline_finder_unittest.py
new file mode 100644
index 0000000..a9e7e4ac
--- /dev/null
+++ b/tools/telemetry/telemetry/internal/backends/mandoline/desktop_mandoline_finder_unittest.py
@@ -0,0 +1,125 @@
+# Copyright 2015 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.
+import unittest
+
+from telemetry.internal.backends.mandoline import desktop_mandoline_finder
+from telemetry.internal.browser import browser_options
+from telemetry.internal.platform import desktop_device
+from telemetry.testing import system_stub
+
+
+# This file verifies the logic for finding a mandoline browser instance on all
+# platforms at once. It does so by providing stubs for the OS/sys/subprocess
+# primitives that the underlying finding logic usually uses to locate a suitable
+# browser. We prefer this approach to having to run the same test on every
+# platform on which we want this code to work.
+
+class FindTestBase(unittest.TestCase):
+  def setUp(self):
+    self._finder_options = browser_options.BrowserFinderOptions()
+    self._finder_options.chrome_root = '../../../'
+    self._finder_stubs = system_stub.Override(desktop_mandoline_finder,
+                                              ['os', 'subprocess', 'sys'])
+    self._path_stubs = system_stub.Override(desktop_mandoline_finder.path,
+                                            ['os', 'sys'])
+
+  def tearDown(self):
+    self._finder_stubs.Restore()
+    self._path_stubs.Restore()
+
+  @property
+  def _files(self):
+    return self._path_stubs.os.path.files
+
+  def DoFindAll(self):
+    return desktop_mandoline_finder.FindAllAvailableBrowsers(
+      self._finder_options, desktop_device.DesktopDevice())
+
+  def DoFindAllTypes(self):
+    browsers = self.DoFindAll()
+    return [b.browser_type for b in browsers]
+
+  def CanFindAvailableBrowsers(self):
+    return desktop_mandoline_finder.CanFindAvailableBrowsers()
+
+
+class LinuxFindTest(FindTestBase):
+  def setUp(self):
+    super(LinuxFindTest, self).setUp()
+
+    self._finder_stubs.sys.platform = 'linux2'
+    self._path_stubs.sys.platform = 'linux2'
+    self._files.append('/foo/mandoline')
+    self._files.append('../../../out/Release/mandoline')
+    self._files.append('../../../out/Debug/mandoline')
+
+    #this = self
+    #def call_hook(*args, **kwargs):  # pylint: disable=W0613
+    #  if this.has_google_chrome_on_path:
+    #    return 0
+    #  raise OSError('Not found')
+    #self._finder_stubs.subprocess.call = call_hook
+
+    #def realpath_hook(*unused_args, **unused_kwargs):
+    #  if this.chrome_beta_is_google_chrome:
+    #    return '/opt/google/chrome-beta/google-chrome-beta'
+    #  return '/opt/google/chrome/google-chrome'
+    #self._finder_stubs.os.path.realpath = realpath_hook
+
+  def testFindAllGivenDefaults(self):
+    if not self.CanFindAvailableBrowsers():
+      return
+
+    types = self.DoFindAllTypes()
+    self.assertEquals(set(types), set(['mandoline-debug', 'mandoline-release']))
+
+  def testFindWithProvidedExecutable(self):
+    if not self.CanFindAvailableBrowsers():
+      return
+
+    self._finder_options.browser_executable = '/foo/mandoline'
+    self.assertIn('exact', self.DoFindAllTypes())
+
+  def testNoErrorWithUnrecognizedExecutableName(self):
+    if not self.CanFindAvailableBrowsers():
+      return
+
+    self._files.append('/foo/chrome')
+    self._finder_options.browser_executable = '/foo/chrome'
+    self.assertNotIn('exact', self.DoFindAllTypes())
+
+
+class WinFindTest(FindTestBase):
+  def setUp(self):
+    super(WinFindTest, self).setUp()
+
+    self._finder_stubs.sys.platform = 'win32'
+    self._path_stubs.sys.platform = 'win32'
+    self._files.append('c:\\tmp\\mandoline.exe')
+    self._files.append('..\\..\\..\\out\\Release\\mandoline.exe')
+    self._files.append('..\\..\\..\\out\\Debug\\mandoline.exe')
+
+  def testFindAllGivenDefaults(self):
+    if not self.CanFindAvailableBrowsers():
+      return
+
+    types = self.DoFindAllTypes()
+    self.assertEquals(set(types), set(['mandoline-debug', 'mandoline-release']))
+
+  def testFindAllWithExact(self):
+    if not self.CanFindAvailableBrowsers():
+      return
+
+    self._finder_options.browser_executable = 'c:\\tmp\\mandoline.exe'
+    types = self.DoFindAllTypes()
+    self.assertEquals(set(types),
+                      set(['exact', 'mandoline-debug', 'mandoline-release']))
+
+  def testNoErrorWithUnrecognizedExecutableName(self):
+    if not self.CanFindAvailableBrowsers():
+      return
+
+    self._files.append('c:\\foo\\chrome.exe')
+    self._finder_options.browser_dir = 'c:\\foo\\chrome.exe'
+    self.assertNotIn('exact', self.DoFindAllTypes())
diff --git a/tools/telemetry/telemetry/testing/system_stub.py b/tools/telemetry/telemetry/testing/system_stub.py
index 18ae7de..9dd59d6 100644
--- a/tools/telemetry/telemetry/testing/system_stub.py
+++ b/tools/telemetry/telemetry/testing/system_stub.py
@@ -7,7 +7,9 @@
 This test allows one to test code that itself uses os, sys, and subprocess.
 """
 
+import ntpath
 import os
+import posixpath
 import re
 import shlex
 import sys
@@ -342,6 +344,12 @@
         tmp = os.path.join(*paths)
         return tmp.replace('\\', '/')
 
+    def basename(self, path):
+      if self.sys.platform.startswith('win'):
+        return ntpath.basename(path)
+      else:
+        return posixpath.basename(path)
+
     @staticmethod
     def abspath(path):
       return os.path.abspath(path)
diff --git a/ui/file_manager/video_player/js/media_controls.js b/ui/file_manager/video_player/js/media_controls.js
index 830bb45..672e662 100644
--- a/ui/file_manager/video_player/js/media_controls.js
+++ b/ui/file_manager/video_player/js/media_controls.js
@@ -245,17 +245,12 @@
 MediaControls.PROGRESS_RANGE = 5000;
 
 /**
- * @param {boolean=} opt_seekMark True if the progress slider should have
- *     a seek mark.
  * @param {HTMLElement=} opt_parent Parent container.
  */
-MediaControls.prototype.initTimeControls = function(opt_seekMark, opt_parent) {
+MediaControls.prototype.initTimeControls = function(opt_parent) {
   var timeControls = this.createControl('time-controls', opt_parent);
 
-  var sliderConstructor =
-      opt_seekMark ? MediaControls.PreciseSlider : MediaControls.Slider;
-
-  this.progressSlider_ = new sliderConstructor(
+  this.progressSlider_ = new MediaControls.PreciseSlider(
       this.createControl('progress media-control', timeControls),
       0, /* value */
       MediaControls.PROGRESS_RANGE,
@@ -848,13 +843,12 @@
  * @param {number} range Number of distinct slider positions to be supported.
  * @param {function(number)} onChange Value change handler.
  * @param {function(boolean)} onDrag Drag begin/end handler.
- * @param {function(number):string} formatFunction Value formatting function.
  * @constructor
  * @struct
  * @extends {MediaControls.Slider}
  */
 MediaControls.PreciseSlider = function(
-    container, value, range, onChange, onDrag, formatFunction) {
+    container, value, range, onChange, onDrag) {
   MediaControls.Slider.apply(this, arguments);
 
   var doc = this.container_.ownerDocument;
@@ -1072,7 +1066,7 @@
 
   this.container_.classList.add('video-controls');
   this.initPlayButton();
-  this.initTimeControls(true /* show seek mark */);
+  this.initTimeControls();
   this.initVolumeControls();
 
   // Create the cast button.
@@ -1300,67 +1294,3 @@
   hideBelow('.volume-controls', 210);
   hideBelow('.fullscreen', 150);
 };
-
-/**
- * Creates audio controls.
- *
- * @param {!HTMLElement} container Parent container.
- * @param {function(boolean)} advanceTrack Parameter: true=forward.
- * @param {function(Event)} onError Error handler.
- * @constructor
- * @struct
- * @extends {MediaControls}
- */
-function AudioControls(container, advanceTrack, onError) {
-  MediaControls.call(this, container, onError);
-
-  this.container_.classList.add('audio-controls');
-
-  this.advanceTrack_ = advanceTrack;
-
-  this.initPlayButton();
-  this.initTimeControls(false /* no seek mark */);
-  /* No volume controls */
-  this.createButton('previous', this.onAdvanceClick_.bind(this, false));
-  this.createButton('next', this.onAdvanceClick_.bind(this, true));
-
-  // Disables all controls at first.
-  this.enableControls_('.media-control', false);
-
-  var audioControls = this;
-  chrome.mediaPlayerPrivate.onNextTrack.addListener(
-      function() { audioControls.onAdvanceClick_(true); });
-  chrome.mediaPlayerPrivate.onPrevTrack.addListener(
-      function() { audioControls.onAdvanceClick_(false); });
-  chrome.mediaPlayerPrivate.onTogglePlayState.addListener(
-      function() { audioControls.togglePlayState(); });
-}
-
-AudioControls.prototype = { __proto__: MediaControls.prototype };
-
-/**
- * Media completion handler. Advances to the next track.
- */
-AudioControls.prototype.onMediaComplete = function() {
-  this.advanceTrack_(true);
-};
-
-/**
- * The track position after which "previous" button acts as "restart".
- */
-AudioControls.TRACK_RESTART_THRESHOLD = 5;  // seconds.
-
-/**
- * @param {boolean} forward True if advancing forward.
- * @private
- */
-AudioControls.prototype.onAdvanceClick_ = function(forward) {
-  if (!forward &&
-      (this.getMedia().currentTime > AudioControls.TRACK_RESTART_THRESHOLD)) {
-    // We are far enough from the beginning of the current track.
-    // Restart it instead of than skipping to the previous one.
-    this.getMedia().currentTime = 0;
-  } else {
-    this.advanceTrack_(forward);
-  }
-};
diff --git a/ui/message_center/views/message_center_view.cc b/ui/message_center/views/message_center_view.cc
index ccdb0437..2c536e0 100644
--- a/ui/message_center/views/message_center_view.cc
+++ b/ui/message_center/views/message_center_view.cc
@@ -454,17 +454,25 @@
   NotificationViewsMap::const_iterator view_iter = notification_views_.find(id);
   if (view_iter == notification_views_.end())
     return;
-  NotificationView* view = view_iter->second;
+
   // Set the item on the mouse cursor as the reposition target so that it
   // should stick to the current position over the update.
-  for (const auto& hover_id_view : notification_views_) {
-    NotificationView* hover_view = hover_id_view.second;
-    if (hover_view->is_hover()) {
-      message_list_view_->SetRepositionTarget(hover_view->bounds());
-      break;
+  bool set = false;
+  if (message_list_view_->IsMouseHovered()) {
+    for (const auto& hover_id_view : notification_views_) {
+      NotificationView* hover_view = hover_id_view.second;
+      if (hover_view->IsMouseHovered()) {
+        message_list_view_->SetRepositionTarget(hover_view->bounds());
+        set = true;
+        break;
+      }
     }
   }
+  if (!set)
+    message_list_view_->ResetRepositionSession();
+
   // TODO(dimich): add MessageCenter::GetVisibleNotificationById(id)
+  NotificationView* view = view_iter->second;
   const NotificationList::Notifications& notifications =
       message_center_->GetVisibleNotifications();
   for (NotificationList::Notifications::const_iterator iter =
diff --git a/ui/message_center/views/message_view.cc b/ui/message_center/views/message_view.cc
index 7e501d4..62e2993 100644
--- a/ui/message_center/views/message_view.cc
+++ b/ui/message_center/views/message_view.cc
@@ -46,8 +46,7 @@
       notifier_id_(notifier_id),
       background_view_(NULL),
       scroller_(NULL),
-      display_source_(display_source),
-      is_hover_(false) {
+      display_source_(display_source) {
   SetFocusable(true);
 
   // Create the opaque background that's above the view's shadow.
@@ -85,15 +84,6 @@
 MessageView::~MessageView() {
 }
 
-// views::View
-void MessageView::OnMouseEntered(const ui::MouseEvent& event) {
-  is_hover_ = true;
-}
-
-void MessageView::OnMouseExited(const ui::MouseEvent& event) {
-  is_hover_ = false;
-}
-
 void MessageView::UpdateWithNotification(const Notification& notification) {
   small_image_view_->SetImage(notification.small_image().AsImageSkia());
   display_source_ = notification.display_source();
diff --git a/ui/message_center/views/message_view.h b/ui/message_center/views/message_view.h
index cf0ef4fc..28cd607 100644
--- a/ui/message_center/views/message_view.h
+++ b/ui/message_center/views/message_view.h
@@ -82,8 +82,6 @@
   void OnFocus() override;
   void OnBlur() override;
   void Layout() override;
-  void OnMouseEntered(const ui::MouseEvent& event) override;
-  void OnMouseExited(const ui::MouseEvent& event) override;
 
   // Overridden from ui::EventHandler:
   void OnGestureEvent(ui::GestureEvent* event) override;
@@ -96,8 +94,6 @@
   NotifierId notifier_id() { return notifier_id_; }
   const base::string16& display_source() const { return display_source_; }
 
-  bool is_hover() { return is_hover_; }
-
  protected:
   // Overridden from views::SlideOutView:
   void OnSlideOut() override;
@@ -119,9 +115,6 @@
 
   base::string16 display_source_;
 
-  // True if the mouse cursor is on this view. False if not.
-  bool is_hover_;
-
   scoped_ptr<views::Painter> focus_painter_;
 
   // Changes the background color being used by |background_view_| and schedules
diff --git a/ui/message_center/views/proportional_image_view.cc b/ui/message_center/views/proportional_image_view.cc
index 21783243..a7befd66 100644
--- a/ui/message_center/views/proportional_image_view.cc
+++ b/ui/message_center/views/proportional_image_view.cc
@@ -5,6 +5,7 @@
 #include "ui/message_center/views/proportional_image_view.h"
 
 #include "ui/gfx/canvas.h"
+#include "ui/gfx/image/image_skia_operations.h"
 #include "ui/message_center/message_center_style.h"
 
 namespace message_center {
@@ -33,29 +34,18 @@
   views::View::OnPaint(canvas);
 
   gfx::Size draw_size = GetImageDrawingSize();
-
   if (draw_size.IsEmpty())
     return;
 
   gfx::Rect draw_bounds = GetContentsBounds();
   draw_bounds.ClampToCenteredSize(draw_size);
 
-  gfx::Size image_size(image_.size());
-
-  if (image_size == draw_size) {
-    canvas->DrawImageInt(image_, draw_bounds.x(), draw_bounds.y());
-  } else {
-    SkPaint paint;
-    paint.setFilterQuality(kLow_SkFilterQuality);
-
-    // This call resizes the image while drawing into the canvas.
-    canvas->DrawImageInt(
-        image_,
-        0, 0, image_size.width(), image_size.height(),
-        draw_bounds.x(), draw_bounds.y(), draw_size.width(), draw_size.height(),
-        true,
-        paint);
-  }
+  gfx::ImageSkia image =
+      (image_.size() == draw_size)
+          ? image_
+          : gfx::ImageSkiaOperations::CreateResizedImage(
+                image_, skia::ImageOperations::RESIZE_BEST, draw_size);
+  canvas->DrawImageInt(image, draw_bounds.x(), draw_bounds.y());
 }
 
 const char* ProportionalImageView::GetClassName() const {
diff --git a/ui/ozone/platform/drm/gpu/drm_window.cc b/ui/ozone/platform/drm/gpu/drm_window.cc
index f0e59f8..9ef04bd0 100644
--- a/ui/ozone/platform/drm/gpu/drm_window.cc
+++ b/ui/ozone/platform/drm/gpu/drm_window.cc
@@ -85,10 +85,10 @@
 void DrmWindow::SetBounds(const gfx::Rect& bounds) {
   TRACE_EVENT2("drm", "DrmWindow::SetBounds", "widget", widget_, "bounds",
                bounds.ToString());
-  bounds_ = bounds;
   if (bounds_.size() != bounds.size())
     last_submitted_planes_.clear();
 
+  bounds_ = bounds;
   screen_manager_->UpdateControllerToWindowMapping();
 }