diff --git a/DEPS b/DEPS
index f81fc5eb..93366c3 100644
--- a/DEPS
+++ b/DEPS
@@ -94,7 +94,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': '3e2b10936c5304477fdadfa233671738008fe154',
+  'swiftshader_revision': 'a0aa5fdeee12bc42616fe13ef3ea62edb1b9f166',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -130,7 +130,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '9252115c46302971355d1d5fcbe1512f32d30a70',
+  'catapult_revision': '43a5c4971235ed78db5c8e2df5eb5c2e0dbff2d6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
diff --git a/ash/window_manager.cc b/ash/window_manager.cc
index f76a2fe..905577e 100644
--- a/ash/window_manager.cc
+++ b/ash/window_manager.cc
@@ -55,6 +55,7 @@
 #include "ui/aura/mus/window_tree_client.h"
 #include "ui/aura/mus/window_tree_host_mus.h"
 #include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
 #include "ui/base/class_property.h"
 #include "ui/base/hit_test.h"
 #include "ui/display/display_observer.h"
@@ -308,7 +309,20 @@
 
 void WindowManager::OnPointerEventObserved(const ui::PointerEvent& event,
                                            aura::Window* target) {
-  pointer_watcher_event_router_->OnPointerEventObserved(event, target);
+  DCHECK_EQ(Config::MASH, Shell::GetAshConfig());
+  // We have received a pointer event on |target|. However, we need to fixup
+  // |target| first. WindowManager's WindowTree is the entire root tree and
+  // we must adjust |target| from being the root to the aura::Window which
+  // would handle |event|.
+  std::unique_ptr<ui::Event> event_copy = ui::Event::Clone(event);
+  ui::EventTarget* e_target =
+      target->GetHost()
+          ->dispatcher()
+          ->GetDefaultEventTargeter()
+          ->FindTargetForEvent(target, event_copy.get());
+
+  pointer_watcher_event_router_->OnPointerEventObserved(
+      event, static_cast<aura::Window*>(e_target));
 }
 
 aura::PropertyConverter* WindowManager::GetPropertyConverter() {
diff --git a/base/process/launch_fuchsia.cc b/base/process/launch_fuchsia.cc
index b79210f..7292bdc 100644
--- a/base/process/launch_fuchsia.cc
+++ b/base/process/launch_fuchsia.cc
@@ -193,4 +193,8 @@
   return GetAppOutputInternal(cl, false, output, exit_code);
 }
 
+void RaiseProcessToHighPriority() {
+  // Fuchsia doesn't provide an API to change process priority.
+}
+
 }  // namespace base
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/ClientManager.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/ClientManager.java
index 17ad8b9..80b2110ce 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/ClientManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/ClientManager.java
@@ -407,12 +407,12 @@
      * requirement for launch. We also need the web->app verification which will be checked after
      * the Activity has launched async.
      * @param session The session attempting to launch the TrustedWebActivity.
-     * @param origin The origin that will load on the TrustedWebActivity.
+     * @param url The url that will load on the TrustedWebActivity.
      * @return Whether the client for the session passes the initial requirements to launch a
      *         TrustedWebActivity in the given origin.
      */
     public synchronized boolean canSessionLaunchInTrustedWebActivity(
-            CustomTabsSessionToken session, Uri origin) {
+            CustomTabsSessionToken session, Uri url) {
         if (!ChromeFeatureList.isEnabled(ChromeFeatureList.TRUSTED_WEB_ACTIVITY)) return false;
         if (ChromeVersionInfo.isBetaBuild() || ChromeVersionInfo.isStableBuild()) return false;
 
@@ -420,8 +420,11 @@
         if (params == null) return false;
         String packageName = params.getPackageName();
         if (TextUtils.isEmpty(packageName)) return false;
-        boolean isAppAssociatedWithOrigin = params.mLinkedUrls.contains(origin);
+        boolean isAppAssociatedWithOrigin = params.mLinkedUrls.contains(url);
         if (!isAppAssociatedWithOrigin) return false;
+
+        // Split path from the given Uri to get only the origin before web->native verification.
+        Uri origin = new Uri.Builder().scheme(url.getScheme()).authority(url.getHost()).build();
         if (OriginVerifier.isValidOrigin(
                     packageName, origin, CustomTabsService.RELATION_HANDLE_ALL_URLS)) {
             return true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
index ab7a37d..56fd836 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
@@ -122,6 +122,7 @@
     private static boolean sRegisteredDaydreamHook;
     private static boolean sAddedBlackOverlayView;
     private static boolean sRegisteredVrAssetsComponent = false;
+    private static boolean sChromeStarted = false;
 
     private ChromeActivity mActivity;
 
@@ -334,6 +335,10 @@
     public static void maybeRegisterVrEntryHook(final ChromeActivity activity) {
         // Daydream is not supported on pre-N devices.
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) return;
+        if (!sChromeStarted) {
+            nativeOnChromeStarted();
+            sChromeStarted = true;
+        }
         if (sInstance != null) return; // Will be handled in onResume.
         if (!activitySupportsVrBrowsing(activity) && sRegisteredVrAssetsComponent) return;
 
@@ -1776,4 +1781,5 @@
     private native boolean nativeIsClearActivatePending(long nativeVrShellDelegate);
     private native void nativeDestroy(long nativeVrShellDelegate);
     private static native void nativeRegisterVrAssetsComponent();
+    private static native void nativeOnChromeStarted();
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
index 72d7b22..26bb763 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
@@ -163,7 +163,12 @@
         void verifyRelationship() {
             mOriginVerifier = new OriginVerifier(mTrustedWebContentProvider,
                     getNativeClientPackageName(), CustomTabsService.RELATION_HANDLE_ALL_URLS);
-            mOriginVerifier.start(mWebappInfo.uri());
+            // Split path from the url to get only the origin.
+            Uri origin = new Uri.Builder()
+                                 .scheme(mWebappInfo.uri().getScheme())
+                                 .authority(mWebappInfo.uri().getHost())
+                                 .build();
+            mOriginVerifier.start(origin);
         }
 
         @Override
diff --git a/chrome/browser/android/vr_shell/vr_shell_delegate.cc b/chrome/browser/android/vr_shell/vr_shell_delegate.cc
index a4a47d51..c773955 100644
--- a/chrome/browser/android/vr_shell/vr_shell_delegate.cc
+++ b/chrome/browser/android/vr_shell/vr_shell_delegate.cc
@@ -12,6 +12,8 @@
 #include "chrome/browser/android/vr_shell/vr_shell.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/component_updater/vr_assets_component_installer.h"
+#include "chrome/browser/vr/assets.h"
+#include "chrome/browser/vr/metrics_helper.h"
 #include "chrome/browser/vr/service/vr_device_manager.h"
 #include "chrome/browser/vr/service/vr_service_impl.h"
 #include "content/public/browser/webvr_service_provider.h"
@@ -284,4 +286,10 @@
       g_browser_process->component_updater());
 }
 
+static void JNI_VrShellDelegate_OnChromeStarted(
+    JNIEnv* env,
+    const JavaParamRef<jclass>& clazz) {
+  vr::Assets::GetInstance()->GetMetricsHelper()->OnChromeStarted();
+}
+
 }  // namespace vr_shell
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.cc
index 72d28cc..bdd1ff749 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.cc
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.cc
@@ -96,7 +96,7 @@
   std::unique_ptr<data_reduction_proxy::DataReductionProxyIOData>
       data_reduction_proxy_io_data(
           new data_reduction_proxy::DataReductionProxyIOData(
-              DataReductionProxyChromeSettings::GetClient(), net_log,
+              DataReductionProxyChromeSettings::GetClient(), prefs, net_log,
               io_task_runner, ui_task_runner, enabled, GetUserAgent(),
               version_info::GetChannelString(chrome::GetChannel())));
 
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 10adea7..ef083f1 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -465,6 +465,11 @@
     prefs::kWebRTCUDPPortRange,
     base::Value::Type::STRING },
 #endif  // BUILDFLAG(ENABLE_WEBRTC)
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+  { key::kSecurityKeyPermitAttestation,
+    prefs::kSecurityKeyPermitAttestation,
+    base::Value::Type::LIST },
+#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
 #if !defined(OS_MACOSX)
   { key::kFullscreenAllowed,
     prefs::kFullscreenAllowed,
@@ -473,9 +478,6 @@
   { key::kFullscreenAllowed,
     extensions::pref_names::kAppFullscreenAllowed,
     base::Value::Type::BOOLEAN },
-  { key::kSecurityKeyPermitAttestation,
-    prefs::kSecurityKeyPermitAttestation,
-    base::Value::Type::LIST },
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
 #endif  // !defined(OS_MACOSX)
 
diff --git a/chrome/browser/process_singleton_win.cc b/chrome/browser/process_singleton_win.cc
index 3d83b26..5242890 100644
--- a/chrome/browser/process_singleton_win.cc
+++ b/chrome/browser/process_singleton_win.cc
@@ -220,7 +220,7 @@
     DPLOG(ERROR) << "Unable to terminate process";
   }
   UMA_HISTOGRAM_SPARSE_SLOWLY(
-      "Chrome.ProcessSingleton.ProcessTerminateErrorCode.Windows",
+      "Chrome.ProcessSingleton.TerminateProcessErrorCode.Windows",
       terminate_error);
 }
 
diff --git a/chrome/browser/process_singleton_win_unittest.cc b/chrome/browser/process_singleton_win_unittest.cc
index 482197f..5106f885 100644
--- a/chrome/browser/process_singleton_win_unittest.cc
+++ b/chrome/browser/process_singleton_win_unittest.cc
@@ -287,7 +287,7 @@
   histogram_tester().ExpectTotalCount(
       "Chrome.ProcessSingleton.TerminateProcessTime", 1u);
   histogram_tester().ExpectUniqueSample(
-      "Chrome.ProcessSingleton.ProcessTerminateErrorCode.Windows", 0, 1u);
+      "Chrome.ProcessSingleton.TerminateProcessErrorCode.Windows", 0, 1u);
   histogram_tester().ExpectUniqueSample(
       "Chrome.ProcessSingleton.TerminationWaitErrorCode.Windows", 0, 1u);
   histogram_tester().ExpectUniqueSample(
@@ -346,7 +346,7 @@
   histogram_tester().ExpectTotalCount(
       "Chrome.ProcessSingleton.TerminateProcessTime", 1u);
   histogram_tester().ExpectUniqueSample(
-      "Chrome.ProcessSingleton.ProcessTerminateErrorCode.Windows", 0, 1u);
+      "Chrome.ProcessSingleton.TerminateProcessErrorCode.Windows", 0, 1u);
   histogram_tester().ExpectUniqueSample(
       "Chrome.ProcessSingleton.TerminationWaitErrorCode.Windows", 0, 1u);
   histogram_tester().ExpectUniqueSample(
diff --git a/chrome/browser/ui/tabs/tab_data_experimental.cc b/chrome/browser/ui/tabs/tab_data_experimental.cc
index 6c43d3ef..3d398d9 100644
--- a/chrome/browser/ui/tabs/tab_data_experimental.cc
+++ b/chrome/browser/ui/tabs/tab_data_experimental.cc
@@ -5,6 +5,8 @@
 #include "chrome/browser/ui/tabs/tab_data_experimental.h"
 
 #include "base/memory/ptr_util.h"
+#include "base/strings/string_util.h"
+#include "chrome/browser/ui/tab_ui_helper.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_experimental.h"
 #include "content/public/browser/web_contents.h"
 
@@ -58,11 +60,43 @@
 TabDataExperimental& TabDataExperimental::operator=(TabDataExperimental&&) =
     default;
 
-base::string16 TabDataExperimental::GetTitle() const {
+const GURL& TabDataExperimental::GetURL() const {
+  if (contents_)
+    return contents_->GetURL();
+  return GURL::EmptyGURL();
+}
+
+const base::string16& TabDataExperimental::GetTitle() const {
   // TODO(brettw) this will need to use TabUIHelper.
   if (contents_)
     return contents_->GetTitle();
-  return base::string16();
+  return base::EmptyString16();
+}
+
+gfx::ImageSkia TabDataExperimental::GetFavicon() const {
+  TabUIHelper* tab_ui_helper = TabUIHelper::FromWebContents(contents_);
+  return tab_ui_helper->GetFavicon().AsImageSkia();
+}
+
+TabNetworkState TabDataExperimental::GetNetworkState() const {
+  if (contents_)
+    return TabNetworkStateForWebContents(contents_);
+  return TabNetworkState::kNone;
+}
+
+bool TabDataExperimental::IsCrashed() const {
+  if (!contents_)
+    return false;
+
+  auto crashed_status = contents_->GetCrashedStatus();
+  return (crashed_status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED ||
+#if defined(OS_CHROMEOS)
+          crashed_status ==
+              base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM ||
+#endif
+          crashed_status == base::TERMINATION_STATUS_PROCESS_CRASHED ||
+          crashed_status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION ||
+          crashed_status == base::TERMINATION_STATUS_LAUNCH_FAILED);
 }
 
 bool TabDataExperimental::CountsAsViewIndex() const {
diff --git a/chrome/browser/ui/tabs/tab_data_experimental.h b/chrome/browser/ui/tabs/tab_data_experimental.h
index b270cd9d..50aacbc 100644
--- a/chrome/browser/ui/tabs/tab_data_experimental.h
+++ b/chrome/browser/ui/tabs/tab_data_experimental.h
@@ -10,6 +10,10 @@
 
 #include "base/macros.h"
 #include "base/strings/string16.h"
+#include "chrome/browser/ui/tabs/tab_network_state.h"
+#include "ui/gfx/image/image_skia.h"
+
+class GURL;
 
 namespace content {
 class WebContents;
@@ -55,7 +59,11 @@
 
   content::WebContents* contents() { return contents_; }
 
-  base::string16 GetTitle() const;
+  const GURL& GetURL() const;
+  const base::string16& GetTitle() const;
+  gfx::ImageSkia GetFavicon() const;
+  TabNetworkState GetNetworkState() const;
+  bool IsCrashed() const;
 
   // Returns true if this tab data itself is counted as a enumerable item when
   // going through the view.
diff --git a/chrome/browser/ui/tabs/tab_strip_model_experimental.cc b/chrome/browser/ui/tabs/tab_strip_model_experimental.cc
index 59dcfdf..7a2b328 100644
--- a/chrome/browser/ui/tabs/tab_strip_model_experimental.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model_experimental.cc
@@ -295,8 +295,8 @@
     if (parent->type() == TabDataExperimental::Type::kSingle) {
       // Promote parent to hub-and-spoke.
       parent->set_type(TabDataExperimental::Type::kHubAndSpoke);
-      for (auto& observer : exp_observers_)
-        observer.TabChanged(parent, TabChangeType::kAll);
+      for (auto& exp_observer : exp_observers_)
+        exp_observer.TabChanged(parent, TabChangeType::kAll);
     }
 
     parent->children_.push_back(std::make_unique<TabDataExperimental>(
@@ -316,8 +316,8 @@
   // Need to do this if we start insering in the middle.
   // selection_model_.IncrementFrom(index);
 
-  for (auto& observer : exp_observers_)
-    observer.TabInserted(data, active);
+  for (auto& exp_observer : exp_observers_)
+    exp_observer.TabInserted(data, active);
   for (auto& observer : observers())
     observer.TabInsertedAt(this, contents, index, active);
 
@@ -520,8 +520,12 @@
     TabChangeType change_type) {
   ViewIterator found = FindViewIndex(view_index);
   DCHECK(found != end());
-  for (auto& observer : exp_observers_)
-    observer.TabChanged(&*found, change_type);
+
+  TabDataExperimental* data = &*found;
+  for (auto& observer : observers())
+    observer.TabChangedAt(data->contents(), view_index, change_type);
+  for (auto& exp_observer : exp_observers_)
+    exp_observer.TabChanged(data, change_type);
 }
 
 void TabStripModelExperimental::SetTabNeedsAttentionAt(int index,
@@ -545,7 +549,10 @@
 }
 
 bool TabStripModelExperimental::TabsAreLoading() const {
-  NOTIMPLEMENTED();
+  for (const auto& data : tabs_) {
+    if (data->contents() && data->contents()->IsLoading())
+      return true;
+  }
   return false;
 }
 
@@ -701,8 +708,8 @@
     uint32_t close_types) {
   TabDataExperimental* data = GetDataForWebContents(contents);
   DCHECK(data);
-  for (auto& observer : exp_observers_)
-    observer.TabClosing(data);
+  for (auto& exp_observer : exp_observers_)
+    exp_observer.TabClosing(data);
 }
 
 void TabStripModelExperimental::DetachWebContents(
@@ -738,8 +745,8 @@
         // Erasing the last child of a hub and spoke one converts it back to
         // a single.
         parent->set_type(TabDataExperimental::Type::kSingle);
-        for (auto& observer : exp_observers_)
-          observer.TabChanged(parent, TabChangeType::kAll);
+        for (auto& exp_observer : exp_observers_)
+          exp_observer.TabChanged(parent, TabChangeType::kAll);
       } else {
         DCHECK(parent->type() == TabDataExperimental::Type::kGroup);
         // TODO(brettw) remove group. Notifications might be tricky.
@@ -751,8 +758,8 @@
     data->set_type(TabDataExperimental::Type::kGroup);
     data->contents_ =
         nullptr;  // TODO(brettw) does this delete things properly?
-    for (auto& observer : exp_observers_)
-      observer.TabChanged(data, TabChangeType::kAll);
+    for (auto& exp_observer : exp_observers_)
+      exp_observer.TabChanged(data, TabChangeType::kAll);
   } else {
     // Just remove from tabs.
     tabs_.erase(tabs_.begin() + found.toplevel_index_);
@@ -868,8 +875,8 @@
     TabDataExperimental* old_data = GetDataForViewIndex(old_model.active());
     TabDataExperimental* new_data =
         GetDataForViewIndex(selection_model_.active());
-    for (auto& observer : exp_observers_)
-      observer.TabSelectionChanged(old_data, new_data);
+    for (auto& exp_observer : exp_observers_)
+      exp_observer.TabSelectionChanged(old_data, new_data);
 
     for (auto& observer : observers())
       observer.TabSelectionChanged(this, old_model);
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
index 6117f50..c5560c2 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/ash/ash_util.h"
+#include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_features.h"
@@ -1535,7 +1536,11 @@
   if (was_source_fullscreen_) {
     // In fullscreen mode it is only possible to get here if the source
     // was in "immersive fullscreen" mode, so toggle it back on.
-    GetAttachedBrowserWidget()->SetFullscreen(true);
+    BrowserView* browser_view = BrowserView::GetBrowserViewForNativeWindow(
+        GetAttachedBrowserWidget()->GetNativeWindow());
+    DCHECK(browser_view);
+    if (!browser_view->IsFullscreen())
+      chrome::ToggleFullscreenMode(browser_view->browser());
   }
 #endif
 }
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index c8ece54..dc7ac813 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -1026,6 +1026,70 @@
   EXPECT_TRUE(new_browser->window()->IsMaximized());
 }
 
+#if defined(OS_CHROMEOS)
+
+// This test makes sense only on Chrome OS where we have the immersive
+// fullscreen mode. The detached tab to a new browser window should remain in
+// immersive fullscreen mode.
+IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
+                       DetachToOwnWindowWhileInImmersiveFullscreenMode) {
+  // Toggle the immersive fullscreen mode for the initial browser.
+  chrome::ToggleFullscreenMode(browser());
+  ASSERT_TRUE(BrowserView::GetBrowserViewForBrowser(browser())
+                  ->immersive_mode_controller()
+                  ->IsEnabled());
+
+  // Add another tab.
+  AddTabAndResetBrowser(browser());
+  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+
+  // Move to the first tab and drag it enough so that it detaches.
+  gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
+  ASSERT_TRUE(PressInput(tab_0_center));
+  ASSERT_TRUE(DragInputToNotifyWhenDone(
+      tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
+      base::Bind(&DetachToOwnWindowStep2, this)));
+  if (input_source() == INPUT_SOURCE_MOUSE) {
+    ASSERT_TRUE(ReleaseMouseAsync());
+    QuitWhenNotDragging();
+  }
+
+  // Should no longer be dragging.
+  ASSERT_FALSE(tab_strip->IsDragSessionActive());
+  ASSERT_FALSE(TabDragController::IsActive());
+
+  // There should now be another browser.
+  ASSERT_EQ(2u, browser_list->size());
+  Browser* new_browser = browser_list->get(1);
+  ASSERT_TRUE(new_browser->window()->IsActive());
+  TabStripImpl* tab_strip2 = GetTabStripForBrowser(new_browser);
+  ASSERT_FALSE(tab_strip2->IsDragSessionActive());
+
+  EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
+  EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
+
+  // The bounds of the initial window should not have changed.
+  EXPECT_TRUE(browser()->window()->IsFullscreen());
+  ASSERT_TRUE(BrowserView::GetBrowserViewForBrowser(browser())
+                  ->immersive_mode_controller()
+                  ->IsEnabled());
+
+  EXPECT_FALSE(GetIsDragged(browser()));
+  EXPECT_FALSE(GetIsDragged(new_browser));
+  // After this both windows should still be manageable.
+  EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
+  EXPECT_TRUE(
+      IsWindowPositionManaged(new_browser->window()->GetNativeWindow()));
+
+  // The new browser should be in immersive fullscreen mode.
+  ASSERT_TRUE(BrowserView::GetBrowserViewForBrowser(new_browser)
+                  ->immersive_mode_controller()
+                  ->IsEnabled());
+  EXPECT_TRUE(new_browser->window()->IsFullscreen());
+}
+
+#endif
+
 // Deletes a tab being dragged before the user moved enough to start a drag.
 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
                        DeleteBeforeStartedDragging) {
diff --git a/chrome/browser/ui/views/tabs/tab_experimental.cc b/chrome/browser/ui/views/tabs/tab_experimental.cc
index 9724eeb..1ae3388 100644
--- a/chrome/browser/ui/views/tabs/tab_experimental.cc
+++ b/chrome/browser/ui/views/tabs/tab_experimental.cc
@@ -5,12 +5,18 @@
 #include "chrome/browser/ui/views/tabs/tab_experimental.h"
 
 #include "chrome/browser/themes/theme_properties.h"
+#include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_experimental.h"
 #include "chrome/browser/ui/view_ids.h"
 #include "chrome/browser/ui/views/tabs/tab_close_button.h"
+#include "chrome/browser/ui/views/tabs/tab_icon.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/grit/components_scaled_resources.h"
+#include "ui/base/l10n/l10n_util.h"
 #include "ui/base/theme_provider.h"
+#include "ui/gfx/favicon_size.h"
 #include "ui/views/border.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/masked_targeter_delegate.h"
@@ -18,6 +24,7 @@
 
 namespace {
 
+constexpr int kExtraLeftPaddingToBalanceCloseButtonPadding = 2;
 constexpr int kAfterTitleSpacing = 4;
 
 // Returns the width of the tab endcap in DIP.  More precisely, this is the
@@ -43,7 +50,10 @@
       model_(model),
       data_(data),
       type_(data->type()),
+      icon_(new TabIcon),
       title_(new views::Label),
+      close_button_(
+          new TabCloseButton(this, base::BindRepeating(&OnMouseEventInTab))),
       hover_controller_(this),
       paint_(this) {
   title_->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD);
@@ -51,12 +61,9 @@
   title_->SetHandlesTooltips(false);
   title_->SetAutoColorReadabilityEnabled(false);
   title_->SetText(CoreTabHelper::GetDefaultTitle());
-  AddChildView(title_);
 
-  // Unretained is safe here because this class outlives its close button, and
-  // the controller outlives this Tab.
-  close_button_ =
-      new TabCloseButton(this, base::BindRepeating(&OnMouseEventInTab));
+  AddChildView(icon_);
+  AddChildView(title_);
   AddChildView(close_button_);
 
   SetEventTargeter(std::make_unique<views::ViewTargeter>(this));
@@ -94,17 +101,39 @@
 }
 
 void TabExperimental::DataUpdated(TabChangeType change_type) {
+  // Need to do network state first since the tab title depends on it.
+  // TODO(brettw) should_hide_throbber param.
+  icon_->SetNetworkState(data_->GetNetworkState(), false);
+  // TODO(brettw) icon layer painting.
   if (change_type == TabChangeType::kLoadingOnly)
-    return;  // TODO(brettw) need to add throbber support.
+    return;
 
+  // Tab title.
+  base::string16 title = data_->GetTitle();
+  if (title.empty()) {
+    title = icon_->ShowingLoadingAnimation()
+                ? l10n_util::GetStringUTF16(IDS_TAB_LOADING_TITLE)
+                : CoreTabHelper::GetDefaultTitle();
+  } else {
+    Browser::FormatTitleForDisplay(&title);
+  }
   title_->SetText(data_->GetTitle());
+  // TODO(brettw) attention indicators when title not loading changes.
   if (change_type == TabChangeType::kTitleNotLoading)
     return;  // Don't need to update anything else.
 
+  icon_->SetIcon(data_->GetURL(), data_->GetFavicon());
+  icon_->SetIsCrashed(data_->IsCrashed());
   type_ = data_->type();
+
   SchedulePaint();
 }
 
+void TabExperimental::StepLoadingAnimation() {
+  icon_->StepLoadingAnimation();
+  // TODO(brettw) throbber layer for faster painting.
+}
+
 void TabExperimental::SetGroupLayoutParams(int first_child_begin_x) {
   first_child_begin_x_ = first_child_begin_x;
 }
@@ -147,7 +176,14 @@
   constexpr int kTitleSpacing = 6;
   const gfx::Rect bounds = GetContentsBounds();
 
-  int title_left = bounds.x() + kTitleSpacing;
+  // Icon.
+  int favicon_y = bounds.y() + (bounds.height() - gfx::kFaviconSize + 1) / 2;
+  gfx::Rect favicon_bounds(
+      bounds.x() + kExtraLeftPaddingToBalanceCloseButtonPadding, favicon_y,
+      icon_->GetPreferredSize().width(), bounds.height() - favicon_y);
+  icon_->SetBoundsRect(favicon_bounds);
+
+  int title_left = favicon_bounds.right() + kTitleSpacing;
   int title_right;
   if (first_child_begin_x_ >= 0)
     title_right = first_child_begin_x_;
@@ -175,8 +211,6 @@
 
 void TabExperimental::OnThemeChanged() {
   OnButtonColorMaybeChanged();
-  // TODO(brettw) favicons.
-  // favicon_ = gfx::ImageSkia();
 }
 
 bool TabExperimental::OnMousePressed(const ui::MouseEvent& event) {
diff --git a/chrome/browser/ui/views/tabs/tab_experimental.h b/chrome/browser/ui/views/tabs/tab_experimental.h
index 76f9b2f..dc69aa1 100644
--- a/chrome/browser/ui/views/tabs/tab_experimental.h
+++ b/chrome/browser/ui/views/tabs/tab_experimental.h
@@ -16,6 +16,7 @@
 
 class TabCloseButton;
 class TabDataExperimental;
+class TabIcon;
 class TabStripModelExperimental;
 
 namespace views {
@@ -62,6 +63,9 @@
   void SetSelected(bool selected);
   void DataUpdated(TabChangeType change_type);
 
+  // Redraws the loading animation if one is visible. Otherwise, no-op.
+  void StepLoadingAnimation();
+
   // Called for group types when layout is done to set the bounds of the
   // first tab. This is used to determine some painting parameters.
   void SetGroupLayoutParams(int first_child_begin_x);
@@ -105,8 +109,9 @@
   bool closing_ = false;
 
   // Non-owning child view pointers (owned by View hierarchy).
+  TabIcon* icon_;
   views::Label* title_;
-  TabCloseButton* close_button_ = nullptr;
+  TabCloseButton* close_button_;
 
   // Location of the first child tab. Negative indicates unused.
   int first_child_begin_x_ = -1;
diff --git a/chrome/browser/ui/views/tabs/tab_strip_experimental.cc b/chrome/browser/ui/views/tabs/tab_strip_experimental.cc
index 355b5596..879cffb4 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_experimental.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip_experimental.cc
@@ -353,7 +353,8 @@
 }
 
 void TabStripExperimental::UpdateLoadingAnimations() {
-  // controller_->UpdateLoadingAnimations();
+  for (const auto& tab : tabs_)
+    tab.second->StepLoadingAnimation();
 }
 
 gfx::Rect TabStripExperimental::GetNewTabButtonBounds() {
diff --git a/chrome/browser/ui/views/tabs/tab_strip_impl.cc b/chrome/browser/ui/views/tabs/tab_strip_impl.cc
index cb8add0..320e6184 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_impl.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip_impl.cc
@@ -72,6 +72,7 @@
 #include "ui/views/window/non_client_view.h"
 
 #if defined(OS_WIN)
+#include "base/win/windows_version.h"
 #include "ui/display/win/screen_win.h"
 #include "ui/gfx/win/hwnd_util.h"
 #include "ui/views/win/hwnd_util.h"
@@ -725,7 +726,7 @@
 #else
   static const SkAlpha kInactiveTabAlphaGlass = 200;
   static const SkAlpha kInactiveTabAlphaOpaque = 255;
-  const SkAlpha base_alpha = GetWidget()->ShouldWindowContentsBeTransparent()
+  const SkAlpha base_alpha = TitlebarBackgroundIsTransparent()
                                  ? kInactiveTabAlphaGlass
                                  : kInactiveTabAlphaOpaque;
 #endif  // OS_CHROMEOS
@@ -1020,7 +1021,7 @@
 int TabStripImpl::GetBackgroundResourceId(bool* custom_image) const {
   const ui::ThemeProvider* tp = GetThemeProvider();
 
-  if (GetWidget()->ShouldWindowContentsBeTransparent()) {
+  if (TitlebarBackgroundIsTransparent()) {
     const int kBackgroundIdGlass = IDR_THEME_TAB_BACKGROUND_V;
     *custom_image = tp->HasCustomImage(kBackgroundIdGlass);
     return kBackgroundIdGlass;
@@ -1411,6 +1412,16 @@
   return in_tab_close_;
 }
 
+bool TabStripImpl::TitlebarBackgroundIsTransparent() const {
+#if defined(OS_WIN)
+  // Windows 8+ uses transparent window contents (because the titlebar area is
+  // drawn by the system and not Chrome), but the actual titlebar is opaque.
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return false;
+#endif
+  return GetWidget()->ShouldWindowContentsBeTransparent();
+}
+
 void TabStripImpl::DoLayout() {
   last_layout_size_ = size();
 
diff --git a/chrome/browser/ui/views/tabs/tab_strip_impl.h b/chrome/browser/ui/views/tabs/tab_strip_impl.h
index b6db4c8..81f3fd4 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_impl.h
+++ b/chrome/browser/ui/views/tabs/tab_strip_impl.h
@@ -316,6 +316,9 @@
   // Returns whether the highlight button should be highlighted after a remove.
   bool ShouldHighlightCloseButtonAfterRemove();
 
+  // Returns whether the window background behind the tabstrip is transparent.
+  bool TitlebarBackgroundIsTransparent() const;
+
   // Invoked from Layout if the size changes or layout is really needed.
   void DoLayout();
 
diff --git a/chrome/browser/ui/webui/chromeos/internet_config_dialog.cc b/chrome/browser/ui/webui/chromeos/internet_config_dialog.cc
index 0426dd3..085857acd 100644
--- a/chrome/browser/ui/webui/chromeos/internet_config_dialog.cc
+++ b/chrome/browser/ui/webui/chromeos/internet_config_dialog.cc
@@ -37,6 +37,7 @@
       {"internetJoinType", IDS_SETTINGS_INTERNET_JOIN_TYPE},
       {"networkButtonConnect", IDS_SETTINGS_INTERNET_BUTTON_CONNECT},
       {"cancel", IDS_CANCEL},
+      {"close", IDS_CANCEL},
       {"save", IDS_SAVE},
   };
   for (const auto& entry : localized_strings)
diff --git a/chrome/browser/ui/webui/chromeos/internet_detail_dialog.cc b/chrome/browser/ui/webui/chromeos/internet_detail_dialog.cc
index f5f6ed3..327acb5 100644
--- a/chrome/browser/ui/webui/chromeos/internet_detail_dialog.cc
+++ b/chrome/browser/ui/webui/chromeos/internet_detail_dialog.cc
@@ -37,6 +37,8 @@
     const char* name;
     int id;
   } localized_strings[] = {
+      {"cancel", IDS_CANCEL},
+      {"close", IDS_CLOSE},
       {"networkButtonConnect", IDS_SETTINGS_INTERNET_BUTTON_CONNECT},
       {"networkButtonDisconnect", IDS_SETTINGS_INTERNET_BUTTON_DISCONNECT},
       {"networkIPAddress", IDS_SETTINGS_INTERNET_NETWORK_IP_ADDRESS},
diff --git a/chrome/browser/vr/BUILD.gn b/chrome/browser/vr/BUILD.gn
index 5927cd3..afadab0 100644
--- a/chrome/browser/vr/BUILD.gn
+++ b/chrome/browser/vr/BUILD.gn
@@ -82,6 +82,8 @@
     "elements/text.h",
     "elements/text_input.cc",
     "elements/text_input.h",
+    "elements/text_texture.cc",
+    "elements/text_texture.h",
     "elements/textured_element.cc",
     "elements/textured_element.h",
     "elements/throbber.cc",
diff --git a/chrome/browser/vr/elements/text.cc b/chrome/browser/vr/elements/text.cc
index 8795efed..a505f774 100644
--- a/chrome/browser/vr/elements/text.cc
+++ b/chrome/browser/vr/elements/text.cc
@@ -6,7 +6,7 @@
 
 #include "base/memory/ptr_util.h"
 #include "cc/paint/skia_paint_canvas.h"
-#include "chrome/browser/vr/elements/ui_texture.h"
+#include "chrome/browser/vr/elements/text_texture.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/font_list.h"
 #include "ui/gfx/geometry/rect.h"
@@ -15,49 +15,6 @@
 
 namespace vr {
 
-class TextTexture : public UiTexture {
- public:
-  explicit TextTexture(float font_height) : font_height_(font_height) {}
-  ~TextTexture() override {}
-
-  void SetText(const base::string16& text) { SetAndDirty(&text_, text); }
-
-  void SetColor(SkColor color) { SetAndDirty(&color_, color); }
-
-  void SetAlignment(TextAlignment alignment) {
-    SetAndDirty(&alignment_, alignment);
-  }
-
-  void SetMultiLine(bool multiline) { SetAndDirty(&multiline_, multiline); }
-
-  void SetTextWidth(float width) { SetAndDirty(&text_width_, width); }
-
-  int rendered_lines() { return rendered_lines_; }
-
- private:
-  gfx::Size GetPreferredTextureSize(int width) const override {
-    return gfx::Size(width, width);
-  }
-
-  gfx::SizeF GetDrawnSize() const override { return size_; }
-
-  void Draw(SkCanvas* sk_canvas, const gfx::Size& texture_size) override;
-
-  gfx::SizeF size_;
-  base::string16 text_;
-  // These dimensions are in meters.
-  float font_height_ = 0;
-  float text_width_ = 0;
-  TextAlignment alignment_ = kTextAlignmentCenter;
-  bool multiline_ = true;
-  SkColor color_ = SK_ColorBLACK;
-
-  // The number of lines generated in the last draw operation.
-  int rendered_lines_ = 0;
-
-  DISALLOW_COPY_AND_ASSIGN(TextTexture);
-};
-
 Text::Text(int maximum_width_pixels, float font_height_meters)
     : TexturedElement(maximum_width_pixels),
       texture_(base::MakeUnique<TextTexture>(font_height_meters)) {}
@@ -83,44 +40,11 @@
   texture_->SetTextWidth(size.width());
 }
 
-int Text::NumRenderedLinesForTest() const {
-  return texture_->rendered_lines();
-}
-
-UiTexture* Text::GetTexture() const {
+TextTexture* Text::GetTextureForTest() {
   return texture_.get();
 }
 
-void TextTexture::Draw(SkCanvas* sk_canvas, const gfx::Size& texture_size) {
-  cc::SkiaPaintCanvas paint_canvas(sk_canvas);
-  gfx::Canvas gfx_canvas(&paint_canvas, 1.0f);
-  gfx::Canvas* canvas = &gfx_canvas;
-
-  gfx::FontList fonts;
-  float pixels_per_meter = texture_size.width() / text_width_;
-  int pixel_font_height = static_cast<int>(font_height_ * pixels_per_meter);
-  GetDefaultFontList(pixel_font_height, text_, &fonts);
-  gfx::Rect text_bounds(texture_size.width(),
-                        multiline_ ? 0 : texture_size.height());
-
-  std::vector<std::unique_ptr<gfx::RenderText>> lines =
-      // TODO(vollick): if this subsumes all text, then we should probably move
-      // this function into this class.
-      PrepareDrawStringRect(
-          text_, fonts, color_, &text_bounds, alignment_,
-          multiline_ ? kWrappingBehaviorWrap : kWrappingBehaviorNoWrap);
-
-  // Draw the text.
-  for (auto& render_text : lines)
-    render_text->Draw(canvas);
-
-  // Note, there is no padding here whatsoever.
-  size_ = gfx::SizeF(text_bounds.size());
-
-  rendered_lines_ = lines.size();
-}
-
-UiTexture* Text::GetTextureForTest() const {
+UiTexture* Text::GetTexture() const {
   return texture_.get();
 }
 
diff --git a/chrome/browser/vr/elements/text.h b/chrome/browser/vr/elements/text.h
index f8a3891..7eea71f4 100644
--- a/chrome/browser/vr/elements/text.h
+++ b/chrome/browser/vr/elements/text.h
@@ -22,15 +22,12 @@
 
   void SetText(const base::string16& text);
   void SetColor(SkColor color);
-
   void SetTextAlignment(UiTexture::TextAlignment alignment);
   void SetMultiLine(bool multiline);
 
   void OnSetSize(gfx::SizeF size) override;
 
-  int NumRenderedLinesForTest() const;
-
-  UiTexture* GetTextureForTest() const;
+  TextTexture* GetTextureForTest();
 
  private:
   UiTexture* GetTexture() const override;
diff --git a/chrome/browser/vr/elements/text_texture.cc b/chrome/browser/vr/elements/text_texture.cc
new file mode 100644
index 0000000..b3fad1d
--- /dev/null
+++ b/chrome/browser/vr/elements/text_texture.cc
@@ -0,0 +1,80 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/vr/elements/text_texture.h"
+
+#include "base/memory/ptr_util.h"
+#include "cc/paint/skia_paint_canvas.h"
+#include "chrome/browser/vr/elements/ui_texture.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/font_list.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/render_text.h"
+
+namespace vr {
+
+TextTexture::TextTexture(float font_height) : font_height_(font_height) {}
+
+TextTexture::~TextTexture() {}
+
+void TextTexture::SetText(const base::string16& text) {
+  SetAndDirty(&text_, text);
+}
+
+void TextTexture::SetColor(SkColor color) {
+  SetAndDirty(&color_, color);
+}
+
+void TextTexture::SetAlignment(TextAlignment alignment) {
+  SetAndDirty(&alignment_, alignment);
+}
+
+void TextTexture::SetMultiLine(bool multiline) {
+  SetAndDirty(&multiline_, multiline);
+}
+
+void TextTexture::SetTextWidth(float width) {
+  SetAndDirty(&text_width_, width);
+}
+
+gfx::SizeF TextTexture::GetDrawnSize() const {
+  return size_;
+}
+
+std::vector<std::unique_ptr<gfx::RenderText>> TextTexture::LayOutText(
+    const gfx::Size& texture_size) {
+  gfx::FontList fonts;
+  float pixels_per_meter = texture_size.width() / text_width_;
+  int pixel_font_height = static_cast<int>(font_height_ * pixels_per_meter);
+  GetDefaultFontList(pixel_font_height, text_, &fonts);
+  gfx::Rect text_bounds(texture_size.width(), 0);
+
+  std::vector<std::unique_ptr<gfx::RenderText>> lines =
+      // TODO(vollick): if this subsumes all text, then we should probably move
+      // this function into this class.
+      PrepareDrawStringRect(
+          text_, fonts, color_, &text_bounds, alignment_,
+          multiline_ ? kWrappingBehaviorWrap : kWrappingBehaviorNoWrap);
+
+  // Note, there is no padding here whatsoever.
+  size_ = gfx::SizeF(text_bounds.size());
+
+  return lines;
+}
+
+gfx::Size TextTexture::GetPreferredTextureSize(int width) const {
+  return gfx::Size(width, width);
+}
+
+void TextTexture::Draw(SkCanvas* sk_canvas, const gfx::Size& texture_size) {
+  cc::SkiaPaintCanvas paint_canvas(sk_canvas);
+  gfx::Canvas gfx_canvas(&paint_canvas, 1.0f);
+  gfx::Canvas* canvas = &gfx_canvas;
+
+  auto lines = LayOutText(texture_size);
+  for (auto& render_text : lines)
+    render_text->Draw(canvas);
+}
+
+}  // namespace vr
diff --git a/chrome/browser/vr/elements/text_texture.h b/chrome/browser/vr/elements/text_texture.h
new file mode 100644
index 0000000..f0cdb50f
--- /dev/null
+++ b/chrome/browser/vr/elements/text_texture.h
@@ -0,0 +1,58 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_VR_ELEMENTS_TEXT_TEXTURE_H_
+#define CHROME_BROWSER_VR_ELEMENTS_TEXT_TEXTURE_H_
+
+#include <memory>
+
+#include "chrome/browser/vr/elements/textured_element.h"
+#include "chrome/browser/vr/elements/ui_texture.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+namespace gfx {
+class RenderText;
+}
+
+namespace vr {
+
+class TextTexture : public UiTexture {
+ public:
+  explicit TextTexture(float font_height);
+  ~TextTexture() override;
+
+  void SetText(const base::string16& text);
+  void SetColor(SkColor color);
+  void SetAlignment(TextAlignment alignment);
+  void SetMultiLine(bool multiline);
+  void SetTextWidth(float width);
+
+  gfx::SizeF GetDrawnSize() const override;
+
+  // This method does all text preparation for the element other than drawing to
+  // the texture. This allows for deeper unit testing of the Text element
+  // without having to mock canvases and simulate frame rendering. The state of
+  // the texture is modified here.
+  std::vector<std::unique_ptr<gfx::RenderText>> LayOutText(
+      const gfx::Size& texture_size);
+
+ private:
+  gfx::Size GetPreferredTextureSize(int width) const override;
+  void Draw(SkCanvas* sk_canvas, const gfx::Size& texture_size) override;
+
+  gfx::SizeF size_;
+  base::string16 text_;
+  // These dimensions are in meters.
+  float font_height_ = 0;
+  float text_width_ = 0;
+  TextAlignment alignment_ = kTextAlignmentCenter;
+  bool multiline_ = true;
+  SkColor color_ = SK_ColorBLACK;
+
+  DISALLOW_COPY_AND_ASSIGN(TextTexture);
+};
+
+}  // namespace vr
+
+#endif  // CHROME_BROWSER_VR_ELEMENTS_TEXT_TEXTURE_H_
diff --git a/chrome/browser/vr/elements/text_unittest.cc b/chrome/browser/vr/elements/text_unittest.cc
index 475634cf..976cb8b 100644
--- a/chrome/browser/vr/elements/text_unittest.cc
+++ b/chrome/browser/vr/elements/text_unittest.cc
@@ -6,48 +6,42 @@
 
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "cc/test/test_skcanvas.h"
-#include "chrome/browser/vr/ui_scene.h"
+#include "chrome/browser/vr/elements/text_texture.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/render_text.h"
 
 namespace vr {
 
 TEST(Text, MultiLine) {
-  UiScene scene;
-  testing::NiceMock<cc::MockCanvas> canvas;
-
   const float kInitialSize = 1.0f;
-  const int kPixelWidth = 512;
+  const gfx::Size texture_size({512, 512});
 
   // Create an initialize a text element with a long string.
-  auto text_instance = base::MakeUnique<Text>(kPixelWidth, 0.020);
-  Text* text = text_instance.get();
+  auto text = base::MakeUnique<Text>(texture_size.width(), 0.020);
   text->SetSize(kInitialSize, 0);
   text->SetText(base::UTF8ToUTF16(std::string(1000, 'x')));
-  text->SetInitializedForTesting();
-  scene.AddUiElement(kRoot, std::move(text_instance));
 
-  // Grab a pointer to the underlying texture to inspect it directly.
-  UiTexture* texture = text->GetTextureForTest();
-  auto texture_size = texture->GetPreferredTextureSize(kPixelWidth);
+  TextTexture* texture = text->GetTextureForTest();
 
   // Make sure we get multiple lines of rendered text from the string.
-  scene.OnBeginFrame(base::TimeTicks(), {0, 0, 0});
-  texture->DrawAndLayout(&canvas, texture_size);
-  int initial_num_lines = text->NumRenderedLinesForTest();
-  EXPECT_GT(initial_num_lines, 1);
+  auto layout = texture->LayOutText(texture_size);
+  size_t initial_num_lines = layout.size();
+  auto initial_size = texture->GetDrawnSize();
+  EXPECT_GT(initial_num_lines, 1u);
+  EXPECT_GT(initial_size.height(), 0.f);
 
-  // Reduce the field width, and ensure that the number of lines increases.
+  // Reduce the field width, and ensure that the number of lines increases along
+  // with the texture height.
   text->SetSize(kInitialSize / 2, 0);
-  scene.OnBeginFrame(base::TimeTicks(), {0, 0, 0});
-  texture->DrawAndLayout(&canvas, texture_size);
-  EXPECT_GT(text->NumRenderedLinesForTest(), initial_num_lines);
+  layout = texture->LayOutText(texture_size);
+  EXPECT_GT(layout.size(), initial_num_lines);
+  EXPECT_GT(texture->GetDrawnSize().height(), initial_size.height());
 
   // Enforce single-line rendering.
   text->SetMultiLine(false);
-  scene.OnBeginFrame(base::TimeTicks(), {0, 0, 0});
-  texture->DrawAndLayout(&canvas, texture_size);
-  EXPECT_EQ(1, text->NumRenderedLinesForTest());
+  layout = texture->LayOutText(texture_size);
+  EXPECT_EQ(layout.size(), 1u);
+  EXPECT_LT(texture->GetDrawnSize().height(), initial_size.height());
 }
 
 }  // namespace vr
diff --git a/chrome/browser/vr/elements/ui_texture.cc b/chrome/browser/vr/elements/ui_texture.cc
index fc05c24..8887357 100644
--- a/chrome/browser/vr/elements/ui_texture.cc
+++ b/chrome/browser/vr/elements/ui_texture.cc
@@ -69,9 +69,9 @@
   DCHECK(bounds);
 
   std::vector<std::unique_ptr<gfx::RenderText>> lines;
-  gfx::Rect rect(*bounds);
 
   if (wrapping_behavior == kWrappingBehaviorWrap) {
+    gfx::Rect rect(*bounds);
     std::vector<base::string16> strings;
     gfx::ElideRectangleText(text, font_list, bounds->width(),
                             bounds->height() ? bounds->height() : INT_MAX,
@@ -108,18 +108,13 @@
         CreateConfiguredRenderText(text, font_list, color, text_alignment);
     if (bounds->width() != 0)
       render_text->SetElideBehavior(gfx::TRUNCATE);
-    else
-      rect.set_width(INT_MAX);
 
-    render_text->SetDisplayRect(rect);
+    if (bounds->width() == 0)
+      bounds->set_width(render_text->GetStringSize().width());
+    if (bounds->height() == 0)
+      bounds->set_height(render_text->GetStringSize().height());
 
-    if (bounds->width() == 0) {
-      int text_width = render_text->GetStringSize().width();
-      bounds->set_width(text_width);
-      rect.set_width(text_width);
-      render_text->SetDisplayRect(rect);
-    }
-
+    render_text->SetDisplayRect(*bounds);
     lines.push_back(std::move(render_text));
   }
   return lines;
diff --git a/chrome/browser/vr/metrics_helper.cc b/chrome/browser/vr/metrics_helper.cc
index a2b5fbd6..0fd8471a 100644
--- a/chrome/browser/vr/metrics_helper.cc
+++ b/chrome/browser/vr/metrics_helper.cc
@@ -13,22 +13,31 @@
 
 namespace {
 
-constexpr char kStatusVr[] = "VR.AssetsComponent.Status.OnEnter.VR";
+constexpr char kStatusVr[] = "VR.Component.Assets.Status.OnEnter.AllVR";
 constexpr char kStatusVrBrowsing[] =
-    "VR.AssetsComponent.Status.OnEnter.VRBrowsing";
-constexpr char kStatusWebVr[] = "VR.AssetsComponent.Status.OnEnter.WebVR";
+    "VR.Component.Assets.Status.OnEnter.VRBrowsing";
+constexpr char kStatusWebVr[] =
+    "VR.Component.Assets.Status.OnEnter.WebVRPresentation";
 constexpr char kLatencyVrBrowsing[] =
-    "VR.AssetsComponent.ReadyLatency.OnEnter.VRBrowsing";
+    "VR.Component.Assets.DurationUntilReady.OnEnter.VRBrowsing";
 constexpr char kLatencyWebVr[] =
-    "VR.AssetsComponent.ReadyLatency.OnEnter.WebVR";
-constexpr char kComponentUpdateStatus[] = "VR.AssetsComponent.UpdateStatus";
-constexpr char kAssetsLoadStatus[] = "VR.AssetsComponent.LoadStatus";
-constexpr char kDataConnectionRegisterComponent[] =
-    "VR.DataConnection.OnRegisterAssetsComponent";
-constexpr char kDataConnectionVr[] = "VR.DataConnection.OnEnter.VR";
-constexpr char kDataConnectionVrBrowsing[] =
-    "VR.DataConnection.OnEnter.VRBrowsing";
-constexpr char kDataConnectionWebVr[] = "VR.DataConnection.OnEnter.WebVR";
+    "VR.Component.Assets.DurationUntilReady.OnEnter.WebVRPresentation";
+constexpr char kLatencyLaunchBrowser[] =
+    "VR.Component.Assets.DurationUntilReady.OnChromeStart";
+// TODO(tiborg): Rename VRAssetsComponentStatus and VRAssetsLoadStatus in
+// enums.xml and consider merging them.
+constexpr char kComponentUpdateStatus[] =
+    "VR.Component.Assets.VersionAndStatus.OnUpdate";
+constexpr char kAssetsLoadStatus[] =
+    "VR.Component.Assets.VersionAndStatus.OnLoad";
+constexpr char kNetworkConnectionTypeRegisterComponent[] =
+    "VR.NetworkConnectionType.OnRegisterComponent";
+constexpr char kNetworkConnectionTypeVr[] =
+    "VR.NetworkConnectionType.OnEnter.AllVR";
+constexpr char kNetworkConnectionTypeVrBrowsing[] =
+    "VR.NetworkConnectionType.OnEnter.VRBrowsing";
+constexpr char kNetworkConnectionTypeWebVr[] =
+    "VR.NetworkConnectionType.OnEnter.WebVRPresentation";
 
 const auto kMinLatency = base::TimeDelta::FromMilliseconds(500);
 const auto kMaxLatency = base::TimeDelta::FromHours(1);
@@ -85,17 +94,17 @@
   switch (mode) {
     case Mode::kVr:
       UMA_HISTOGRAM_ENUMERATION(
-          kDataConnectionVr, type,
+          kNetworkConnectionTypeVr, type,
           net::NetworkChangeNotifier::ConnectionType::CONNECTION_LAST + 1);
       return;
     case Mode::kVrBrowsing:
       UMA_HISTOGRAM_ENUMERATION(
-          kDataConnectionVrBrowsing, type,
+          kNetworkConnectionTypeVrBrowsing, type,
           net::NetworkChangeNotifier::ConnectionType::CONNECTION_LAST + 1);
       return;
     case Mode::kWebVr:
       UMA_HISTOGRAM_ENUMERATION(
-          kDataConnectionWebVr, type,
+          kNetworkConnectionTypeWebVr, type,
           net::NetworkChangeNotifier::ConnectionType::CONNECTION_LAST + 1);
       return;
     default:
@@ -132,6 +141,15 @@
   LogLatencyIfWaited(Mode::kVrBrowsing, now);
   LogLatencyIfWaited(Mode::kWebVr, now);
   OnComponentUpdated(AssetsComponentUpdateStatus::kSuccess, version);
+
+  if (logged_ready_duration_on_chrome_start_) {
+    return;
+  }
+  DCHECK(chrome_start_time_);
+  auto ready_duration = now - *chrome_start_time_;
+  UMA_HISTOGRAM_CUSTOM_TIMES(kLatencyLaunchBrowser, ready_duration, kMinLatency,
+                             kMaxLatency, kLatencyBucketCount);
+  logged_ready_duration_on_chrome_start_ = true;
 }
 
 void MetricsHelper::OnEnter(Mode mode) {
@@ -153,7 +171,7 @@
 
 void MetricsHelper::OnRegisteredComponent() {
   UMA_HISTOGRAM_ENUMERATION(
-      kDataConnectionRegisterComponent,
+      kNetworkConnectionTypeRegisterComponent,
       net::NetworkChangeNotifier::GetConnectionType(),
       net::NetworkChangeNotifier::ConnectionType::CONNECTION_LAST + 1);
 }
@@ -175,6 +193,12 @@
       EncodeVersionStatus(component_version, static_cast<int>(status)));
 }
 
+void MetricsHelper::OnChromeStarted() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(!chrome_start_time_);
+  chrome_start_time_ = base::Time::Now();
+}
+
 base::Optional<base::Time>& MetricsHelper::GetEnterTime(Mode mode) {
   switch (mode) {
     case Mode::kVr:
diff --git a/chrome/browser/vr/metrics_helper.h b/chrome/browser/vr/metrics_helper.h
index c27f1a88..3a23309 100644
--- a/chrome/browser/vr/metrics_helper.h
+++ b/chrome/browser/vr/metrics_helper.h
@@ -35,6 +35,7 @@
                           const base::Optional<base::Version>& version);
   void OnAssetsLoaded(AssetsLoadStatus status,
                       const base::Version& component_version);
+  void OnChromeStarted();
 
  private:
   base::Optional<base::Time>& GetEnterTime(Mode mode);
@@ -43,6 +44,8 @@
   base::Optional<base::Time> enter_vr_time_;
   base::Optional<base::Time> enter_vr_browsing_time_;
   base::Optional<base::Time> enter_web_vr_time_;
+  base::Optional<base::Time> chrome_start_time_;
+  bool logged_ready_duration_on_chrome_start_ = false;
   bool component_ready_ = false;
 
   SEQUENCE_CHECKER(sequence_checker_);
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index fb5fc44..4a9ff34 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -33,7 +33,7 @@
   "UnsafelyTreatInsecureOriginAsSecure": {
     "os": ["win", "linux", "max", "chromeos", "android"],
     "test_policy": { "UnsafelyTreatInsecureOriginAsSecure": ["http://example.com/"] },
-    "pref_mappings": [ { "pref": "unsafely_treat_insecure_origin_as_securex" } ]
+    "pref_mappings": [ { "pref": "unsafely_treat_insecure_origin_as_secure" } ]
   },
 
   "HomepageLocation": {
diff --git a/components/arc/connection_holder.h b/components/arc/connection_holder.h
index 72cd647..4c6fb0d 100644
--- a/components/arc/connection_holder.h
+++ b/components/arc/connection_holder.h
@@ -107,8 +107,10 @@
   explicit ConnectionHolderImpl(ConnectionNotifier* connection_notifier)
       : connection_notifier_(connection_notifier), weak_ptr_factory_(this) {}
 
-  InstanceType* instance() { return instance_; }
-  uint32_t instance_version() const { return instance_version_; }
+  InstanceType* instance() { return IsConnected() ? instance_ : nullptr; }
+  uint32_t instance_version() const {
+    return IsConnected() ? instance_version_ : 0;
+  }
 
   // Returns true if |binding_| is set.
   bool IsConnected() const { return binding_.get(); }
@@ -130,8 +132,6 @@
   // Sets (or resets if |instance| is nullptr) the instance.
   void SetInstance(InstanceType* instance,
                    uint32_t version = InstanceType::version_) {
-    DCHECK(instance == nullptr || instance_ == nullptr);
-
     // Note: This can be called with nullptr even if |instance_| is still
     // nullptr for just in case clean up purpose. No-op in such a case.
     if (instance == instance_)
@@ -143,29 +143,31 @@
   }
 
  private:
-  // Called when |instance_| or |host_| is updated from null to non-null or
-  // from non-null to null.
+  // Called when |instance_| or |host_| are updated.
   void OnChanged() {
-    if (instance_ && host_) {
-      // When both get ready, start connection.
-      // TODO(crbug.com/750563): Fix the race issue.
-      binding_ = std::make_unique<mojo::Binding<HostType>>(host_);
-      mojo::InterfacePtr<HostType> host_proxy;
-      binding_->Bind(mojo::MakeRequest(&host_proxy));
-      // Note: because the callback will be destroyed with |binding_|,
-      // base::Unretained() can be safely used.
-      binding_->set_connection_error_handler(base::BindOnce(
-          &mojo::Binding<HostType>::Close, base::Unretained(binding_.get())));
-
-      // Call the appropriate version of Init().
-      CallInstanceInit<InstanceType>(std::move(host_proxy),
-                                     HasInitDeprecated<InstanceType>());
-    } else if (binding_.get()) {
-      // Otherwise, the connection is closed. If it was connected,
-      // reset the host binding and notify.
-      binding_.reset();
-      connection_notifier_->NotifyConnectionClosed();
+    // Cancel any in-flight connection requests. This also prevents Observers
+    // from being notified of a spurious OnConnectionClosed() before an
+    // OnConnectionReady() event.
+    weak_ptr_factory_.InvalidateWeakPtrs();
+    if (binding_.get()) {
+      // Regardless of what has changed, the old connection is now stale. Reset
+      // the current binding and notify any listeners. Since |binding_| is set
+      // just before the OnConnectionReady() event, we never notify observers of
+      // OnConnectionClosed() without seeing the former event first.
+      if (instance_ && host_)
+        LOG(ERROR) << "Unbinding instance of a stale connection";
+      OnConnectionClosed();
     }
+    if (!instance_ || !host_)
+      return;
+    // When both the instance and host are ready, start connection.
+    // TODO(crbug.com/750563): Fix the race issue.
+    auto binding = std::make_unique<mojo::Binding<HostType>>(host_);
+    mojo::InterfacePtr<HostType> host_proxy;
+    binding->Bind(mojo::MakeRequest(&host_proxy));
+    // Call the appropriate version of Init().
+    CallInstanceInit<InstanceType>(std::move(host_proxy), std::move(binding),
+                                   HasInitDeprecated<InstanceType>());
   }
 
   // Dispatches the correct version of Init(). The template type is needed
@@ -174,52 +176,84 @@
   // std::false_type) refers to whether InstanceType::DeprecatedInit() exists.
   template <class T>
   typename std::enable_if<CountInitArgs<T>::value == 2, void>::type
-  CallInstanceInit(mojo::InterfacePtr<HostType> host_proxy, std::true_type) {
+  CallInstanceInit(mojo::InterfacePtr<HostType> host_proxy,
+                   std::unique_ptr<mojo::Binding<HostType>> binding,
+                   std::true_type) {
     if (instance_version_ < InstanceType::kInitMinVersion) {
       // The instance is too old to know about the new Init() version. For now,
       // call the deprecated version for backwards-compatibility.
       // TODO(crbug.com/750563): Deprecate this version.
-      CallInstanceInitDeprecated(std::move(host_proxy),
+      CallInstanceInitDeprecated(std::move(host_proxy), std::move(binding),
                                  HasInitDeprecated<InstanceType>());
       return;
     }
 
-    instance_->Init(std::move(host_proxy),
-                    base::BindOnce(&ConnectionHolderImpl::OnConnectionReady,
-                                   weak_ptr_factory_.GetWeakPtr()));
+    instance_->Init(
+        std::move(host_proxy),
+        base::BindOnce(&ConnectionHolderImpl::OnConnectionReady,
+                       weak_ptr_factory_.GetWeakPtr(), std::move(binding)));
   }
 
   template <class T>
   typename std::enable_if<CountInitArgs<T>::value == 2, void>::type
-  CallInstanceInit(mojo::InterfacePtr<HostType> host_proxy, std::false_type) {
-    instance_->Init(std::move(host_proxy),
-                    base::BindOnce(&ConnectionHolderImpl::OnConnectionReady,
-                                   weak_ptr_factory_.GetWeakPtr()));
+  CallInstanceInit(mojo::InterfacePtr<HostType> host_proxy,
+                   std::unique_ptr<mojo::Binding<HostType>> binding,
+                   std::false_type) {
+    instance_->Init(
+        std::move(host_proxy),
+        base::BindOnce(&ConnectionHolderImpl::OnConnectionReady,
+                       weak_ptr_factory_.GetWeakPtr(), std::move(binding)));
   }
 
   // TODO(crbug.com/750563): Deprecate this version.
   template <class T>
   typename std::enable_if<CountInitArgs<T>::value == 1, void>::type
-  CallInstanceInit(mojo::InterfacePtr<HostType> host_proxy, ...) {
+  CallInstanceInit(mojo::InterfacePtr<HostType> host_proxy,
+                   std::unique_ptr<mojo::Binding<HostType>> binding,
+                   ...) {
     instance_->Init(std::move(host_proxy));
-    OnConnectionReady();
+    OnConnectionReady(std::move(binding));
   }
 
-  void CallInstanceInitDeprecated(mojo::InterfacePtr<HostType> host_proxy,
-                                  std::true_type) {
+  void CallInstanceInitDeprecated(
+      mojo::InterfacePtr<HostType> host_proxy,
+      std::unique_ptr<mojo::Binding<HostType>> binding,
+      std::true_type) {
     instance_->InitDeprecated(std::move(host_proxy));
-    OnConnectionReady();
+    OnConnectionReady(std::move(binding));
   }
 
-  void CallInstanceInitDeprecated(mojo::InterfacePtr<HostType> host_proxy,
-                                  std::false_type) {
+  void CallInstanceInitDeprecated(
+      mojo::InterfacePtr<HostType> host_proxy,
+      std::unique_ptr<mojo::Binding<HostType>> binding,
+      std::false_type) {
     // If InitDeprecated does not exists, ARC container must support
     // Init() with callback, already. Thus, this should not be called.
     NOTREACHED();
   }
 
+  // Resets the binding and notifies all the observers that the connection is
+  // closed.
+  void OnConnectionClosed() {
+    DCHECK(binding_);
+    binding_.reset();
+    connection_notifier_->NotifyConnectionClosed();
+  }
+
   // Notifies all the observers that the connection is ready.
-  void OnConnectionReady() { connection_notifier_->NotifyConnectionReady(); }
+  void OnConnectionReady(std::unique_ptr<mojo::Binding<HostType>> binding) {
+    DCHECK(!binding_);
+    // Now that we can finally commit to this connection and will deliver the
+    // OnConnectionReady() event, set the connection error handler to notify
+    // Observers of connection closures.
+    // Note: because the callback will be destroyed with |binding_|,
+    // base::Unretained() can be safely used.
+    binding->set_connection_error_handler(base::BindOnce(
+        &ConnectionHolderImpl::OnConnectionClosed, base::Unretained(this)));
+
+    binding_ = std::move(binding);
+    connection_notifier_->NotifyConnectionReady();
+  }
 
   // This class does not have ownership. The pointers should be managed by the
   // caller.
diff --git a/components/arc/test/connection_holder_util.h b/components/arc/test/connection_holder_util.h
index 53fa7a6..e7515c0 100644
--- a/components/arc/test/connection_holder_util.h
+++ b/components/arc/test/connection_holder_util.h
@@ -21,8 +21,8 @@
 class ReadinessObserver
     : public ConnectionHolder<InstanceType, HostType>::Observer {
  public:
-  explicit ReadinessObserver(ConnectionHolder<InstanceType, HostType>* holder,
-                             base::OnceClosure closure)
+  ReadinessObserver(ConnectionHolder<InstanceType, HostType>* holder,
+                    base::OnceClosure closure)
       : holder_(holder), closure_(std::move(closure)) {
     holder_->AddObserver(this);
   }
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
index 312d5bf..a1e29f1 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
@@ -25,7 +25,9 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/time/default_tick_clock.h"
+#include "build/build_config.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h"
+#include "components/data_reduction_proxy/core/browser/network_properties_manager.h"
 #include "components/data_reduction_proxy/core/browser/warmup_url_fetcher.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_config_values.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.h"
@@ -37,6 +39,7 @@
 #include "net/base/host_port_pair.h"
 #include "net/base/load_flags.h"
 #include "net/base/network_change_notifier.h"
+#include "net/base/network_interfaces.h"
 #include "net/log/net_log_source_type.h"
 #include "net/nqe/effective_connection_type.h"
 #include "net/proxy/proxy_server.h"
@@ -72,7 +75,7 @@
 // name in metrics/histograms/histograms.xml.
 enum DataReductionProxyNetworkChangeEvent {
   // The client IP address changed.
-  IP_CHANGED = 0,
+  DEPRECATED_IP_CHANGED = 0,
   // [Deprecated] Proxy is disabled because a VPN is running.
   DEPRECATED_DISABLED_ON_VPN = 1,
   // There was a network change.
@@ -135,6 +138,7 @@
       configurator_(configurator),
       event_creator_(event_creator),
       connection_type_(net::NetworkChangeNotifier::GetConnectionType()),
+      network_properties_manager_(nullptr),
       weak_factory_(this) {
   DCHECK(io_task_runner_);
   DCHECK(configurator);
@@ -144,7 +148,6 @@
 }
 
 DataReductionProxyConfig::~DataReductionProxyConfig() {
-  net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
   net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
 }
 
@@ -152,8 +155,11 @@
     const scoped_refptr<net::URLRequestContextGetter>&
         basic_url_request_context_getter,
     const scoped_refptr<net::URLRequestContextGetter>&
-        url_request_context_getter) {
+        url_request_context_getter,
+    NetworkPropertiesManager* manager) {
   DCHECK(thread_checker_.CalledOnValidThread());
+  network_properties_manager_ = manager;
+  DCHECK(network_properties_manager_);
 
   secure_proxy_checker_.reset(
       new SecureProxyChecker(basic_url_request_context_getter));
@@ -161,7 +167,6 @@
 
   if (ShouldAddDefaultProxyBypassRules())
     AddDefaultProxyBypassRules();
-  net::NetworkChangeNotifier::AddIPAddressObserver(this);
   net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
 }
 
@@ -181,9 +186,10 @@
 
   if (enabled_by_user_ && !params::IsIncludedInHoldbackFieldTrial() &&
       !config_values_->proxies_for_http().empty()) {
-    configurator_->Enable(!network_properties_manager_.IsSecureProxyAllowed(),
-                          !network_properties_manager_.IsInsecureProxyAllowed(),
-                          config_values_->proxies_for_http());
+    configurator_->Enable(
+        !network_properties_manager_->IsSecureProxyAllowed(),
+        !network_properties_manager_->IsInsecureProxyAllowed(),
+        config_values_->proxies_for_http());
   } else {
     configurator_->Disable();
   }
@@ -350,6 +356,8 @@
 void DataReductionProxyConfig::SetProxyConfig(bool enabled, bool at_startup) {
   DCHECK(thread_checker_.CalledOnValidThread());
   enabled_by_user_ = enabled;
+  network_properties_manager_->OnChangeInNetworkID(GetCurrentNetworkID());
+
   ReloadConfig();
 
   if (enabled_by_user_) {
@@ -372,9 +380,9 @@
   bool is_captive_portal = GetIsCaptivePortal();
   UMA_HISTOGRAM_BOOLEAN("DataReductionProxy.CaptivePortalDetected.Platform",
                         is_captive_portal);
-  if (is_captive_portal == network_properties_manager_.IsCaptivePortal())
+  if (is_captive_portal == network_properties_manager_->IsCaptivePortal())
     return;
-  network_properties_manager_.SetIsCaptivePortal(is_captive_portal);
+  network_properties_manager_->SetIsCaptivePortal(is_captive_portal);
   ReloadConfig();
 }
 
@@ -392,12 +400,17 @@
     bool secure_proxies_allowed,
     bool insecure_proxies_allowed) {
   enabled_by_user_ = enabled;
-  network_properties_manager_.SetIsSecureProxyDisallowedByCarrier(
+  network_properties_manager_->SetIsSecureProxyDisallowedByCarrier(
       !secure_proxies_allowed);
-  network_properties_manager_.SetHasWarmupURLProbeFailed(
+  network_properties_manager_->SetHasWarmupURLProbeFailed(
       false, !insecure_proxies_allowed);
 }
 
+void DataReductionProxyConfig::SetNetworkPropertiesManagerForTesting(
+    NetworkPropertiesManager* manager) {
+  network_properties_manager_ = manager;
+}
+
 void DataReductionProxyConfig::HandleSecureProxyCheckResponse(
     const std::string& response,
     const net::URLRequestStatus& status,
@@ -422,29 +435,29 @@
   }
 
   bool secure_proxy_allowed_past =
-      !network_properties_manager_.IsSecureProxyDisallowedByCarrier();
-  network_properties_manager_.SetIsSecureProxyDisallowedByCarrier(
+      !network_properties_manager_->IsSecureProxyDisallowedByCarrier();
+  network_properties_manager_->SetIsSecureProxyDisallowedByCarrier(
       !success_response);
   if (!enabled_by_user_)
     return;
 
-  if (!network_properties_manager_.IsSecureProxyDisallowedByCarrier() !=
+  if (!network_properties_manager_->IsSecureProxyDisallowedByCarrier() !=
       secure_proxy_allowed_past)
     ReloadConfig();
 
   // Record the result.
   if (secure_proxy_allowed_past &&
-      !network_properties_manager_.IsSecureProxyDisallowedByCarrier()) {
+      !network_properties_manager_->IsSecureProxyDisallowedByCarrier()) {
     RecordSecureProxyCheckFetchResult(SUCCEEDED_PROXY_ALREADY_ENABLED);
   } else if (secure_proxy_allowed_past &&
-             network_properties_manager_.IsSecureProxyDisallowedByCarrier()) {
+             network_properties_manager_->IsSecureProxyDisallowedByCarrier()) {
     RecordSecureProxyCheckFetchResult(FAILED_PROXY_DISABLED);
   } else if (!secure_proxy_allowed_past &&
-             !network_properties_manager_.IsSecureProxyDisallowedByCarrier()) {
+             !network_properties_manager_->IsSecureProxyDisallowedByCarrier()) {
     RecordSecureProxyCheckFetchResult(SUCCEEDED_PROXY_ENABLED);
   } else {
     DCHECK(!secure_proxy_allowed_past &&
-           network_properties_manager_.IsSecureProxyDisallowedByCarrier());
+           network_properties_manager_->IsSecureProxyDisallowedByCarrier());
     RecordSecureProxyCheckFetchResult(FAILED_PROXY_ALREADY_DISABLED);
   }
 }
@@ -455,16 +468,13 @@
 
   connection_type_ = type;
   RecordNetworkChangeEvent(NETWORK_CHANGED);
+  network_properties_manager_->OnChangeInNetworkID(GetCurrentNetworkID());
+
+  ReloadConfig();
 
   FetchWarmupURL();
-}
-
-void DataReductionProxyConfig::OnIPAddressChanged() {
-  DCHECK(thread_checker_.CalledOnValidThread());
 
   if (enabled_by_user_) {
-    RecordNetworkChangeEvent(IP_CHANGED);
-
     HandleCaptivePortal();
     // It is safe to use base::Unretained here, since it gets executed
     // synchronously on the IO thread, and |this| outlives
@@ -626,11 +636,11 @@
 void DataReductionProxyConfig::OnInsecureProxyWarmupURLProbeStatusChange(
     bool insecure_proxies_allowed) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  bool old_status = network_properties_manager_.IsInsecureProxyAllowed();
-  network_properties_manager_.SetHasWarmupURLProbeFailed(
+  bool old_status = network_properties_manager_->IsInsecureProxyAllowed();
+  network_properties_manager_->SetHasWarmupURLProbeFailed(
       false, !insecure_proxies_allowed);
 
-  if (old_status == network_properties_manager_.IsInsecureProxyAllowed())
+  if (old_status == network_properties_manager_->IsInsecureProxyAllowed())
     return;
   ReloadConfig();
 }
@@ -639,19 +649,19 @@
   if (!enabled_by_user_ || config_values_->proxies_for_http().empty())
     return net::ProxyConfig::CreateDirect();
   return configurator_->CreateProxyConfig(
-      !network_properties_manager_.IsSecureProxyAllowed(),
-      !network_properties_manager_.IsInsecureProxyAllowed(),
+      !network_properties_manager_->IsSecureProxyAllowed(),
+      !network_properties_manager_->IsInsecureProxyAllowed(),
       config_values_->proxies_for_http());
 }
 
 bool DataReductionProxyConfig::secure_proxy_allowed() const {
   DCHECK(thread_checker_.CalledOnValidThread());
-  return network_properties_manager_.IsSecureProxyAllowed();
+  return network_properties_manager_->IsSecureProxyAllowed();
 }
 
 bool DataReductionProxyConfig::insecure_proxies_allowed() const {
   DCHECK(thread_checker_.CalledOnValidThread());
-  return network_properties_manager_.IsInsecureProxyAllowed();
+  return network_properties_manager_->IsInsecureProxyAllowed();
 }
 
 std::vector<DataReductionProxyServer>
@@ -664,4 +674,52 @@
   return config_values_->proxies_for_http();
 }
 
+std::string DataReductionProxyConfig::GetCurrentNetworkID() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // It is possible that the connection type changed between when
+  // GetConnectionType() was called and when the API to determine the
+  // network name was called. Check if that happened and retry until the
+  // connection type stabilizes. This is an imperfect solution but should
+  // capture majority of cases, and should not significantly affect estimates
+  // (that are approximate to begin with).
+
+  while (true) {
+    net::NetworkChangeNotifier::ConnectionType connection_type =
+        net::NetworkChangeNotifier::GetConnectionType();
+    std::string ssid_mccmnc;
+
+    switch (connection_type) {
+      case net::NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN:
+      case net::NetworkChangeNotifier::ConnectionType::CONNECTION_NONE:
+      case net::NetworkChangeNotifier::ConnectionType::CONNECTION_BLUETOOTH:
+      case net::NetworkChangeNotifier::ConnectionType::CONNECTION_ETHERNET:
+        break;
+      case net::NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI:
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_WIN)
+        ssid_mccmnc = net::GetWifiSSID();
+#endif
+        break;
+      case net::NetworkChangeNotifier::ConnectionType::CONNECTION_2G:
+      case net::NetworkChangeNotifier::ConnectionType::CONNECTION_3G:
+      case net::NetworkChangeNotifier::ConnectionType::CONNECTION_4G:
+#if defined(OS_ANDROID)
+        ssid_mccmnc = net::android::GetTelephonyNetworkOperator();
+#endif
+        break;
+    }
+
+    if (connection_type == net::NetworkChangeNotifier::GetConnectionType()) {
+      if (connection_type >= net::NetworkChangeNotifier::CONNECTION_2G &&
+          connection_type <= net::NetworkChangeNotifier::CONNECTION_4G) {
+        // No need to differentiate cellular connections by the exact
+        // connection type.
+        return "cell," + ssid_mccmnc;
+      }
+      return base::IntToString(connection_type) + "," + ssid_mccmnc;
+    }
+  }
+  NOTREACHED();
+}
+
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h
index 2a6d182..5a3f59e1 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h
@@ -18,7 +18,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread_checker.h"
 #include "base/time/time.h"
-#include "components/data_reduction_proxy/core/browser/network_properties_manager.h"
 #include "components/data_reduction_proxy/core/browser/secure_proxy_checker.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_server.h"
 #include "components/previews/core/previews_experiments.h"
@@ -48,6 +47,7 @@
 class DataReductionProxyConfigValues;
 class DataReductionProxyConfigurator;
 class DataReductionProxyEventCreator;
+class NetworkPropertiesManager;
 class SecureProxyChecker;
 class WarmupURLFetcher;
 struct DataReductionProxyTypeInfo;
@@ -84,8 +84,7 @@
 // This object lives on the IO thread and all of its methods are expected to be
 // called from there.
 class DataReductionProxyConfig
-    : public net::NetworkChangeNotifier::IPAddressObserver,
-      public net::NetworkChangeNotifier::NetworkChangeObserver {
+    : public net::NetworkChangeNotifier::NetworkChangeObserver {
  public:
   // The caller must ensure that all parameters remain alive for the lifetime
   // of the |DataReductionProxyConfig| instance, with the exception of
@@ -110,7 +109,8 @@
   void InitializeOnIOThread(const scoped_refptr<net::URLRequestContextGetter>&
                                 basic_url_request_context_getter,
                             const scoped_refptr<net::URLRequestContextGetter>&
-                                url_request_context_getter);
+                                url_request_context_getter,
+                            NetworkPropertiesManager* manager);
 
   // Sets the proxy configs, enabling or disabling the proxy according to
   // the value of |enabled|. If |restricted| is true, only enable the fallback
@@ -200,6 +200,8 @@
   // Called when a new client config has been fetched.
   void OnNewClientConfigFetched();
 
+  void SetNetworkPropertiesManagerForTesting(NetworkPropertiesManager* manager);
+
  protected:
   // Should be called when there is a change in the status of the availability
   // of the insecure data saver proxies triggered due to warmup URL.
@@ -216,6 +218,9 @@
   // testing.
   virtual bool ShouldAddDefaultProxyBypassRules() const;
 
+  // Returns the ID of the current network by calling the platform APIs.
+  virtual std::string GetCurrentNetworkID() const;
+
  private:
   friend class MockDataReductionProxyConfig;
   friend class TestDataReductionProxyConfig;
@@ -243,9 +248,6 @@
   // |configurator_|. Used by the Data Reduction Proxy config service client.
   void ReloadConfig();
 
-  // NetworkChangeNotifier::IPAddressObserver implementation:
-  void OnIPAddressChanged() override;
-
   // NetworkChangeNotifier::NetworkChangeObserver implementation:
   void OnNetworkChanged(
       net::NetworkChangeNotifier::ConnectionType type) override;
@@ -336,7 +338,9 @@
   // The current connection type.
   net::NetworkChangeNotifier::ConnectionType connection_type_;
 
-  NetworkPropertiesManager network_properties_manager_;
+  // Should be accessed only on the IO thread. Guaranteed to be non-null during
+  // the lifetime of |this| if accessed on the IO thread.
+  NetworkPropertiesManager* network_properties_manager_;
 
   base::WeakPtrFactory<DataReductionProxyConfig> weak_factory_;
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc
index a78757a..f3ba9fa9 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc
@@ -122,6 +122,18 @@
   add_default_proxy_bypass_rules_ = add_default_proxy_bypass_rules;
 }
 
+std::string TestDataReductionProxyConfig::GetCurrentNetworkID() const {
+  if (current_network_id_) {
+    return current_network_id_.value();
+  }
+  return DataReductionProxyConfig::GetCurrentNetworkID();
+}
+
+void TestDataReductionProxyConfig::SetCurrentNetworkID(
+    const std::string& network_id) {
+  current_network_id_ = network_id;
+}
+
 MockDataReductionProxyConfig::MockDataReductionProxyConfig(
     std::unique_ptr<DataReductionProxyConfigValues> config_values,
     scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h
index a454696..ed0acfe8 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h
@@ -102,6 +102,10 @@
 
   void SetShouldAddDefaultProxyBypassRules(bool add_default_proxy_bypass_rules);
 
+  std::string GetCurrentNetworkID() const override;
+
+  void SetCurrentNetworkID(const std::string& network_id);
+
   using DataReductionProxyConfig::UpdateConfigForTesting;
   using DataReductionProxyConfig::OnInsecureProxyWarmupURLProbeStatusChange;
 
@@ -113,6 +117,8 @@
   base::Optional<bool> was_data_reduction_proxy_used_;
   base::Optional<int> proxy_index_;
 
+  base::Optional<std::string> current_network_id_;
+
   // Set to true if the captive portal probe for the current network has been
   // blocked.
   bool is_captive_portal_;
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
index 1b5f58a3..500add8 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
@@ -35,6 +35,7 @@
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
+#include "components/data_reduction_proxy/core/browser/network_properties_manager.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h"
@@ -162,7 +163,8 @@
     int http_response_code;
   };
 
-  void CheckSecureProxyCheckOnIPChange(
+  void CheckSecureProxyCheckOnNetworkChange(
+      net::NetworkChangeNotifier::ConnectionType connection_type,
       const std::string& response,
       bool is_captive_portal,
       int response_code,
@@ -170,6 +172,8 @@
       SecureProxyCheckFetchResult expected_fetch_result,
       const std::vector<net::ProxyServer>& expected_proxies_for_http) {
     base::HistogramTester histogram_tester;
+    net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
+        connection_type);
 
     TestResponder responder;
     responder.response = response;
@@ -180,7 +184,6 @@
         .WillRepeatedly(testing::WithArgs<0>(
             testing::Invoke(&responder, &TestResponder::ExecuteCallback)));
     mock_config()->SetIsCaptivePortal(is_captive_portal);
-    net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
     test_context_->RunUntilIdle();
     EXPECT_EQ(expected_proxies_for_http, GetConfiguredProxiesForHttp());
 
@@ -240,13 +243,15 @@
     return test_context_->GetConfiguredProxiesForHttp();
   }
 
+  base::MessageLoopForIO message_loop_;
+
+  std::unique_ptr<DataReductionProxyTestContext> test_context_;
+
  private:
   std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier_;
-  bool mock_config_used_;
-
-  base::MessageLoopForIO message_loop_;
-  std::unique_ptr<DataReductionProxyTestContext> test_context_;
   std::unique_ptr<TestDataReductionProxyParams> expected_params_;
+
+  bool mock_config_used_;
 };
 
 TEST_F(DataReductionProxyConfigTest, TestReloadConfigHoldback) {
@@ -316,7 +321,53 @@
             GetConfiguredProxiesForHttp());
 }
 
-TEST_F(DataReductionProxyConfigTest, TestOnIPAddressChanged) {
+TEST_F(DataReductionProxyConfigTest, TestOnConnectionChangePersistedData) {
+  base::FieldTrialList field_trial_list(nullptr);
+
+  const net::ProxyServer kHttpsProxy = net::ProxyServer::FromURI(
+      "https://secure_origin.net:443", net::ProxyServer::SCHEME_HTTP);
+  const net::ProxyServer kHttpProxy = net::ProxyServer::FromURI(
+      "insecure_origin.net:80", net::ProxyServer::SCHEME_HTTP);
+  SetProxiesForHttpOnCommandLine({kHttpsProxy, kHttpProxy});
+
+  ResetSettings();
+  test_config()->SetProxyConfig(true, true);
+
+  EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}),
+            GetConfiguredProxiesForHttp());
+
+  test_config()->SetCurrentNetworkID("wifi,test");
+  net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
+      net::NetworkChangeNotifier::CONNECTION_WIFI);
+  base::RunLoop().RunUntilIdle();
+  test_config()->UpdateConfigForTesting(true /* enabled */,
+                                        false /* secure_proxies_allowed */,
+                                        true /* insecure_proxies_allowed */);
+  test_config()->OnNewClientConfigFetched();
+  EXPECT_EQ(std::vector<net::ProxyServer>({kHttpProxy}),
+            GetConfiguredProxiesForHttp());
+  base::RunLoop().RunUntilIdle();
+
+  test_config()->SetCurrentNetworkID("cell,test");
+  net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
+      net::NetworkChangeNotifier::CONNECTION_2G);
+  base::RunLoop().RunUntilIdle();
+  test_config()->UpdateConfigForTesting(true /* enabled */,
+                                        false /* secure_proxies_allowed */,
+                                        false /* insecure_proxies_allowed */);
+  test_config()->OnNewClientConfigFetched();
+  EXPECT_EQ(std::vector<net::ProxyServer>({}), GetConfiguredProxiesForHttp());
+
+  // On network change, persisted config should be read, and config reloaded.
+  test_config()->SetCurrentNetworkID("wifi,test");
+  net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
+      net::NetworkChangeNotifier::CONNECTION_WIFI);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(std::vector<net::ProxyServer>({kHttpProxy}),
+            GetConfiguredProxiesForHttp());
+}
+
+TEST_F(DataReductionProxyConfigTest, TestOnNetworkChanged) {
   RecreateContextWithMockConfig();
   const net::URLRequestStatus kSuccess(net::URLRequestStatus::SUCCESS, net::OK);
   const net::ProxyServer kHttpsProxy = net::ProxyServer::FromURI(
@@ -331,70 +382,77 @@
   mock_config()->UpdateConfigForTesting(true, true, true);
   mock_config()->OnNewClientConfigFetched();
 
-  // IP address change triggers a secure proxy check that succeeds. Proxy
+  // Connection change triggers a secure proxy check that succeeds. Proxy
   // remains unrestricted.
-  CheckSecureProxyCheckOnIPChange("OK", false, net::HTTP_OK, kSuccess,
-                                  SUCCEEDED_PROXY_ALREADY_ENABLED,
-                                  {kHttpsProxy, kHttpProxy});
+  CheckSecureProxyCheckOnNetworkChange(
+      net::NetworkChangeNotifier::CONNECTION_WIFI, "OK", false, net::HTTP_OK,
+      kSuccess, SUCCEEDED_PROXY_ALREADY_ENABLED, {kHttpsProxy, kHttpProxy});
 
-  // IP address change triggers a secure proxy check that succeeds but captive
+  // Connection change triggers a secure proxy check that succeeds but captive
   // portal fails. Proxy is restricted.
-  CheckSecureProxyCheckOnIPChange("OK", true, net::HTTP_OK, kSuccess,
-                                  SUCCEEDED_PROXY_ALREADY_ENABLED,
-                                  std::vector<net::ProxyServer>(1, kHttpProxy));
+  CheckSecureProxyCheckOnNetworkChange(
+      net::NetworkChangeNotifier::CONNECTION_WIFI, "OK", true, net::HTTP_OK,
+      kSuccess, SUCCEEDED_PROXY_ALREADY_ENABLED,
+      std::vector<net::ProxyServer>(1, kHttpProxy));
 
-  // IP address change triggers a secure proxy check that fails. Proxy is
+  // Connection change triggers a secure proxy check that fails. Proxy is
   // restricted.
-  CheckSecureProxyCheckOnIPChange("Bad", false, net::HTTP_OK, kSuccess,
-                                  FAILED_PROXY_DISABLED,
-                                  std::vector<net::ProxyServer>(1, kHttpProxy));
+  CheckSecureProxyCheckOnNetworkChange(
+      net::NetworkChangeNotifier::CONNECTION_WIFI, "Bad", false, net::HTTP_OK,
+      kSuccess, FAILED_PROXY_DISABLED,
+      std::vector<net::ProxyServer>(1, kHttpProxy));
 
-  // IP address change triggers a secure proxy check that succeeds. Proxies
+  // Connection change triggers a secure proxy check that succeeds. Proxies
   // are unrestricted.
-  CheckSecureProxyCheckOnIPChange("OK", false, net::HTTP_OK, kSuccess,
-                                  SUCCEEDED_PROXY_ENABLED,
-                                  {kHttpsProxy, kHttpProxy});
+  CheckSecureProxyCheckOnNetworkChange(
+      net::NetworkChangeNotifier::CONNECTION_WIFI, "OK", false, net::HTTP_OK,
+      kSuccess, SUCCEEDED_PROXY_ENABLED, {kHttpsProxy, kHttpProxy});
 
-  // IP address change triggers a secure proxy check that fails. Proxy is
+  // Connection change triggers a secure proxy check that fails. Proxy is
   // restricted.
-  CheckSecureProxyCheckOnIPChange("Bad", true, net::HTTP_OK, kSuccess,
-                                  FAILED_PROXY_DISABLED,
-                                  std::vector<net::ProxyServer>(1, kHttpProxy));
+  CheckSecureProxyCheckOnNetworkChange(
+      net::NetworkChangeNotifier::CONNECTION_WIFI, "Bad", true, net::HTTP_OK,
+      kSuccess, FAILED_PROXY_DISABLED,
+      std::vector<net::ProxyServer>(1, kHttpProxy));
 
-  // IP address change triggers a secure proxy check that fails due to the
+  // Connection change triggers a secure proxy check that fails due to the
   // network changing again. This should be ignored, so the proxy should remain
   // unrestricted.
-  CheckSecureProxyCheckOnIPChange(
-      std::string(), false, net::URLFetcher::RESPONSE_CODE_INVALID,
+  CheckSecureProxyCheckOnNetworkChange(
+      net::NetworkChangeNotifier::CONNECTION_WIFI, std::string(), false,
+      net::URLFetcher::RESPONSE_CODE_INVALID,
       net::URLRequestStatus(net::URLRequestStatus::FAILED,
                             net::ERR_INTERNET_DISCONNECTED),
       INTERNET_DISCONNECTED, std::vector<net::ProxyServer>(1, kHttpProxy));
 
-  // IP address change triggers a secure proxy check that fails. Proxy remains
+  // Connection change triggers a secure proxy check that fails. Proxy remains
   // restricted.
-  CheckSecureProxyCheckOnIPChange("Bad", false, net::HTTP_OK, kSuccess,
-                                  FAILED_PROXY_ALREADY_DISABLED,
-                                  std::vector<net::ProxyServer>(1, kHttpProxy));
+  CheckSecureProxyCheckOnNetworkChange(
+      net::NetworkChangeNotifier::CONNECTION_WIFI, "Bad", false, net::HTTP_OK,
+      kSuccess, FAILED_PROXY_ALREADY_DISABLED,
+      std::vector<net::ProxyServer>(1, kHttpProxy));
 
-  // IP address change triggers a secure proxy check that succeeds. Proxy is
+  // Connection change triggers a secure proxy check that succeeds. Proxy is
   // unrestricted.
-  CheckSecureProxyCheckOnIPChange("OK", false, net::HTTP_OK, kSuccess,
-                                  SUCCEEDED_PROXY_ENABLED,
-                                  {kHttpsProxy, kHttpProxy});
+  CheckSecureProxyCheckOnNetworkChange(
+      net::NetworkChangeNotifier::CONNECTION_WIFI, "OK", false, net::HTTP_OK,
+      kSuccess, SUCCEEDED_PROXY_ENABLED, {kHttpsProxy, kHttpProxy});
 
-  // IP address change triggers a secure proxy check that fails due to the
+  // Connection change triggers a secure proxy check that fails due to the
   // network changing again. This should be ignored, so the proxy should remain
   // unrestricted.
-  CheckSecureProxyCheckOnIPChange(
-      std::string(), false, net::URLFetcher::RESPONSE_CODE_INVALID,
+  CheckSecureProxyCheckOnNetworkChange(
+      net::NetworkChangeNotifier::CONNECTION_WIFI, std::string(), false,
+      net::URLFetcher::RESPONSE_CODE_INVALID,
       net::URLRequestStatus(net::URLRequestStatus::FAILED,
                             net::ERR_INTERNET_DISCONNECTED),
       INTERNET_DISCONNECTED, {kHttpsProxy, kHttpProxy});
 
-  // IP address change triggers a secure proxy check that fails because of a
+  // Connection change triggers a secure proxy check that fails because of a
   // redirect response, e.g. by a captive portal. Proxy is restricted.
-  CheckSecureProxyCheckOnIPChange(
-      "Bad", false, net::HTTP_FOUND,
+  CheckSecureProxyCheckOnNetworkChange(
+      net::NetworkChangeNotifier::CONNECTION_WIFI, "Bad", false,
+      net::HTTP_FOUND,
       net::URLRequestStatus(net::URLRequestStatus::CANCELED, net::ERR_ABORTED),
       FAILED_PROXY_DISABLED, std::vector<net::ProxyServer>(1, kHttpProxy));
 }
@@ -449,8 +507,12 @@
 
     scoped_refptr<net::URLRequestContextGetter> request_context_getter_ =
         new net::TestURLRequestContextGetter(task_runner());
+
+    NetworkPropertiesManager network_properties_manager(
+        test_context_->pref_service(), test_context_->task_runner());
     config.InitializeOnIOThread(request_context_getter_.get(),
-                                request_context_getter_.get());
+                                request_context_getter_.get(),
+                                &network_properties_manager);
     RunUntilIdle();
 
     {
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
index b55c538..98e55d4 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
@@ -24,6 +24,7 @@
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
+#include "components/data_reduction_proxy/core/browser/network_properties_manager.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_event_storage_delegate.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
@@ -93,6 +94,7 @@
 
 DataReductionProxyIOData::DataReductionProxyIOData(
     Client client,
+    PrefService* prefs,
     net::NetLog* net_log,
     scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
     scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
@@ -157,13 +159,25 @@
   proxy_delegate_.reset(new DataReductionProxyDelegate(
       config_.get(), configurator_.get(), event_creator_.get(),
       bypass_stats_.get(), net_log_));
+  network_properties_manager_.reset(
+      new NetworkPropertiesManager(prefs, ui_task_runner_));
 }
 
-DataReductionProxyIOData::DataReductionProxyIOData()
+DataReductionProxyIOData::DataReductionProxyIOData(
+    PrefService* prefs,
+    scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
     : client_(Client::UNKNOWN),
       net_log_(nullptr),
+      io_task_runner_(io_task_runner),
+      ui_task_runner_(ui_task_runner),
       url_request_context_getter_(nullptr),
-      weak_factory_(this) {}
+      weak_factory_(this) {
+  DCHECK(ui_task_runner_);
+  DCHECK(io_task_runner_);
+  network_properties_manager_.reset(
+      new NetworkPropertiesManager(prefs, ui_task_runner_));
+}
 
 DataReductionProxyIOData::~DataReductionProxyIOData() {
   // Guaranteed to be destroyed on IO thread if the IO thread is still
@@ -173,6 +187,7 @@
 
 void DataReductionProxyIOData::ShutdownOnUIThread() {
   DCHECK(ui_task_runner_->BelongsToCurrentThread());
+  network_properties_manager_->ShutdownOnUIThread();
 }
 
 void DataReductionProxyIOData::SetDataReductionProxyService(
@@ -195,8 +210,10 @@
 
 void DataReductionProxyIOData::InitializeOnIOThread() {
   DCHECK(io_task_runner_->BelongsToCurrentThread());
+  DCHECK(network_properties_manager_);
   config_->InitializeOnIOThread(basic_url_request_context_getter_.get(),
-                                url_request_context_getter_);
+                                url_request_context_getter_,
+                                network_properties_manager_.get());
   bypass_stats_->InitializeOnIOThread();
   proxy_delegate_->InitializeOnIOThread(this);
   if (config_client_.get())
@@ -225,6 +242,12 @@
                  service_, pingback_reporting_fraction));
 }
 
+void DataReductionProxyIOData::DeleteBrowsingHistory(const base::Time start,
+                                                     const base::Time end) {
+  DCHECK(io_task_runner_->BelongsToCurrentThread());
+  network_properties_manager_->DeleteHistory();
+}
+
 std::unique_ptr<net::URLRequestInterceptor>
 DataReductionProxyIOData::CreateInterceptor() {
   DCHECK(io_task_runner_->BelongsToCurrentThread());
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h
index 8a1e32a..ae80b3d 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h
@@ -48,6 +48,7 @@
 class DataReductionProxyConfigurator;
 class DataReductionProxyEventCreator;
 class DataReductionProxyService;
+class NetworkPropertiesManager;
 
 // Contains and initializes all Data Reduction Proxy objects that operate on
 // the IO thread.
@@ -57,6 +58,7 @@
   // state of the Data Reduction Proxy.
   DataReductionProxyIOData(
       Client client,
+      PrefService* prefs,
       net::NetLog* net_log,
       scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
       scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
@@ -136,6 +138,9 @@
   // |pingback_reporting_fraction|. Overridden in testing.
   virtual void SetPingbackReportingFraction(float pingback_reporting_fraction);
 
+  // Called when the user clears the browsing history.
+  void DeleteBrowsingHistory(const base::Time start, const base::Time end);
+
   // Various accessor methods.
   DataReductionProxyConfigurator* configurator() const {
     return configurator_.get();
@@ -214,7 +219,10 @@
                            TestResetBadProxyListOnDisableDataSaver);
 
   // Used for testing.
-  DataReductionProxyIOData();
+  DataReductionProxyIOData(
+      PrefService* prefs,
+      scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+      scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
 
   // Initializes the weak pointer to |this| on the IO thread. It must be done
   // on the IO thread, since it is used for posting tasks from the UI thread
@@ -299,6 +307,11 @@
   // The production channel of this build.
   const std::string channel_;
 
+  // Created on the UI thread. Guaranteed to be destroyed on IO thread if the
+  // IO thread is still available at the time of destruction. If the IO thread
+  // is unavailable, then the destruction will happen on the UI thread.
+  std::unique_ptr<NetworkPropertiesManager> network_properties_manager_;
+
   base::WeakPtrFactory<DataReductionProxyIOData> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(DataReductionProxyIOData);
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc
index 58370dc2..70fcaae 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc
@@ -106,7 +106,7 @@
 TEST_F(DataReductionProxyIODataTest, TestConstruction) {
   std::unique_ptr<DataReductionProxyIOData> io_data(
       new DataReductionProxyIOData(
-          Client::UNKNOWN, net_log(),
+          Client::UNKNOWN, prefs(), net_log(),
           scoped_task_environment_.GetMainThreadTaskRunner(),
           scoped_task_environment_.GetMainThreadTaskRunner(),
           false /* enabled */, std::string() /* user_agent */,
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc
index a310830..d730066 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc
@@ -90,6 +90,7 @@
   registry->RegisterStringPref(prefs::kDataReductionProxyConfig, std::string());
   registry->RegisterInt64Pref(prefs::kDataReductionProxyLastConfigRetrievalTime,
                               0L);
+  registry->RegisterDictionaryPref(prefs::kNetworkProperties);
 }
 
 void RegisterSimpleProfilePrefs(PrefRegistrySimple* registry) {
@@ -170,6 +171,7 @@
   registry->RegisterStringPref(prefs::kDataReductionProxyConfig, std::string());
   registry->RegisterInt64Pref(prefs::kDataReductionProxyLastConfigRetrievalTime,
                               0L);
+  registry->RegisterDictionaryPref(prefs::kNetworkProperties);
 }
 
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
index 48f85903..77fe29f 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
@@ -248,6 +248,10 @@
   db_task_runner_->PostTask(
       FROM_HERE, base::Bind(&DBDataOwner::DeleteBrowsingHistory,
                             db_data_owner_->GetWeakPtr(), start, end));
+
+  io_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&DataReductionProxyIOData::DeleteBrowsingHistory,
+                            io_data_, start, end));
 }
 
 void DataReductionProxyService::AddObserver(
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc
index 2b2eeb0..e4d3204 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc
@@ -24,6 +24,7 @@
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
+#include "components/data_reduction_proxy/core/browser/network_properties_manager.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
@@ -63,6 +64,11 @@
 
 TEST_F(DataReductionProxySettingsTest, TestIsProxyEnabledOrManaged) {
   InitPrefMembers();
+  NetworkPropertiesManager network_properties_manager(
+      test_context_->pref_service(), test_context_->task_runner());
+  test_context_->config()->SetNetworkPropertiesManagerForTesting(
+      &network_properties_manager);
+
   // The proxy is disabled initially.
   test_context_->config()->UpdateConfigForTesting(false, true, true);
 
@@ -82,6 +88,11 @@
 
 TEST_F(DataReductionProxySettingsTest, TestCanUseDataReductionProxy) {
   InitPrefMembers();
+  NetworkPropertiesManager network_properties_manager(
+      test_context_->pref_service(), test_context_->task_runner());
+  test_context_->config()->SetNetworkPropertiesManagerForTesting(
+      &network_properties_manager);
+
   // The proxy is disabled initially.
   test_context_->config()->UpdateConfigForTesting(false, true, true);
 
@@ -248,6 +259,11 @@
           .SkipSettingsInitialization()
           .Build();
 
+  NetworkPropertiesManager network_properties_manager(
+      drp_test_context->pref_service(), drp_test_context->task_runner());
+  drp_test_context->config()->SetNetworkPropertiesManagerForTesting(
+      &network_properties_manager);
+
   // The proxy is enabled initially.
   drp_test_context->config()->UpdateConfigForTesting(true, true, true);
   drp_test_context->InitSettings();
@@ -269,6 +285,11 @@
   // Initialize the pref member in |settings_| without the usual callback
   // so it won't trigger MaybeActivateDataReductionProxy when the pref value
   // is set.
+  NetworkPropertiesManager network_properties_manager(
+      test_context_->pref_service(), test_context_->task_runner());
+  test_context_->config()->SetNetworkPropertiesManagerForTesting(
+      &network_properties_manager);
+
   settings_->spdy_proxy_auth_enabled_.Init(
       test_context_->GetDataReductionProxyEnabledPrefName(),
       settings_->GetOriginalProfilePrefs());
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
index cdb018b..8c9575f 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
@@ -249,6 +249,7 @@
 }
 
 TestDataReductionProxyIOData::TestDataReductionProxyIOData(
+    PrefService* prefs,
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
     std::unique_ptr<DataReductionProxyConfig> config,
     std::unique_ptr<DataReductionProxyEventCreator> event_creator,
@@ -256,7 +257,7 @@
     std::unique_ptr<DataReductionProxyConfigurator> configurator,
     net::NetLog* net_log,
     bool enabled)
-    : DataReductionProxyIOData(),
+    : DataReductionProxyIOData(prefs, task_runner, task_runner),
       service_set_(false),
       pingback_reporting_fraction_(0.0f),
       test_request_options_(request_options.get()) {
@@ -496,9 +497,9 @@
 
   std::unique_ptr<TestDataReductionProxyIOData> io_data(
       new TestDataReductionProxyIOData(
-          task_runner, std::move(config), std::move(event_creator),
-          std::move(request_options), std::move(configurator), net_log.get(),
-          true /* enabled */));
+          pref_service.get(), task_runner, std::move(config),
+          std::move(event_creator), std::move(request_options),
+          std::move(configurator), net_log.get(), true /* enabled */));
   io_data->SetSimpleURLRequestContextGetter(request_context_getter);
 
   if (use_test_config_client_) {
@@ -596,6 +597,7 @@
   // indirectly owned by |settings_|.
   if (settings_.get()) {
     settings_.reset();
+    storage_delegate_->SetStorageDelegate(nullptr);
     RunUntilIdle();
   }
 }
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
index 7d4b174..0adb3ffd 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
@@ -195,6 +195,7 @@
 class TestDataReductionProxyIOData : public DataReductionProxyIOData {
  public:
   TestDataReductionProxyIOData(
+      PrefService* prefs,
       const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
       std::unique_ptr<DataReductionProxyConfig> config,
       std::unique_ptr<DataReductionProxyEventCreator> event_creator,
diff --git a/components/data_reduction_proxy/core/browser/network_properties_manager.cc b/components/data_reduction_proxy/core/browser/network_properties_manager.cc
index b7809bb..69cae91 100644
--- a/components/data_reduction_proxy/core/browser/network_properties_manager.cc
+++ b/components/data_reduction_proxy/core/browser/network_properties_manager.cc
@@ -4,13 +4,229 @@
 
 #include "components/data_reduction_proxy/core/browser/network_properties_manager.h"
 
+#include "base/base64.h"
+#include "base/bind.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/optional.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/values.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
+#include "components/prefs/scoped_user_pref_update.h"
+
 namespace data_reduction_proxy {
 
-NetworkPropertiesManager::NetworkPropertiesManager() {}
+namespace {
 
-NetworkPropertiesManager::~NetworkPropertiesManager() {}
+constexpr size_t kMaxCacheSize = 10u;
+
+// Parses a base::Value to NetworkProperties struct. If the parsing is
+// unsuccessful, a nullptr is returned.
+base::Optional<NetworkProperties> GetParsedNetworkProperty(
+    const base::Value& value) {
+  if (!value.is_string())
+    return base::nullopt;
+
+  std::string base64_decoded;
+  if (!base::Base64Decode(value.GetString(), &base64_decoded))
+    return base::nullopt;
+
+  NetworkProperties network_properties;
+  if (!network_properties.ParseFromString(base64_decoded))
+    return base::nullopt;
+
+  return network_properties;
+}
+
+}  // namespace
+
+class NetworkPropertiesManager::PrefManager {
+ public:
+  explicit PrefManager(PrefService* pref_service)
+      : pref_service_(pref_service), ui_weak_ptr_factory_(this) {}
+
+  ~PrefManager() {}
+
+  base::WeakPtr<PrefManager> GetWeakPtr() {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    return ui_weak_ptr_factory_.GetWeakPtr();
+  }
+
+  void ShutdownOnUIThread() {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    ui_weak_ptr_factory_.InvalidateWeakPtrs();
+  }
+
+  void OnChangeInNetworkPropertyOnUIThread(
+      const std::string& network_id,
+      const NetworkProperties& network_properties) {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+    std::string serialized_network_properties;
+    bool serialize_to_string_ok =
+        network_properties.SerializeToString(&serialized_network_properties);
+    if (!serialize_to_string_ok)
+      return;
+
+    std::string base64_encoded;
+    base::Base64Encode(serialized_network_properties, &base64_encoded);
+
+    DictionaryPrefUpdate update(pref_service_, prefs::kNetworkProperties);
+    base::DictionaryValue* properties_dict = update.Get();
+    properties_dict->SetKey(network_id, base::Value(base64_encoded));
+
+    LimitPrefSize(properties_dict);
+  }
+
+  void DeleteHistory() {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    pref_service_->ClearPref(prefs::kNetworkProperties);
+  }
+
+ private:
+  // Limits the pref size to kMaxCacheSize.
+  void LimitPrefSize(base::DictionaryValue* properties_dict) {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+    if (properties_dict->size() <= kMaxCacheSize)
+      return;
+
+    // Delete the key that corresponds to the network with the earliest
+    // timestamp.
+    const std::string* key_to_delete = nullptr;
+    int64_t earliest_timestamp = std::numeric_limits<int64_t>::max();
+
+    for (const auto& it : properties_dict->DictItems()) {
+      base::Optional<NetworkProperties> network_properties =
+          GetParsedNetworkProperty(it.second);
+      if (!network_properties) {
+        // Delete the corrupted entry. No need to find the oldest entry.
+        key_to_delete = &it.first;
+        break;
+      }
+
+      int64_t timestamp = network_properties.value().last_modified();
+
+      // TODO(tbansal): crbug.com/779219: Consider handling the case when the
+      // device clock is moved back. For example, if the clock is moved back
+      // by a year, then for the next year, those older entries will have
+      // timestamps that are later than any new entries from networks that the
+      // user browses.
+      if (timestamp < earliest_timestamp) {
+        earliest_timestamp = timestamp;
+        key_to_delete = &it.first;
+      }
+    }
+    if (key_to_delete == nullptr)
+      return;
+    properties_dict->RemoveKey(*key_to_delete);
+  }
+
+  // Guaranteed to be non-null during the lifetime of |this|.
+  PrefService* pref_service_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  // Used to get |weak_ptr_| to self on the UI thread.
+  base::WeakPtrFactory<PrefManager> ui_weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrefManager);
+};
+
+NetworkPropertiesManager::NetworkPropertiesManager(
+    PrefService* pref_service,
+    scoped_refptr<base::SequencedTaskRunner> ui_task_runner)
+    : ui_task_runner_(ui_task_runner),
+      network_properties_container_(ConvertDictionaryValueToParsedPrefs(
+          pref_service->GetDictionary(prefs::kNetworkProperties))) {
+  DCHECK(ui_task_runner_);
+  DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
+
+  pref_manager_.reset(new PrefManager(pref_service));
+  pref_manager_weak_ptr_ = pref_manager_->GetWeakPtr();
+
+  DETACH_FROM_SEQUENCE(sequence_checker_);
+}
+
+NetworkPropertiesManager::~NetworkPropertiesManager() {
+  if (ui_task_runner_->RunsTasksInCurrentSequence() && pref_manager_) {
+    pref_manager_->ShutdownOnUIThread();
+  }
+}
+
+void NetworkPropertiesManager::DeleteHistory() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  ui_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&NetworkPropertiesManager::PrefManager::DeleteHistory,
+                 pref_manager_weak_ptr_));
+}
+
+void NetworkPropertiesManager::ShutdownOnUIThread() {
+  DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
+  pref_manager_->ShutdownOnUIThread();
+  pref_manager_.reset();
+}
+
+void NetworkPropertiesManager::OnChangeInNetworkID(
+    const std::string& network_id) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  network_id_ = network_id;
+
+  bool cached_entry_found = false;
+
+  NetworkPropertiesContainer::const_iterator it =
+      network_properties_container_.find(network_id_);
+  if (it != network_properties_container_.end()) {
+    network_properties_ = it->second;
+    cached_entry_found = true;
+
+  } else {
+    // Reset to default state.
+    network_properties_.Clear();
+  }
+  UMA_HISTOGRAM_BOOLEAN("DataReductionProxy.NetworkProperties.CacheHit",
+                        cached_entry_found);
+}
+
+void NetworkPropertiesManager::OnChangeInNetworkPropertyOnIOThread() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  network_properties_.set_last_modified(base::Time::Now().ToJavaTime());
+  // Remove the entry from the map, if it is already present.
+  network_properties_container_.erase(network_id_);
+  network_properties_container_.emplace(
+      std::make_pair(network_id_, network_properties_));
+
+  ui_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&NetworkPropertiesManager::PrefManager::
+                     OnChangeInNetworkPropertyOnUIThread,
+                 pref_manager_weak_ptr_, network_id_, network_properties_));
+}
+
+// static
+NetworkPropertiesManager::NetworkPropertiesContainer
+NetworkPropertiesManager::ConvertDictionaryValueToParsedPrefs(
+    const base::Value* value) {
+  NetworkPropertiesContainer read_prefs;
+
+  for (const auto& it : value->DictItems()) {
+    base::Optional<NetworkProperties> network_properties =
+        GetParsedNetworkProperty(it.second);
+    if (!network_properties)
+      continue;
+
+    read_prefs.emplace(std::make_pair(it.first, network_properties.value()));
+  }
+
+  return read_prefs;
+}
 
 bool NetworkPropertiesManager::IsSecureProxyAllowed() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return !network_properties_.secure_proxy_disallowed_by_carrier() &&
          !network_properties_.has_captive_portal() &&
          !network_properties_.secure_proxy_flags()
@@ -18,30 +234,38 @@
 }
 
 bool NetworkPropertiesManager::IsInsecureProxyAllowed() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return !network_properties_.insecure_proxy_flags()
               .disallowed_due_to_warmup_probe_failure();
 }
 
 bool NetworkPropertiesManager::IsSecureProxyDisallowedByCarrier() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return network_properties_.secure_proxy_disallowed_by_carrier();
 }
 
 void NetworkPropertiesManager::SetIsSecureProxyDisallowedByCarrier(
     bool disallowed_by_carrier) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   network_properties_.set_secure_proxy_disallowed_by_carrier(
       disallowed_by_carrier);
+  OnChangeInNetworkPropertyOnIOThread();
 }
 
 bool NetworkPropertiesManager::IsCaptivePortal() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return network_properties_.has_captive_portal();
 }
 
 void NetworkPropertiesManager::SetIsCaptivePortal(bool is_captive_portal) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   network_properties_.set_has_captive_portal(is_captive_portal);
+  OnChangeInNetworkPropertyOnIOThread();
 }
 
 bool NetworkPropertiesManager::HasWarmupURLProbeFailed(
     bool secure_proxy) const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return secure_proxy ? network_properties_.secure_proxy_flags()
                             .disallowed_due_to_warmup_probe_failure()
                       : network_properties_.insecure_proxy_flags()
@@ -51,6 +275,7 @@
 void NetworkPropertiesManager::SetHasWarmupURLProbeFailed(
     bool secure_proxy,
     bool warmup_url_probe_failed) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (secure_proxy) {
     network_properties_.mutable_secure_proxy_flags()
         ->set_disallowed_due_to_warmup_probe_failure(warmup_url_probe_failed);
@@ -58,6 +283,7 @@
     network_properties_.mutable_insecure_proxy_flags()
         ->set_disallowed_due_to_warmup_probe_failure(warmup_url_probe_failed);
   }
+  OnChangeInNetworkPropertyOnIOThread();
 }
 
 }  // namespace data_reduction_proxy
\ No newline at end of file
diff --git a/components/data_reduction_proxy/core/browser/network_properties_manager.h b/components/data_reduction_proxy/core/browser/network_properties_manager.h
index 33032db..8a1dfd2 100644
--- a/components/data_reduction_proxy/core/browser/network_properties_manager.h
+++ b/components/data_reduction_proxy/core/browser/network_properties_manager.h
@@ -5,17 +5,40 @@
 #ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_NETWORK_PROPERTIES_MANAGER_H_
 #define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_NETWORK_PROPERTIES_MANAGER_H_
 
+#include <map>
+#include <memory>
+#include <string>
+
 #include "base/macros.h"
+#include "base/sequence_checker.h"
+#include "base/sequenced_task_runner.h"
 #include "components/data_reduction_proxy/proto/network_properties.pb.h"
+#include "components/prefs/pref_service.h"
+
+namespace base {
+class Value;
+}
 
 namespace data_reduction_proxy {
 
-// Stores the properties of a single network.
+// Stores the properties of a single network. Created on the UI thread, but
+// lives on the IO thread. Guaranteed to be destroyed on IO thread if the IO
+// thread is still available at the time of destruction. If the IO thread is
+// unavailable, then the destruction will happen on the UI thread.
 class NetworkPropertiesManager {
  public:
-  NetworkPropertiesManager();
+  NetworkPropertiesManager(
+      PrefService* pref_service,
+      scoped_refptr<base::SequencedTaskRunner> ui_task_runner);
 
-  ~NetworkPropertiesManager();
+  virtual ~NetworkPropertiesManager();
+
+  // Called when the user clears the browsing history.
+  void DeleteHistory();
+
+  void ShutdownOnUIThread();
+
+  void OnChangeInNetworkID(const std::string& network_id);
 
   // Returns true if usage of secure proxies are allowed on the current network.
   bool IsSecureProxyAllowed() const;
@@ -52,9 +75,41 @@
                                   bool warmup_url_probe_failed);
 
  private:
+  // Map from network IDs to network properties.
+  typedef std::map<std::string, NetworkProperties> NetworkPropertiesContainer;
+
+  // PrefManager writes or updates the network properties prefs. Created on
+  // UI thread, and should be used on the UI thread. May be destroyed on UI
+  // or IO thread.
+  class PrefManager;
+
+  // Called when there is a change in the network property of the current
+  // network.
+  void OnChangeInNetworkPropertyOnIOThread();
+
+  static NetworkPropertiesContainer ConvertDictionaryValueToParsedPrefs(
+      const base::Value* value);
+
+  // Task runner on which prefs should be accessed.
+  scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
+
+  // Network properties of different networks. Should be accessed on the IO
+  // thread.
+  NetworkPropertiesContainer network_properties_container_;
+
+  // ID of the current network.
+  std::string network_id_;
+
   // State of the proxies on the current network.
   NetworkProperties network_properties_;
 
+  std::unique_ptr<PrefManager> pref_manager_;
+
+  // Should be dereferenced only on the UI thread.
+  base::WeakPtr<PrefManager> pref_manager_weak_ptr_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+
   DISALLOW_COPY_AND_ASSIGN(NetworkPropertiesManager);
 };
 
diff --git a/components/data_reduction_proxy/core/browser/network_properties_manager_unittest.cc b/components/data_reduction_proxy/core/browser/network_properties_manager_unittest.cc
index b45edc2..1b6a365 100644
--- a/components/data_reduction_proxy/core/browser/network_properties_manager_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/network_properties_manager_unittest.cc
@@ -5,14 +5,38 @@
 #include "components/data_reduction_proxy/core/browser/network_properties_manager.h"
 
 #include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/test/histogram_tester.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace data_reduction_proxy {
 
 namespace {
 
+class TestNetworkPropertiesManager : public NetworkPropertiesManager {
+ public:
+  TestNetworkPropertiesManager(
+      PrefService* pref_service,
+      scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
+      : NetworkPropertiesManager(pref_service, ui_task_runner) {}
+  ~TestNetworkPropertiesManager() override {}
+};
+
 TEST(NetworkPropertyTest, TestSetterGetterCaptivePortal) {
-  NetworkPropertiesManager network_properties_manager;
+  base::HistogramTester histogram_tester;
+  TestingPrefServiceSimple test_prefs;
+  test_prefs.registry()->RegisterDictionaryPref(prefs::kNetworkProperties);
+  base::MessageLoopForIO loop;
+  TestNetworkPropertiesManager network_properties_manager(
+      &test_prefs, base::ThreadTaskRunnerHandle::Get());
+
+  std::string network_id("test");
+  network_properties_manager.OnChangeInNetworkID(network_id);
 
   EXPECT_TRUE(network_properties_manager.IsInsecureProxyAllowed());
   EXPECT_TRUE(network_properties_manager.IsSecureProxyAllowed());
@@ -24,6 +48,20 @@
   EXPECT_TRUE(network_properties_manager.IsCaptivePortal());
   EXPECT_FALSE(network_properties_manager.HasWarmupURLProbeFailed(false));
   EXPECT_FALSE(network_properties_manager.HasWarmupURLProbeFailed(true));
+  base::RunLoop().RunUntilIdle();
+
+  // Verify the prefs.
+  EXPECT_EQ(1u, test_prefs.GetDictionary(prefs::kNetworkProperties)->size());
+  EXPECT_FALSE(test_prefs.GetDictionary(prefs::kNetworkProperties)
+                   ->HasKey("mismatched_network_id"));
+  EXPECT_TRUE(
+      test_prefs.GetDictionary(prefs::kNetworkProperties)->HasKey(network_id));
+  {
+    TestNetworkPropertiesManager network_properties_manager_2(
+        &test_prefs, base::ThreadTaskRunnerHandle::Get());
+    network_properties_manager_2.OnChangeInNetworkID(network_id);
+    EXPECT_TRUE(network_properties_manager_2.IsCaptivePortal());
+  }
 
   network_properties_manager.SetIsCaptivePortal(false);
   EXPECT_TRUE(network_properties_manager.IsInsecureProxyAllowed());
@@ -32,10 +70,29 @@
   EXPECT_FALSE(network_properties_manager.IsCaptivePortal());
   EXPECT_FALSE(network_properties_manager.HasWarmupURLProbeFailed(false));
   EXPECT_FALSE(network_properties_manager.HasWarmupURLProbeFailed(true));
+  base::RunLoop().RunUntilIdle();
+
+  {
+    TestNetworkPropertiesManager network_properties_manager_2(
+        &test_prefs, base::ThreadTaskRunnerHandle::Get());
+    network_properties_manager_2.OnChangeInNetworkID(network_id);
+    EXPECT_FALSE(network_properties_manager_2.IsCaptivePortal());
+  }
+
+  // Verify the prefs.
+  EXPECT_EQ(1u, test_prefs.GetDictionary(prefs::kNetworkProperties)->size());
+  EXPECT_FALSE(test_prefs.GetDictionary(prefs::kNetworkProperties)
+                   ->HasKey("mismatched_network_id"));
+  EXPECT_TRUE(
+      test_prefs.GetDictionary(prefs::kNetworkProperties)->HasKey(network_id));
 }
 
 TEST(NetworkPropertyTest, TestSetterGetterDisallowedByCarrier) {
-  NetworkPropertiesManager network_properties_manager;
+  TestingPrefServiceSimple test_prefs;
+  test_prefs.registry()->RegisterDictionaryPref(prefs::kNetworkProperties);
+  base::MessageLoopForIO loop;
+  TestNetworkPropertiesManager network_properties_manager(
+      &test_prefs, base::ThreadTaskRunnerHandle::Get());
 
   EXPECT_TRUE(network_properties_manager.IsInsecureProxyAllowed());
   EXPECT_TRUE(network_properties_manager.IsSecureProxyAllowed());
@@ -58,7 +115,11 @@
 }
 
 TEST(NetworkPropertyTest, TestWarmupURLFailedOnSecureProxy) {
-  NetworkPropertiesManager network_properties_manager;
+  TestingPrefServiceSimple test_prefs;
+  test_prefs.registry()->RegisterDictionaryPref(prefs::kNetworkProperties);
+  base::MessageLoopForIO loop;
+  TestNetworkPropertiesManager network_properties_manager(
+      &test_prefs, base::ThreadTaskRunnerHandle::Get());
 
   EXPECT_TRUE(network_properties_manager.IsInsecureProxyAllowed());
   EXPECT_TRUE(network_properties_manager.IsSecureProxyAllowed());
@@ -81,7 +142,11 @@
 }
 
 TEST(NetworkPropertyTest, TestWarmupURLFailedOnInSecureProxy) {
-  NetworkPropertiesManager network_properties_manager;
+  TestingPrefServiceSimple test_prefs;
+  test_prefs.registry()->RegisterDictionaryPref(prefs::kNetworkProperties);
+  base::MessageLoopForIO loop;
+  TestNetworkPropertiesManager network_properties_manager(
+      &test_prefs, base::ThreadTaskRunnerHandle::Get());
 
   EXPECT_TRUE(network_properties_manager.IsInsecureProxyAllowed());
   EXPECT_TRUE(network_properties_manager.IsSecureProxyAllowed());
@@ -103,6 +168,219 @@
   EXPECT_FALSE(network_properties_manager.HasWarmupURLProbeFailed(true));
 }
 
+TEST(NetworkPropertyTest, TestLimitPrefSize) {
+  TestingPrefServiceSimple test_prefs;
+  test_prefs.registry()->RegisterDictionaryPref(prefs::kNetworkProperties);
+  base::MessageLoopForIO loop;
+  TestNetworkPropertiesManager network_properties_manager(
+      &test_prefs, base::ThreadTaskRunnerHandle::Get());
+
+  size_t num_network_ids = 100;
+
+  for (size_t i = 0; i < num_network_ids; ++i) {
+    std::string network_id("test" + base::IntToString(i));
+    network_properties_manager.OnChangeInNetworkID(network_id);
+
+    // State should be reset when there is a change in the network ID.
+    EXPECT_TRUE(network_properties_manager.IsInsecureProxyAllowed());
+    EXPECT_TRUE(network_properties_manager.IsSecureProxyAllowed());
+
+    network_properties_manager.SetIsCaptivePortal(true);
+    EXPECT_TRUE(network_properties_manager.IsInsecureProxyAllowed());
+    EXPECT_FALSE(network_properties_manager.IsSecureProxyAllowed());
+    EXPECT_FALSE(network_properties_manager.IsSecureProxyDisallowedByCarrier());
+    EXPECT_TRUE(network_properties_manager.IsCaptivePortal());
+    EXPECT_FALSE(network_properties_manager.HasWarmupURLProbeFailed(false));
+    EXPECT_FALSE(network_properties_manager.HasWarmupURLProbeFailed(true));
+
+    base::RunLoop().RunUntilIdle();
+  }
+
+  // Pref size should be bounded to 10.
+  EXPECT_EQ(10u, test_prefs.GetDictionary(prefs::kNetworkProperties)->size());
+  EXPECT_FALSE(test_prefs.GetDictionary(prefs::kNetworkProperties)
+                   ->HasKey("mismatched_network_id"));
+
+  // The last 10 network IDs are guaranteed to be present in the prefs.
+  for (size_t i = num_network_ids - 10; i < num_network_ids; ++i) {
+    EXPECT_TRUE(test_prefs.GetDictionary(prefs::kNetworkProperties)
+                    ->HasKey("test" + base::IntToString(i)));
+  }
+
+  {
+    TestNetworkPropertiesManager network_properties_manager_2(
+        &test_prefs, base::ThreadTaskRunnerHandle::Get());
+    for (size_t i = 0; i < num_network_ids; ++i) {
+      std::string network_id("test" + base::IntToString(i));
+      network_properties_manager_2.OnChangeInNetworkID(network_id);
+
+      EXPECT_EQ(test_prefs.GetDictionary(prefs::kNetworkProperties)
+                    ->HasKey(network_id),
+                network_properties_manager_2.IsCaptivePortal());
+      EXPECT_FALSE(
+          network_properties_manager_2.IsSecureProxyDisallowedByCarrier());
+      EXPECT_FALSE(network_properties_manager_2.HasWarmupURLProbeFailed(false));
+      EXPECT_FALSE(network_properties_manager_2.HasWarmupURLProbeFailed(true));
+    }
+  }
+}
+
+TEST(NetworkPropertyTest, TestChangeNetworkIDBackAndForth) {
+  TestingPrefServiceSimple test_prefs;
+  test_prefs.registry()->RegisterDictionaryPref(prefs::kNetworkProperties);
+  base::MessageLoopForIO loop;
+  TestNetworkPropertiesManager network_properties_manager(
+      &test_prefs, base::ThreadTaskRunnerHandle::Get());
+
+  // First network ID has a captive portal.
+  std::string first_network_id("test1");
+  network_properties_manager.OnChangeInNetworkID(first_network_id);
+  // State should be reset when there is a change in the network ID.
+  EXPECT_FALSE(network_properties_manager.IsCaptivePortal());
+  EXPECT_TRUE(network_properties_manager.IsInsecureProxyAllowed());
+  network_properties_manager.SetIsCaptivePortal(true);
+  EXPECT_TRUE(network_properties_manager.IsCaptivePortal());
+  EXPECT_TRUE(network_properties_manager.IsInsecureProxyAllowed());
+  base::RunLoop().RunUntilIdle();
+
+  // Warmup probe failed on the insecure proxy for the second network ID.
+  std::string second_network_id("test2");
+  network_properties_manager.OnChangeInNetworkID(second_network_id);
+  // State should be reset when there is a change in the network ID.
+  EXPECT_FALSE(network_properties_manager.IsCaptivePortal());
+  EXPECT_TRUE(network_properties_manager.IsInsecureProxyAllowed());
+  network_properties_manager.SetHasWarmupURLProbeFailed(false, true);
+  EXPECT_FALSE(network_properties_manager.IsCaptivePortal());
+  EXPECT_FALSE(network_properties_manager.IsInsecureProxyAllowed());
+  base::RunLoop().RunUntilIdle();
+
+  // Change back to |first_network_id|.
+  network_properties_manager.OnChangeInNetworkID(first_network_id);
+  EXPECT_TRUE(network_properties_manager.IsCaptivePortal());
+  EXPECT_TRUE(network_properties_manager.IsInsecureProxyAllowed());
+
+  // Change back to |second_network_id|.
+  network_properties_manager.OnChangeInNetworkID(second_network_id);
+  EXPECT_FALSE(network_properties_manager.IsCaptivePortal());
+  EXPECT_FALSE(network_properties_manager.IsInsecureProxyAllowed());
+
+  // Verify the prefs.
+  EXPECT_EQ(2u, test_prefs.GetDictionary(prefs::kNetworkProperties)->size());
+  EXPECT_FALSE(test_prefs.GetDictionary(prefs::kNetworkProperties)
+                   ->HasKey("mismatched_network_id"));
+  EXPECT_TRUE(test_prefs.GetDictionary(prefs::kNetworkProperties)
+                  ->HasKey(first_network_id));
+  EXPECT_TRUE(test_prefs.GetDictionary(prefs::kNetworkProperties)
+                  ->HasKey(second_network_id));
+}
+
+TEST(NetworkPropertyTest, TestNetworkQualitiesOverwrite) {
+  TestingPrefServiceSimple test_prefs;
+  test_prefs.registry()->RegisterDictionaryPref(prefs::kNetworkProperties);
+  base::MessageLoopForIO loop;
+  TestNetworkPropertiesManager network_properties_manager(
+      &test_prefs, base::ThreadTaskRunnerHandle::Get());
+
+  // First network ID has a captive portal.
+  std::string first_network_id("test1");
+  network_properties_manager.OnChangeInNetworkID(first_network_id);
+  // State should be reset when there is a change in the network ID.
+  EXPECT_FALSE(network_properties_manager.IsCaptivePortal());
+  EXPECT_TRUE(network_properties_manager.IsInsecureProxyAllowed());
+  network_properties_manager.SetIsCaptivePortal(true);
+  EXPECT_TRUE(network_properties_manager.IsCaptivePortal());
+  EXPECT_TRUE(network_properties_manager.IsInsecureProxyAllowed());
+  base::RunLoop().RunUntilIdle();
+
+  // Warmup probe failed on the insecure proxy for the second network ID.
+  std::string second_network_id("test2");
+  network_properties_manager.OnChangeInNetworkID(second_network_id);
+  // State should be reset when there is a change in the network ID.
+  EXPECT_FALSE(network_properties_manager.IsCaptivePortal());
+  EXPECT_TRUE(network_properties_manager.IsInsecureProxyAllowed());
+  network_properties_manager.SetHasWarmupURLProbeFailed(false, true);
+  EXPECT_FALSE(network_properties_manager.IsCaptivePortal());
+  EXPECT_FALSE(network_properties_manager.IsInsecureProxyAllowed());
+  base::RunLoop().RunUntilIdle();
+
+  // Change back to |first_network_id|.
+  network_properties_manager.OnChangeInNetworkID(first_network_id);
+  EXPECT_TRUE(network_properties_manager.IsCaptivePortal());
+  EXPECT_TRUE(network_properties_manager.IsInsecureProxyAllowed());
+  network_properties_manager.SetHasWarmupURLProbeFailed(false, true);
+
+  // Change to |first_network_id|.
+  network_properties_manager.OnChangeInNetworkID(first_network_id);
+  EXPECT_TRUE(network_properties_manager.IsCaptivePortal());
+  EXPECT_FALSE(network_properties_manager.IsInsecureProxyAllowed());
+
+  // Verify the prefs.
+  EXPECT_EQ(2u, test_prefs.GetDictionary(prefs::kNetworkProperties)->size());
+  EXPECT_FALSE(test_prefs.GetDictionary(prefs::kNetworkProperties)
+                   ->HasKey("mismatched_network_id"));
+  EXPECT_TRUE(test_prefs.GetDictionary(prefs::kNetworkProperties)
+                  ->HasKey(first_network_id));
+  EXPECT_TRUE(test_prefs.GetDictionary(prefs::kNetworkProperties)
+                  ->HasKey(second_network_id));
+}
+
+TEST(NetworkPropertyTest, TestDeleteHistory) {
+  base::HistogramTester histogram_tester;
+  TestingPrefServiceSimple test_prefs;
+  test_prefs.registry()->RegisterDictionaryPref(prefs::kNetworkProperties);
+  base::MessageLoopForIO loop;
+  TestNetworkPropertiesManager network_properties_manager(
+      &test_prefs, base::ThreadTaskRunnerHandle::Get());
+
+  std::string network_id("test");
+  network_properties_manager.OnChangeInNetworkID(network_id);
+  histogram_tester.ExpectUniqueSample(
+      "DataReductionProxy.NetworkProperties.CacheHit", false, 1);
+
+  EXPECT_TRUE(network_properties_manager.IsInsecureProxyAllowed());
+  EXPECT_TRUE(network_properties_manager.IsSecureProxyAllowed());
+
+  network_properties_manager.SetIsCaptivePortal(true);
+  EXPECT_TRUE(network_properties_manager.IsInsecureProxyAllowed());
+  EXPECT_FALSE(network_properties_manager.IsSecureProxyAllowed());
+  EXPECT_FALSE(network_properties_manager.IsSecureProxyDisallowedByCarrier());
+  EXPECT_TRUE(network_properties_manager.IsCaptivePortal());
+  EXPECT_FALSE(network_properties_manager.HasWarmupURLProbeFailed(false));
+  EXPECT_FALSE(network_properties_manager.HasWarmupURLProbeFailed(true));
+  base::RunLoop().RunUntilIdle();
+
+  // Verify the prefs.
+  EXPECT_EQ(1u, test_prefs.GetDictionary(prefs::kNetworkProperties)->size());
+  EXPECT_FALSE(test_prefs.GetDictionary(prefs::kNetworkProperties)
+                   ->HasKey("mismatched_network_id"));
+  EXPECT_TRUE(
+      test_prefs.GetDictionary(prefs::kNetworkProperties)->HasKey(network_id));
+  {
+    TestNetworkPropertiesManager network_properties_manager_2(
+        &test_prefs, base::ThreadTaskRunnerHandle::Get());
+    network_properties_manager_2.OnChangeInNetworkID(network_id);
+    EXPECT_TRUE(network_properties_manager_2.IsCaptivePortal());
+    histogram_tester.ExpectBucketCount(
+        "DataReductionProxy.NetworkProperties.CacheHit", true, 1);
+    histogram_tester.ExpectTotalCount(
+        "DataReductionProxy.NetworkProperties.CacheHit", 2);
+  }
+
+  // Pref should be cleared.
+  network_properties_manager.DeleteHistory();
+  base::RunLoop().RunUntilIdle();
+  {
+    TestNetworkPropertiesManager network_properties_manager_2(
+        &test_prefs, base::ThreadTaskRunnerHandle::Get());
+    network_properties_manager_2.OnChangeInNetworkID(network_id);
+    EXPECT_FALSE(network_properties_manager_2.IsCaptivePortal());
+    histogram_tester.ExpectBucketCount(
+        "DataReductionProxy.NetworkProperties.CacheHit", false, 2);
+    histogram_tester.ExpectTotalCount(
+        "DataReductionProxy.NetworkProperties.CacheHit", 3);
+  }
+}
+
 }  // namespace
 
 }  // namespace data_reduction_proxy
\ No newline at end of file
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc
index 7d2083e..0acc086 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc
@@ -209,5 +209,9 @@
 const char kDataReductionProxyLastConfigRetrievalTime[] =
     "data_reduction.last_config_retrieval_time";
 
+// Pref to store the properties of the different networks. The pref stores the
+// map of network IDs and their respective network properties.
+const char kNetworkProperties[] = "data_reduction.network_properties";
+
 }  // namespace prefs
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h
index 4bbff19..5738c30 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h
@@ -52,6 +52,7 @@
 extern const char kHttpOriginalContentLength[];
 extern const char kHttpReceivedContentLength[];
 extern const char kDataReductionProxyLastConfigRetrievalTime[];
+extern const char kNetworkProperties[];
 
 }  // namespace prefs
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/proto/network_properties.proto b/components/data_reduction_proxy/proto/network_properties.proto
index aa82b45..0a381811 100644
--- a/components/data_reduction_proxy/proto/network_properties.proto
+++ b/components/data_reduction_proxy/proto/network_properties.proto
@@ -19,4 +19,5 @@
   optional bool has_captive_portal = 2;
   optional ProxyFlags secure_proxy_flags = 3;
   optional ProxyFlags insecure_proxy_flags = 4;
+  optional int64 last_modified = 5;
 }
\ No newline at end of file
diff --git a/components/exo/wayland/aura-shell-client-protocol.h b/components/exo/wayland/aura-shell-client-protocol.h
index 2792ac45..8131b8a 100644
--- a/components/exo/wayland/aura-shell-client-protocol.h
+++ b/components/exo/wayland/aura-shell-client-protocol.h
@@ -16,6 +16,7 @@
  * @section page_ifaces_aura_shell Interfaces
  * - @subpage page_iface_zaura_shell - aura_shell
  * - @subpage page_iface_zaura_surface - aura shell interface to a wl_surface
+ * - @subpage page_iface_zaura_output - aura shell interface to a wl_output
  * @section page_copyright_aura_shell Copyright
  * <pre>
  *
@@ -41,7 +42,9 @@
  * DEALINGS IN THE SOFTWARE.
  * </pre>
  */
+struct wl_output;
 struct wl_surface;
+struct zaura_output;
 struct zaura_shell;
 struct zaura_surface;
 
@@ -81,6 +84,22 @@
  * client to access aura shell specific functionality for surface.
  */
 extern const struct wl_interface zaura_surface_interface;
+/**
+ * @page page_iface_zaura_output zaura_output
+ * @section page_iface_zaura_output_desc Description
+ *
+ * An additional interface to a wl_output object, which allows the
+ * client to access aura shell specific functionality for output.
+ * @section page_iface_zaura_output_api API
+ * See @ref iface_zaura_output.
+ */
+/**
+ * @defgroup iface_zaura_output The zaura_output interface
+ *
+ * An additional interface to a wl_output object, which allows the
+ * client to access aura shell specific functionality for output.
+ */
+extern const struct wl_interface zaura_output_interface;
 
 #ifndef ZAURA_SHELL_ERROR_ENUM
 #define ZAURA_SHELL_ERROR_ENUM
@@ -89,16 +108,25 @@
 	 * the surface already has an aura surface object associated
 	 */
 	ZAURA_SHELL_ERROR_AURA_SURFACE_EXISTS = 0,
+	/**
+	 * the output already has an aura output object associated
+	 */
+	ZAURA_SHELL_ERROR_AURA_OUTPUT_EXISTS = 1,
 };
 #endif /* ZAURA_SHELL_ERROR_ENUM */
 
 #define ZAURA_SHELL_GET_AURA_SURFACE 0
+#define ZAURA_SHELL_GET_AURA_OUTPUT 1
 
 
 /**
  * @ingroup iface_zaura_shell
  */
 #define ZAURA_SHELL_GET_AURA_SURFACE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zaura_shell
+ */
+#define ZAURA_SHELL_GET_AURA_OUTPUT_SINCE_VERSION 2
 
 /** @ingroup iface_zaura_shell */
 static inline void
@@ -146,6 +174,23 @@
 	return (struct zaura_surface *) id;
 }
 
+/**
+ * @ingroup iface_zaura_shell
+ *
+ * Instantiate an interface extension for the given wl_output to
+ * provide aura shell functionality.
+ */
+static inline struct zaura_output *
+zaura_shell_get_aura_output(struct zaura_shell *zaura_shell, struct wl_output *output)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) zaura_shell,
+			 ZAURA_SHELL_GET_AURA_OUTPUT, &zaura_output_interface, NULL, output);
+
+	return (struct zaura_output *) id;
+}
+
 #ifndef ZAURA_SURFACE_FRAME_TYPE_ENUM
 #define ZAURA_SURFACE_FRAME_TYPE_ENUM
 /**
@@ -171,12 +216,17 @@
 #endif /* ZAURA_SURFACE_FRAME_TYPE_ENUM */
 
 #define ZAURA_SURFACE_SET_FRAME 0
+#define ZAURA_SURFACE_SET_PARENT 1
 
 
 /**
  * @ingroup iface_zaura_surface
  */
 #define ZAURA_SURFACE_SET_FRAME_SINCE_VERSION 1
+/**
+ * @ingroup iface_zaura_surface
+ */
+#define ZAURA_SURFACE_SET_PARENT_SINCE_VERSION 2
 
 /** @ingroup iface_zaura_surface */
 static inline void
@@ -217,6 +267,126 @@
 			 ZAURA_SURFACE_SET_FRAME, type);
 }
 
+/**
+ * @ingroup iface_zaura_surface
+ *
+ * Set the "parent" of this surface. "x" and "y" arguments specify the
+ * initial position for surface relative to parent.
+ */
+static inline void
+zaura_surface_set_parent(struct zaura_surface *zaura_surface, struct zaura_surface *parent, int32_t x, int32_t y)
+{
+	wl_proxy_marshal((struct wl_proxy *) zaura_surface,
+			 ZAURA_SURFACE_SET_PARENT, parent, x, y);
+}
+
+#ifndef ZAURA_OUTPUT_SCALE_PROPERTY_ENUM
+#define ZAURA_OUTPUT_SCALE_PROPERTY_ENUM
+/**
+ * @ingroup iface_zaura_output
+ * scale information
+ *
+ * These flags describe properties of an output scale.
+ * They are used in the flags bitfield of the scale event.
+ */
+enum zaura_output_scale_property {
+	/**
+	 * indicates this is the current scale
+	 */
+	ZAURA_OUTPUT_SCALE_PROPERTY_CURRENT = 0x1,
+	/**
+	 * indicates this is the preferred scale
+	 */
+	ZAURA_OUTPUT_SCALE_PROPERTY_PREFERRED = 0x2,
+};
+#endif /* ZAURA_OUTPUT_SCALE_PROPERTY_ENUM */
+
+#ifndef ZAURA_OUTPUT_SCALE_FACTOR_ENUM
+#define ZAURA_OUTPUT_SCALE_FACTOR_ENUM
+enum zaura_output_scale_factor {
+	ZAURA_OUTPUT_SCALE_FACTOR_0500 = 500,
+	ZAURA_OUTPUT_SCALE_FACTOR_0600 = 600,
+	ZAURA_OUTPUT_SCALE_FACTOR_0625 = 625,
+	ZAURA_OUTPUT_SCALE_FACTOR_0750 = 750,
+	ZAURA_OUTPUT_SCALE_FACTOR_0800 = 800,
+	ZAURA_OUTPUT_SCALE_FACTOR_1000 = 1000,
+	ZAURA_OUTPUT_SCALE_FACTOR_1125 = 1125,
+	ZAURA_OUTPUT_SCALE_FACTOR_1200 = 1200,
+	ZAURA_OUTPUT_SCALE_FACTOR_1250 = 1250,
+	ZAURA_OUTPUT_SCALE_FACTOR_1500 = 1500,
+	ZAURA_OUTPUT_SCALE_FACTOR_1600 = 1600,
+	ZAURA_OUTPUT_SCALE_FACTOR_2000 = 2000,
+};
+#endif /* ZAURA_OUTPUT_SCALE_FACTOR_ENUM */
+
+/**
+ * @ingroup iface_zaura_output
+ * @struct zaura_output_listener
+ */
+struct zaura_output_listener {
+	/**
+	 * advertise available scales for the output
+	 *
+	 * The scale event describes an available scale for the output.
+	 *
+	 * The event is sent when binding to the output object and there
+	 * will always be one scale, the current scale. The event is sent
+	 * again if an output changes scale, for the scale that is now
+	 * current. In other words, the current scale is always the last
+	 * scale that was received with the current flag set.
+	 * @param flags bitfield of scale flags
+	 * @param scale output scale
+	 */
+	void (*scale)(void *data,
+		      struct zaura_output *zaura_output,
+		      uint32_t flags,
+		      uint32_t scale);
+};
+
+/**
+ * @ingroup iface_zaura_output
+ */
+static inline int
+zaura_output_add_listener(struct zaura_output *zaura_output,
+			  const struct zaura_output_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) zaura_output,
+				     (void (**)(void)) listener, data);
+}
+
+/**
+ * @ingroup iface_zaura_output
+ */
+#define ZAURA_OUTPUT_SCALE_SINCE_VERSION 1
+
+
+/** @ingroup iface_zaura_output */
+static inline void
+zaura_output_set_user_data(struct zaura_output *zaura_output, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) zaura_output, user_data);
+}
+
+/** @ingroup iface_zaura_output */
+static inline void *
+zaura_output_get_user_data(struct zaura_output *zaura_output)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) zaura_output);
+}
+
+static inline uint32_t
+zaura_output_get_version(struct zaura_output *zaura_output)
+{
+	return wl_proxy_get_version((struct wl_proxy *) zaura_output);
+}
+
+/** @ingroup iface_zaura_output */
+static inline void
+zaura_output_destroy(struct zaura_output *zaura_output)
+{
+	wl_proxy_destroy((struct wl_proxy *) zaura_output);
+}
+
 #ifdef  __cplusplus
 }
 #endif
diff --git a/components/exo/wayland/aura-shell-protocol.c b/components/exo/wayland/aura-shell-protocol.c
index 61bb7b5..8dc4341 100644
--- a/components/exo/wayland/aura-shell-protocol.c
+++ b/components/exo/wayland/aura-shell-protocol.c
@@ -27,32 +27,52 @@
 #include <stdint.h>
 #include "wayland-util.h"
 
+extern const struct wl_interface wl_output_interface;
 extern const struct wl_interface wl_surface_interface;
+extern const struct wl_interface zaura_output_interface;
 extern const struct wl_interface zaura_surface_interface;
 
 static const struct wl_interface *types[] = {
 	NULL,
+	NULL,
 	&zaura_surface_interface,
 	&wl_surface_interface,
+	&zaura_output_interface,
+	&wl_output_interface,
+	&zaura_surface_interface,
+	NULL,
+	NULL,
 };
 
 static const struct wl_message zaura_shell_requests[] = {
-	{ "get_aura_surface", "no", types + 1 },
+	{ "get_aura_surface", "no", types + 2 },
+	{ "get_aura_output", "2no", types + 4 },
 };
 
 WL_EXPORT const struct wl_interface zaura_shell_interface = {
-	"zaura_shell", 1,
-	1, zaura_shell_requests,
+	"zaura_shell", 2,
+	2, zaura_shell_requests,
 	0, NULL,
 };
 
 static const struct wl_message zaura_surface_requests[] = {
 	{ "set_frame", "u", types + 0 },
+	{ "set_parent", "2?oii", types + 6 },
 };
 
 WL_EXPORT const struct wl_interface zaura_surface_interface = {
-	"zaura_surface", 1,
-	1, zaura_surface_requests,
+	"zaura_surface", 2,
+	2, zaura_surface_requests,
 	0, NULL,
 };
 
+static const struct wl_message zaura_output_events[] = {
+	{ "scale", "uu", types + 0 },
+};
+
+WL_EXPORT const struct wl_interface zaura_output_interface = {
+	"zaura_output", 2,
+	0, NULL,
+	1, zaura_output_events,
+};
+
diff --git a/components/exo/wayland/aura-shell-server-protocol.h b/components/exo/wayland/aura-shell-server-protocol.h
index 37b9a9e..9328c45 100644
--- a/components/exo/wayland/aura-shell-server-protocol.h
+++ b/components/exo/wayland/aura-shell-server-protocol.h
@@ -19,6 +19,7 @@
  * @section page_ifaces_aura_shell Interfaces
  * - @subpage page_iface_zaura_shell - aura_shell
  * - @subpage page_iface_zaura_surface - aura shell interface to a wl_surface
+ * - @subpage page_iface_zaura_output - aura shell interface to a wl_output
  * @section page_copyright_aura_shell Copyright
  * <pre>
  *
@@ -44,7 +45,9 @@
  * DEALINGS IN THE SOFTWARE.
  * </pre>
  */
+struct wl_output;
 struct wl_surface;
+struct zaura_output;
 struct zaura_shell;
 struct zaura_surface;
 
@@ -84,6 +87,22 @@
  * client to access aura shell specific functionality for surface.
  */
 extern const struct wl_interface zaura_surface_interface;
+/**
+ * @page page_iface_zaura_output zaura_output
+ * @section page_iface_zaura_output_desc Description
+ *
+ * An additional interface to a wl_output object, which allows the
+ * client to access aura shell specific functionality for output.
+ * @section page_iface_zaura_output_api API
+ * See @ref iface_zaura_output.
+ */
+/**
+ * @defgroup iface_zaura_output The zaura_output interface
+ *
+ * An additional interface to a wl_output object, which allows the
+ * client to access aura shell specific functionality for output.
+ */
+extern const struct wl_interface zaura_output_interface;
 
 #ifndef ZAURA_SHELL_ERROR_ENUM
 #define ZAURA_SHELL_ERROR_ENUM
@@ -92,6 +111,10 @@
 	 * the surface already has an aura surface object associated
 	 */
 	ZAURA_SHELL_ERROR_AURA_SURFACE_EXISTS = 0,
+	/**
+	 * the output already has an aura output object associated
+	 */
+	ZAURA_SHELL_ERROR_AURA_OUTPUT_EXISTS = 1,
 };
 #endif /* ZAURA_SHELL_ERROR_ENUM */
 
@@ -114,6 +137,19 @@
 				 struct wl_resource *resource,
 				 uint32_t id,
 				 struct wl_resource *surface);
+	/**
+	 * extend output interface for aura shell
+	 *
+	 * Instantiate an interface extension for the given wl_output to
+	 * provide aura shell functionality.
+	 * @param id the new aura output interface id
+	 * @param output the output
+	 * @since 2
+	 */
+	void (*get_aura_output)(struct wl_client *client,
+				struct wl_resource *resource,
+				uint32_t id,
+				struct wl_resource *output);
 };
 
 
@@ -121,6 +157,10 @@
  * @ingroup iface_zaura_shell
  */
 #define ZAURA_SHELL_GET_AURA_SURFACE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zaura_shell
+ */
+#define ZAURA_SHELL_GET_AURA_OUTPUT_SINCE_VERSION 2
 
 #ifndef ZAURA_SURFACE_FRAME_TYPE_ENUM
 #define ZAURA_SURFACE_FRAME_TYPE_ENUM
@@ -160,6 +200,18 @@
 	void (*set_frame)(struct wl_client *client,
 			  struct wl_resource *resource,
 			  uint32_t type);
+	/**
+	 * set the parent of this surface
+	 *
+	 * Set the "parent" of this surface. "x" and "y" arguments
+	 * specify the initial position for surface relative to parent.
+	 * @since 2
+	 */
+	void (*set_parent)(struct wl_client *client,
+			   struct wl_resource *resource,
+			   struct wl_resource *parent,
+			   int32_t x,
+			   int32_t y);
 };
 
 
@@ -167,6 +219,70 @@
  * @ingroup iface_zaura_surface
  */
 #define ZAURA_SURFACE_SET_FRAME_SINCE_VERSION 1
+/**
+ * @ingroup iface_zaura_surface
+ */
+#define ZAURA_SURFACE_SET_PARENT_SINCE_VERSION 2
+
+#ifndef ZAURA_OUTPUT_SCALE_PROPERTY_ENUM
+#define ZAURA_OUTPUT_SCALE_PROPERTY_ENUM
+/**
+ * @ingroup iface_zaura_output
+ * scale information
+ *
+ * These flags describe properties of an output scale.
+ * They are used in the flags bitfield of the scale event.
+ */
+enum zaura_output_scale_property {
+	/**
+	 * indicates this is the current scale
+	 */
+	ZAURA_OUTPUT_SCALE_PROPERTY_CURRENT = 0x1,
+	/**
+	 * indicates this is the preferred scale
+	 */
+	ZAURA_OUTPUT_SCALE_PROPERTY_PREFERRED = 0x2,
+};
+#endif /* ZAURA_OUTPUT_SCALE_PROPERTY_ENUM */
+
+#ifndef ZAURA_OUTPUT_SCALE_FACTOR_ENUM
+#define ZAURA_OUTPUT_SCALE_FACTOR_ENUM
+enum zaura_output_scale_factor {
+	ZAURA_OUTPUT_SCALE_FACTOR_0500 = 500,
+	ZAURA_OUTPUT_SCALE_FACTOR_0600 = 600,
+	ZAURA_OUTPUT_SCALE_FACTOR_0625 = 625,
+	ZAURA_OUTPUT_SCALE_FACTOR_0750 = 750,
+	ZAURA_OUTPUT_SCALE_FACTOR_0800 = 800,
+	ZAURA_OUTPUT_SCALE_FACTOR_1000 = 1000,
+	ZAURA_OUTPUT_SCALE_FACTOR_1125 = 1125,
+	ZAURA_OUTPUT_SCALE_FACTOR_1200 = 1200,
+	ZAURA_OUTPUT_SCALE_FACTOR_1250 = 1250,
+	ZAURA_OUTPUT_SCALE_FACTOR_1500 = 1500,
+	ZAURA_OUTPUT_SCALE_FACTOR_1600 = 1600,
+	ZAURA_OUTPUT_SCALE_FACTOR_2000 = 2000,
+};
+#endif /* ZAURA_OUTPUT_SCALE_FACTOR_ENUM */
+
+#define ZAURA_OUTPUT_SCALE 0
+
+/**
+ * @ingroup iface_zaura_output
+ */
+#define ZAURA_OUTPUT_SCALE_SINCE_VERSION 1
+
+
+/**
+ * @ingroup iface_zaura_output
+ * Sends an scale event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param flags bitfield of scale flags
+ * @param scale output scale
+ */
+static inline void
+zaura_output_send_scale(struct wl_resource *resource_, uint32_t flags, uint32_t scale)
+{
+	wl_resource_post_event(resource_, ZAURA_OUTPUT_SCALE, flags, scale);
+}
 
 #ifdef  __cplusplus
 }
diff --git a/components/exo/wayland/protocol/aura-shell.xml b/components/exo/wayland/protocol/aura-shell.xml
index 01f8e33..f4d99e7 100644
--- a/components/exo/wayland/protocol/aura-shell.xml
+++ b/components/exo/wayland/protocol/aura-shell.xml
@@ -24,7 +24,7 @@
     DEALINGS IN THE SOFTWARE.
   </copyright>
 
-  <interface name="zaura_shell" version="1">
+  <interface name="zaura_shell" version="2">
     <description summary="aura_shell">
       The global interface exposing aura shell capabilities is used to
       instantiate an interface extension for a wl_surface object.
@@ -35,6 +35,8 @@
     <enum name="error">
       <entry name="aura_surface_exists" value="0"
 	     summary="the surface already has an aura surface object associated"/>
+      <entry name="aura_output_exists" value="1"
+	     summary="the output already has an aura output object associated"/>
     </enum>
 
     <request name="get_aura_surface">
@@ -50,9 +52,23 @@
       <arg name="surface" type="object" interface="wl_surface"
 	   summary="the surface"/>
     </request>
+
+    <!-- Version 2 additions -->
+
+    <request name="get_aura_output" since="2">
+      <description summary="extend output interface for aura shell">
+	Instantiate an interface extension for the given wl_output to
+	provide aura shell functionality.
+      </description>
+
+      <arg name="id" type="new_id" interface="zaura_output"
+	   summary="the new aura output interface id"/>
+      <arg name="output" type="object" interface="wl_output"
+	   summary="the output"/>
+    </request>
   </interface>
 
-  <interface name="zaura_surface" version="1">
+  <interface name="zaura_surface" version="2">
     <description summary="aura shell interface to a wl_surface">
       An additional interface to a wl_surface object, which allows the
       client to access aura shell specific functionality for surface.
@@ -73,6 +89,67 @@
       </description>
       <arg name="type" type="uint" summary="the new frame type"/>
     </request>
+
+    <!-- Version 2 additions -->
+
+    <request name="set_parent" since="2">
+      <description summary="set the parent of this surface">
+	Set the "parent" of this surface. "x" and "y" arguments specify the
+	initial position for surface relative to parent.
+      </description>
+      <arg name="parent" type="object" interface="zaura_surface" allow-null="true"/>
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+    </request>
   </interface>
 
+  <interface name="zaura_output" version="2">
+    <description summary="aura shell interface to a wl_output">
+      An additional interface to a wl_output object, which allows the
+      client to access aura shell specific functionality for output.
+    </description>
+
+    <!-- Version 2 additions -->
+
+    <enum name="scale_property" bitfield="true">
+      <description summary="scale information">
+	These flags describe properties of an output scale.
+	They are used in the flags bitfield of the scale event.
+      </description>
+      <entry name="current" value="0x1"
+	     summary="indicates this is the current scale"/>
+      <entry name="preferred" value="0x2"
+	     summary="indicates this is the preferred scale"/>
+    </enum>
+
+    <enum name="scale_factor">
+      <entry name="0500" value="500"/>
+      <entry name="0600" value="600"/>
+      <entry name="0625" value="625"/>
+      <entry name="0750" value="750"/>
+      <entry name="0800" value="800"/>
+      <entry name="1000" value="1000"/>
+      <entry name="1125" value="1125"/>
+      <entry name="1200" value="1200"/>
+      <entry name="1250" value="1250"/>
+      <entry name="1500" value="1500"/>
+      <entry name="1600" value="1600"/>
+      <entry name="2000" value="2000"/>
+    </enum>
+
+    <event name="scale">
+      <description summary="advertise available scales for the output">
+	The scale event describes an available scale for the output.
+
+	The event is sent when binding to the output object and there
+	will always be one scale, the current scale. The event is sent
+	again if an output changes scale, for the scale that is now
+	current. In other words, the current scale is always the last
+	scale that was received with the current flag set.
+      </description>
+      <arg name="flags" type="uint" enum="scale_property" summary="bitfield of scale flags"/>
+      <arg name="scale" type="uint" enum="scale_factor" summary="output scale"/>
+    </event>
+ </interface>
+
 </protocol>
diff --git a/components/viz/common/gpu/in_process_context_provider.cc b/components/viz/common/gpu/in_process_context_provider.cc
index 7c94a6d..46c479fb 100644
--- a/components/viz/common/gpu/in_process_context_provider.cc
+++ b/components/viz/common/gpu/in_process_context_provider.cc
@@ -30,7 +30,6 @@
 #include "third_party/khronos/GLES2/gl2ext.h"
 #include "third_party/skia/include/gpu/GrContext.h"
 #include "third_party/skia/include/gpu/gl/GrGLInterface.h"
-#include "ui/gfx/native_widget_types.h"
 
 namespace viz {
 
@@ -52,7 +51,7 @@
 
 InProcessContextProvider::InProcessContextProvider(
     scoped_refptr<gpu::InProcessCommandBuffer::Service> service,
-    gpu::SurfaceHandle widget,
+    gpu::SurfaceHandle surface_handle,
     gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
     gpu::ImageFactory* image_factory,
     const gpu::SharedMemoryLimits& limits,
@@ -62,8 +61,8 @@
       context_result_(context_->Initialize(
           std::move(service),
           nullptr,
-          (widget == gpu::kNullSurfaceHandle),
-          widget,
+          (surface_handle == gpu::kNullSurfaceHandle),
+          surface_handle,
           (shared_context ? shared_context->context_.get() : nullptr),
           attributes_,
           limits,
diff --git a/components/viz/common/gpu/in_process_context_provider.h b/components/viz/common/gpu/in_process_context_provider.h
index d73409c..eeef36d 100644
--- a/components/viz/common/gpu/in_process_context_provider.h
+++ b/components/viz/common/gpu/in_process_context_provider.h
@@ -37,7 +37,7 @@
  public:
   InProcessContextProvider(
       scoped_refptr<gpu::InProcessCommandBuffer::Service> service,
-      gpu::SurfaceHandle widget,
+      gpu::SurfaceHandle surface_handle,
       gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
       gpu::ImageFactory* image_factory,
       const gpu::SharedMemoryLimits& limits,
diff --git a/components/viz/host/host_frame_sink_manager.cc b/components/viz/host/host_frame_sink_manager.cc
index 17f812d7..ca1af0f 100644
--- a/components/viz/host/host_frame_sink_manager.cc
+++ b/components/viz/host/host_frame_sink_manager.cc
@@ -97,6 +97,7 @@
 void HostFrameSinkManager::CreateRootCompositorFrameSink(
     const FrameSinkId& frame_sink_id,
     gpu::SurfaceHandle surface_handle,
+    bool force_software_compositing,
     const RendererSettings& renderer_settings,
     mojom::CompositorFrameSinkAssociatedRequest request,
     mojom::CompositorFrameSinkClientPtr client,
@@ -109,8 +110,9 @@
   data.has_created_compositor_frame_sink = true;
 
   frame_sink_manager_->CreateRootCompositorFrameSink(
-      frame_sink_id, surface_handle, renderer_settings, std::move(request),
-      std::move(client), std::move(display_private_request));
+      frame_sink_id, surface_handle, force_software_compositing,
+      renderer_settings, std::move(request), std::move(client),
+      std::move(display_private_request));
   display_hit_test_query_[frame_sink_id] = base::MakeUnique<HitTestQuery>();
 }
 
diff --git a/components/viz/host/host_frame_sink_manager.h b/components/viz/host/host_frame_sink_manager.h
index 5e007f3..d91ed439 100644
--- a/components/viz/host/host_frame_sink_manager.h
+++ b/components/viz/host/host_frame_sink_manager.h
@@ -93,6 +93,7 @@
   void CreateRootCompositorFrameSink(
       const FrameSinkId& frame_sink_id,
       gpu::SurfaceHandle surface_handle,
+      bool force_software_compositing,
       const RendererSettings& renderer_settings,
       mojom::CompositorFrameSinkAssociatedRequest request,
       mojom::CompositorFrameSinkClientPtr client,
diff --git a/components/viz/host/host_frame_sink_manager_unittest.cc b/components/viz/host/host_frame_sink_manager_unittest.cc
index a08db51..697c8b4 100644
--- a/components/viz/host/host_frame_sink_manager_unittest.cc
+++ b/components/viz/host/host_frame_sink_manager_unittest.cc
@@ -74,6 +74,7 @@
   void CreateRootCompositorFrameSink(
       const FrameSinkId& frame_sink_id,
       gpu::SurfaceHandle surface_handle,
+      bool force_software_compositor,
       const RendererSettings& renderer_settings,
       mojom::CompositorFrameSinkAssociatedRequest request,
       mojom::CompositorFrameSinkClientPtr client,
@@ -520,6 +521,7 @@
   EXPECT_FALSE(DisplayHitTestQueryExists(kFrameSinkChild1));
   host().CreateRootCompositorFrameSink(
       kFrameSinkChild1, 0 /* surface_handle */,
+      false /* force_software_compositing */,
       RendererSettings() /* renderer_settings */, nullptr /* request */,
       nullptr /* client */, nullptr /* display_private_request */);
   EXPECT_TRUE(DisplayHitTestQueryExists(kFrameSinkChild1));
@@ -596,6 +598,7 @@
   mojom::DisplayPrivateAssociatedPtr display_private;
   host().CreateRootCompositorFrameSink(
       kFrameSinkChild1, 0 /* surface_handle */,
+      false /* force_software_compositing */,
       RendererSettings() /* renderer_settings */,
       MakeRequest(&compositor_frame_sink_associated_info),
       compositor_frame_sink_client.BindInterfacePtr(),
diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn
index 53fb4558..edb3cc78 100644
--- a/components/viz/service/BUILD.gn
+++ b/components/viz/service/BUILD.gn
@@ -79,9 +79,9 @@
     "display_embedder/compositing_mode_reporter_impl.cc",
     "display_embedder/compositing_mode_reporter_impl.h",
     "display_embedder/compositor_overlay_candidate_validator.h",
-    "display_embedder/display_output_surface.cc",
-    "display_embedder/display_output_surface.h",
     "display_embedder/display_provider.h",
+    "display_embedder/gl_output_surface.cc",
+    "display_embedder/gl_output_surface.h",
     "display_embedder/gpu_display_provider.cc",
     "display_embedder/gpu_display_provider.h",
     "display_embedder/in_process_gpu_memory_buffer_manager.cc",
@@ -90,6 +90,8 @@
     "display_embedder/server_shared_bitmap_manager.h",
     "display_embedder/shared_bitmap_allocation_notifier_impl.cc",
     "display_embedder/shared_bitmap_allocation_notifier_impl.h",
+    "display_embedder/software_output_surface.cc",
+    "display_embedder/software_output_surface.h",
     "frame_sinks/compositor_frame_sink_impl.cc",
     "frame_sinks/compositor_frame_sink_impl.h",
     "frame_sinks/compositor_frame_sink_support.cc",
@@ -219,8 +221,8 @@
     sources += [
       "display_embedder/compositor_overlay_candidate_validator_ozone.cc",
       "display_embedder/compositor_overlay_candidate_validator_ozone.h",
-      "display_embedder/display_output_surface_ozone.cc",
-      "display_embedder/display_output_surface_ozone.h",
+      "display_embedder/gl_output_surface_ozone.cc",
+      "display_embedder/gl_output_surface_ozone.h",
       "display_embedder/software_output_device_ozone.cc",
       "display_embedder/software_output_device_ozone.h",
     ]
diff --git a/components/viz/service/display_embedder/display_provider.h b/components/viz/service/display_embedder/display_provider.h
index be728d87..4eabbb1 100644
--- a/components/viz/service/display_embedder/display_provider.h
+++ b/components/viz/service/display_embedder/display_provider.h
@@ -23,9 +23,12 @@
 
   // Creates a new Display for |surface_handle| with |frame_sink_id|. Will
   // also create BeginFrameSource and return it in |begin_frame_source|.
+  // If |force_software_compositing| is true, then the resulting display
+  // compositor will not use Gpu acceleration even if it would by default.
   virtual std::unique_ptr<Display> CreateDisplay(
       const FrameSinkId& frame_sink_id,
       gpu::SurfaceHandle surface_handle,
+      bool force_software_compositing,
       const RendererSettings& renderer_settings,
       std::unique_ptr<SyntheticBeginFrameSource>* out_begin_frame_source) = 0;
 };
diff --git a/components/viz/service/display_embedder/display_output_surface.cc b/components/viz/service/display_embedder/gl_output_surface.cc
similarity index 63%
rename from components/viz/service/display_embedder/display_output_surface.cc
rename to components/viz/service/display_embedder/gl_output_surface.cc
index d598c84..684ea912 100644
--- a/components/viz/service/display_embedder/display_output_surface.cc
+++ b/components/viz/service/display_embedder/gl_output_surface.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 "components/viz/service/display_embedder/display_output_surface.h"
+#include "components/viz/service/display_embedder/gl_output_surface.h"
 
 #include <stdint.h>
 
@@ -19,7 +19,7 @@
 
 namespace viz {
 
-DisplayOutputSurface::DisplayOutputSurface(
+GLOutputSurface::GLOutputSurface(
     scoped_refptr<InProcessContextProvider> context_provider,
     SyntheticBeginFrameSource* synthetic_begin_frame_source)
     : OutputSurface(context_provider),
@@ -32,34 +32,34 @@
   capabilities_.supports_stencil =
       context_provider->ContextCapabilities().num_stencil_bits > 0;
   context_provider->SetSwapBuffersCompletionCallback(
-      base::Bind(&DisplayOutputSurface::OnGpuSwapBuffersCompleted,
-                 weak_ptr_factory_.GetWeakPtr()));
+      base::BindRepeating(&GLOutputSurface::OnGpuSwapBuffersCompleted,
+                          weak_ptr_factory_.GetWeakPtr()));
   context_provider->SetUpdateVSyncParametersCallback(
-      base::Bind(&DisplayOutputSurface::OnVSyncParametersUpdated,
-                 weak_ptr_factory_.GetWeakPtr()));
-  context_provider->SetPresentationCallback(base::Bind(
-      &DisplayOutputSurface::OnPresentation, weak_ptr_factory_.GetWeakPtr()));
+      base::BindRepeating(&GLOutputSurface::OnVSyncParametersUpdated,
+                          weak_ptr_factory_.GetWeakPtr()));
+  context_provider->SetPresentationCallback(base::BindRepeating(
+      &GLOutputSurface::OnPresentation, weak_ptr_factory_.GetWeakPtr()));
 }
 
-DisplayOutputSurface::~DisplayOutputSurface() {}
+GLOutputSurface::~GLOutputSurface() {}
 
-void DisplayOutputSurface::BindToClient(OutputSurfaceClient* client) {
+void GLOutputSurface::BindToClient(OutputSurfaceClient* client) {
   DCHECK(client);
   DCHECK(!client_);
   client_ = client;
 }
 
-void DisplayOutputSurface::EnsureBackbuffer() {}
+void GLOutputSurface::EnsureBackbuffer() {}
 
-void DisplayOutputSurface::DiscardBackbuffer() {
+void GLOutputSurface::DiscardBackbuffer() {
   context_provider()->ContextGL()->DiscardBackbufferCHROMIUM();
 }
 
-void DisplayOutputSurface::BindFramebuffer() {
+void GLOutputSurface::BindFramebuffer() {
   context_provider()->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, 0);
 }
 
-void DisplayOutputSurface::SetDrawRectangle(const gfx::Rect& rect) {
+void GLOutputSurface::SetDrawRectangle(const gfx::Rect& rect) {
   if (set_draw_rectangle_for_frame_)
     return;
   DCHECK(gfx::Rect(size_).Contains(rect));
@@ -71,11 +71,11 @@
       rect.x(), rect.y(), rect.width(), rect.height());
 }
 
-void DisplayOutputSurface::Reshape(const gfx::Size& size,
-                                   float device_scale_factor,
-                                   const gfx::ColorSpace& color_space,
-                                   bool has_alpha,
-                                   bool use_stencil) {
+void GLOutputSurface::Reshape(const gfx::Size& size,
+                              float device_scale_factor,
+                              const gfx::ColorSpace& color_space,
+                              bool has_alpha,
+                              bool use_stencil) {
   size_ = size;
   has_set_draw_rectangle_since_last_resize_ = false;
   context_provider()->ContextGL()->ResizeCHROMIUM(
@@ -83,7 +83,7 @@
       gl::GetGLColorSpace(color_space), has_alpha);
 }
 
-void DisplayOutputSurface::SwapBuffers(OutputSurfaceFrame frame) {
+void GLOutputSurface::SwapBuffers(OutputSurfaceFrame frame) {
   DCHECK(context_provider_);
 
   if (latency_info_cache_.WillSwap(std::move(frame.latency_info)))
@@ -98,68 +98,68 @@
   }
 }
 
-uint32_t DisplayOutputSurface::GetFramebufferCopyTextureFormat() {
+uint32_t GLOutputSurface::GetFramebufferCopyTextureFormat() {
   // TODO(danakj): What attributes are used for the default framebuffer here?
   // Can it have alpha? InProcessContextProvider doesn't take any
   // attributes.
   return GL_RGB;
 }
 
-OverlayCandidateValidator* DisplayOutputSurface::GetOverlayCandidateValidator()
+OverlayCandidateValidator* GLOutputSurface::GetOverlayCandidateValidator()
     const {
   return nullptr;
 }
 
-bool DisplayOutputSurface::IsDisplayedAsOverlayPlane() const {
+bool GLOutputSurface::IsDisplayedAsOverlayPlane() const {
   return false;
 }
 
-unsigned DisplayOutputSurface::GetOverlayTextureId() const {
+unsigned GLOutputSurface::GetOverlayTextureId() const {
   return 0;
 }
 
-gfx::BufferFormat DisplayOutputSurface::GetOverlayBufferFormat() const {
+gfx::BufferFormat GLOutputSurface::GetOverlayBufferFormat() const {
   return gfx::BufferFormat::RGBX_8888;
 }
 
-bool DisplayOutputSurface::SurfaceIsSuspendForRecycle() const {
+bool GLOutputSurface::SurfaceIsSuspendForRecycle() const {
   return false;
 }
 
-bool DisplayOutputSurface::HasExternalStencilTest() const {
+bool GLOutputSurface::HasExternalStencilTest() const {
   return false;
 }
 
-void DisplayOutputSurface::ApplyExternalStencil() {}
+void GLOutputSurface::ApplyExternalStencil() {}
 
-void DisplayOutputSurface::DidReceiveSwapBuffersAck(gfx::SwapResult result,
-                                                    uint64_t swap_id) {
+void GLOutputSurface::DidReceiveSwapBuffersAck(gfx::SwapResult result,
+                                               uint64_t swap_id) {
   client_->DidReceiveSwapBuffersAck(swap_id);
 }
 
-void DisplayOutputSurface::OnGpuSwapBuffersCompleted(
+void GLOutputSurface::OnGpuSwapBuffersCompleted(
     const gfx::SwapResponse& response,
     const gpu::GpuProcessHostedCALayerTreeParamsMac* params_mac) {
   DidReceiveSwapBuffersAck(response.result, response.swap_id);
   latency_info_cache_.OnSwapBuffersCompleted(response);
 }
 
-void DisplayOutputSurface::LatencyInfoCompleted(
+void GLOutputSurface::LatencyInfoCompleted(
     const std::vector<ui::LatencyInfo>& latency_info) {
   for (const auto& latency : latency_info) {
     latency_tracker_.OnGpuSwapBuffersCompleted(latency);
   }
 }
 
-void DisplayOutputSurface::OnVSyncParametersUpdated(base::TimeTicks timebase,
-                                                    base::TimeDelta interval) {
+void GLOutputSurface::OnVSyncParametersUpdated(base::TimeTicks timebase,
+                                               base::TimeDelta interval) {
   // TODO(brianderson): We should not be receiving 0 intervals.
   synthetic_begin_frame_source_->OnUpdateVSyncParameters(
       timebase,
       interval.is_zero() ? BeginFrameArgs::DefaultInterval() : interval);
 }
 
-void DisplayOutputSurface::OnPresentation(
+void GLOutputSurface::OnPresentation(
     uint64_t swap_id,
     const gfx::PresentationFeedback& feedback) {
   client_->DidReceivePresentationFeedback(swap_id, feedback);
diff --git a/components/viz/service/display_embedder/display_output_surface.h b/components/viz/service/display_embedder/gl_output_surface.h
similarity index 81%
rename from components/viz/service/display_embedder/display_output_surface.h
rename to components/viz/service/display_embedder/gl_output_surface.h
index 457b24c7..7f4769c 100644
--- a/components/viz/service/display_embedder/display_output_surface.h
+++ b/components/viz/service/display_embedder/gl_output_surface.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 COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_DISPLAY_OUTPUT_SURFACE_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_DISPLAY_OUTPUT_SURFACE_H_
+#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_H_
 
 #include <memory>
 
@@ -17,12 +17,12 @@
 
 // An OutputSurface implementation that directly draws and
 // swaps to an actual GL surface.
-class DisplayOutputSurface : public OutputSurface,
-                             public OutputSurface::LatencyInfoCache::Client {
+class GLOutputSurface : public OutputSurface,
+                        public OutputSurface::LatencyInfoCache::Client {
  public:
-  DisplayOutputSurface(scoped_refptr<InProcessContextProvider> context_provider,
-                       SyntheticBeginFrameSource* synthetic_begin_frame_source);
-  ~DisplayOutputSurface() override;
+  GLOutputSurface(scoped_refptr<InProcessContextProvider> context_provider,
+                  SyntheticBeginFrameSource* synthetic_begin_frame_source);
+  ~GLOutputSurface() override;
 
   // OutputSurface implementation
   void BindToClient(OutputSurfaceClient* client) override;
@@ -76,9 +76,9 @@
   gfx::Size size_;
   LatencyInfoCache latency_info_cache_;
 
-  base::WeakPtrFactory<DisplayOutputSurface> weak_ptr_factory_;
+  base::WeakPtrFactory<GLOutputSurface> weak_ptr_factory_;
 };
 
 }  // namespace viz
 
-#endif  // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_DISPLAY_OUTPUT_SURFACE_H_
+#endif  // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_H_
diff --git a/components/viz/service/display_embedder/display_output_surface_ozone.cc b/components/viz/service/display_embedder/gl_output_surface_ozone.cc
similarity index 73%
rename from components/viz/service/display_embedder/display_output_surface_ozone.cc
rename to components/viz/service/display_embedder/gl_output_surface_ozone.cc
index 6ddb997..197830e 100644
--- a/components/viz/service/display_embedder/display_output_surface_ozone.cc
+++ b/components/viz/service/display_embedder/gl_output_surface_ozone.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 "components/viz/service/display_embedder/display_output_surface_ozone.h"
+#include "components/viz/service/display_embedder/gl_output_surface_ozone.h"
 
 #include <utility>
 
@@ -19,14 +19,14 @@
 
 namespace viz {
 
-DisplayOutputSurfaceOzone::DisplayOutputSurfaceOzone(
+GLOutputSurfaceOzone::GLOutputSurfaceOzone(
     scoped_refptr<InProcessContextProvider> context_provider,
     gfx::AcceleratedWidget widget,
     SyntheticBeginFrameSource* synthetic_begin_frame_source,
     gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
     uint32_t target,
     uint32_t internalformat)
-    : DisplayOutputSurface(context_provider, synthetic_begin_frame_source),
+    : GLOutputSurface(context_provider, synthetic_begin_frame_source),
       gl_helper_(context_provider->ContextGL(),
                  context_provider->ContextSupport()) {
   capabilities_.uses_default_gl_framebuffer = false;
@@ -47,11 +47,11 @@
   buffer_queue_->Initialize();
 }
 
-DisplayOutputSurfaceOzone::~DisplayOutputSurfaceOzone() {
+GLOutputSurfaceOzone::~GLOutputSurfaceOzone() {
   // TODO(rjkroege): Support cleanup.
 }
 
-void DisplayOutputSurfaceOzone::BindFramebuffer() {
+void GLOutputSurfaceOzone::BindFramebuffer() {
   DCHECK(buffer_queue_);
   buffer_queue_->BindFramebuffer();
 }
@@ -62,18 +62,18 @@
 // implies that screen size changes need to be plumbed differently. In
 // particular, we must create the native window in the size that the hardware
 // reports.
-void DisplayOutputSurfaceOzone::Reshape(const gfx::Size& size,
-                                        float device_scale_factor,
-                                        const gfx::ColorSpace& color_space,
-                                        bool has_alpha,
-                                        bool use_stencil) {
+void GLOutputSurfaceOzone::Reshape(const gfx::Size& size,
+                                   float device_scale_factor,
+                                   const gfx::ColorSpace& color_space,
+                                   bool has_alpha,
+                                   bool use_stencil) {
   reshape_size_ = size;
-  DisplayOutputSurface::Reshape(size, device_scale_factor, color_space,
-                                has_alpha, use_stencil);
+  GLOutputSurface::Reshape(size, device_scale_factor, color_space, has_alpha,
+                           use_stencil);
   buffer_queue_->Reshape(size, device_scale_factor, color_space, use_stencil);
 }
 
-void DisplayOutputSurfaceOzone::SwapBuffers(OutputSurfaceFrame frame) {
+void GLOutputSurfaceOzone::SwapBuffers(OutputSurfaceFrame frame) {
   DCHECK(buffer_queue_);
 
   // TODO(rjkroege): What if swap happens again before DidReceiveSwapBuffersAck
@@ -85,29 +85,29 @@
       frame.sub_buffer_rect ? *frame.sub_buffer_rect : gfx::Rect(swap_size_);
   buffer_queue_->SwapBuffers(damage_rect);
 
-  DisplayOutputSurface::SwapBuffers(std::move(frame));
+  GLOutputSurface::SwapBuffers(std::move(frame));
 }
 
-uint32_t DisplayOutputSurfaceOzone::GetFramebufferCopyTextureFormat() {
+uint32_t GLOutputSurfaceOzone::GetFramebufferCopyTextureFormat() {
   return buffer_queue_->internal_format();
 }
 
-bool DisplayOutputSurfaceOzone::IsDisplayedAsOverlayPlane() const {
+bool GLOutputSurfaceOzone::IsDisplayedAsOverlayPlane() const {
   // TODO(rjkroege): implement remaining overlay functionality.
   return true;
 }
 
-unsigned DisplayOutputSurfaceOzone::GetOverlayTextureId() const {
+unsigned GLOutputSurfaceOzone::GetOverlayTextureId() const {
   return buffer_queue_->GetCurrentTextureId();
 }
 
-gfx::BufferFormat DisplayOutputSurfaceOzone::GetOverlayBufferFormat() const {
+gfx::BufferFormat GLOutputSurfaceOzone::GetOverlayBufferFormat() const {
   DCHECK(buffer_queue_);
   return buffer_queue_->buffer_format();
 }
 
-void DisplayOutputSurfaceOzone::DidReceiveSwapBuffersAck(gfx::SwapResult result,
-                                                         uint64_t swap_id) {
+void GLOutputSurfaceOzone::DidReceiveSwapBuffersAck(gfx::SwapResult result,
+                                                    uint64_t swap_id) {
   bool force_swap = false;
   if (result == gfx::SwapResult::SWAP_NAK_RECREATE_BUFFERS) {
     // Even through the swap failed, this is a fixable error so we can pretend
diff --git a/components/viz/service/display_embedder/display_output_surface_ozone.h b/components/viz/service/display_embedder/gl_output_surface_ozone.h
similarity index 68%
rename from components/viz/service/display_embedder/display_output_surface_ozone.h
rename to components/viz/service/display_embedder/gl_output_surface_ozone.h
index 24d8970..251c124 100644
--- a/components/viz/service/display_embedder/display_output_surface_ozone.h
+++ b/components/viz/service/display_embedder/gl_output_surface_ozone.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 COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_DISPLAY_OUTPUT_SURFACE_OZONE_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_DISPLAY_OUTPUT_SURFACE_OZONE_H_
+#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_OZONE_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_OZONE_H_
 
 #include <memory>
 
@@ -12,7 +12,7 @@
 #include "components/viz/common/gpu/context_provider.h"
 #include "components/viz/common/gpu/in_process_context_provider.h"
 #include "components/viz/service/display/output_surface.h"
-#include "components/viz/service/display_embedder/display_output_surface.h"
+#include "components/viz/service/display_embedder/gl_output_surface.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gfx/swap_result.h"
@@ -31,17 +31,16 @@
 // "surfaceless" surface (aka one backed by a buffer managed explicitly in
 // mus/ozone. This class is adapted from
 // GpuSurfacelessBrowserCompositorOutputSurface.
-class DisplayOutputSurfaceOzone : public DisplayOutputSurface {
+class GLOutputSurfaceOzone : public GLOutputSurface {
  public:
-  DisplayOutputSurfaceOzone(
-      scoped_refptr<InProcessContextProvider> context_provider,
-      gfx::AcceleratedWidget widget,
-      SyntheticBeginFrameSource* synthetic_begin_frame_source,
-      gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
-      uint32_t target,
-      uint32_t internalformat);
+  GLOutputSurfaceOzone(scoped_refptr<InProcessContextProvider> context_provider,
+                       gfx::AcceleratedWidget widget,
+                       SyntheticBeginFrameSource* synthetic_begin_frame_source,
+                       gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+                       uint32_t target,
+                       uint32_t internalformat);
 
-  ~DisplayOutputSurfaceOzone() override;
+  ~GLOutputSurfaceOzone() override;
 
   // TODO(rjkroege): Implement the equivalent of Reflector.
 
@@ -59,7 +58,7 @@
   unsigned GetOverlayTextureId() const override;
   gfx::BufferFormat GetOverlayBufferFormat() const override;
 
-  // DisplayOutputSurface:
+  // GLOutputSurface:
   void DidReceiveSwapBuffersAck(gfx::SwapResult result,
                                 uint64_t swap_id) override;
 
@@ -69,9 +68,9 @@
   gfx::Size reshape_size_;
   gfx::Size swap_size_;
 
-  DISALLOW_COPY_AND_ASSIGN(DisplayOutputSurfaceOzone);
+  DISALLOW_COPY_AND_ASSIGN(GLOutputSurfaceOzone);
 };
 
 }  // namespace viz
 
-#endif  // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_DISPLAY_OUTPUT_SURFACE_OZONE_H_
+#endif  // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_OZONE_H_
diff --git a/components/viz/service/display_embedder/gpu_display_provider.cc b/components/viz/service/display_embedder/gpu_display_provider.cc
index 20398b8d..b7184da3 100644
--- a/components/viz/service/display_embedder/gpu_display_provider.cc
+++ b/components/viz/service/display_embedder/gpu_display_provider.cc
@@ -16,18 +16,36 @@
 #include "components/viz/service/display/display.h"
 #include "components/viz/service/display/display_scheduler.h"
 #include "components/viz/service/display_embedder/compositing_mode_reporter_impl.h"
-#include "components/viz/service/display_embedder/display_output_surface.h"
+#include "components/viz/service/display_embedder/gl_output_surface.h"
 #include "components/viz/service/display_embedder/in_process_gpu_memory_buffer_manager.h"
 #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
+#include "components/viz/service/display_embedder/software_output_surface.h"
 #include "gpu/command_buffer/client/shared_memory_limits.h"
 #include "gpu/command_buffer/service/image_factory.h"
+#include "gpu/ipc/common/surface_handle.h"
 #include "gpu/ipc/service/gpu_channel_manager.h"
 #include "gpu/ipc/service/gpu_memory_buffer_factory.h"
 #include "ui/base/ui_base_switches.h"
 
+#if defined(OS_WIN)
+#include "components/viz/service/display_embedder/software_output_device_win.h"
+#endif
+
+#if defined(OS_MACOSX)
+#include "components/viz/service/display_embedder/software_output_device_mac.h"
+#endif
+
+#if defined(USE_X11)
+#include "components/viz/service/display_embedder/software_output_device_x11.h"
+#endif
+
 #if defined(USE_OZONE)
-#include "components/viz/service/display_embedder/display_output_surface_ozone.h"
+#include "components/viz/service/display_embedder/gl_output_surface_ozone.h"
+#include "components/viz/service/display_embedder/software_output_device_ozone.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
+#include "ui/ozone/public/ozone_platform.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
+#include "ui/ozone/public/surface_ozone_canvas.h"
 #endif
 
 namespace {
@@ -62,6 +80,7 @@
 std::unique_ptr<Display> GpuDisplayProvider::CreateDisplay(
     const FrameSinkId& frame_sink_id,
     gpu::SurfaceHandle surface_handle,
+    bool force_software_compositing,
     const RendererSettings& renderer_settings,
     std::unique_ptr<SyntheticBeginFrameSource>* out_begin_frame_source) {
   auto synthetic_begin_frame_source =
@@ -70,37 +89,54 @@
           restart_id_);
 
   // TODO(crbug.com/730660): Fallback to software if gpu doesn't work with
-  // compositing_mode_reporter_->SetUsingSoftwareCompositing();
+  // compositing_mode_reporter_->SetUsingSoftwareCompositing(), and once that
+  // is done, always make software-based Displays only.
+  bool gpu_compositing = !force_software_compositing;
   (void)compositing_mode_reporter_;
 
-  scoped_refptr<InProcessContextProvider> context_provider =
-      new InProcessContextProvider(gpu_service_, surface_handle,
-                                   gpu_memory_buffer_manager_.get(),
-                                   image_factory_, gpu::SharedMemoryLimits(),
-                                   nullptr /* shared_context */);
-
-  // TODO(rjkroege): If there is something better to do than CHECK, add it.
-  // TODO(danakj): Should retry if the result is kTransientFailure.
-  auto result = context_provider->BindToCurrentThread();
-  CHECK_EQ(result, gpu::ContextResult::kSuccess);
-
-  std::unique_ptr<OutputSurface> display_output_surface;
-  if (context_provider->ContextCapabilities().surfaceless) {
-#if defined(USE_OZONE)
-    display_output_surface = base::MakeUnique<DisplayOutputSurfaceOzone>(
-        std::move(context_provider), surface_handle,
-        synthetic_begin_frame_source.get(), gpu_memory_buffer_manager_.get(),
-        GL_TEXTURE_2D, GL_RGB);
+#if !defined(GPU_SURFACE_HANDLE_IS_ACCELERATED_WINDOW)
+  // TODO(crbug.com/730660): On Mac/Android the handle is not an
+  // AcceleratedWidget, and the widget is only available in the browser process
+  // via GpuSurfaceTracker (and maybe can't be used in the viz process??)
+  NOTIMPLEMENTED();
+  gfx::AcceleratedWidget widget = 0;
+  (void)widget;
 #else
-    NOTREACHED();
+  gfx::AcceleratedWidget widget = surface_handle;
 #endif
+
+  std::unique_ptr<OutputSurface> output_surface;
+
+  if (!gpu_compositing) {
+    output_surface = std::make_unique<SoftwareOutputSurface>(
+        CreateSoftwareOutputDeviceForPlatform(widget), task_runner_);
   } else {
-    display_output_surface = base::MakeUnique<DisplayOutputSurface>(
-        std::move(context_provider), synthetic_begin_frame_source.get());
+    auto context_provider = base::MakeRefCounted<InProcessContextProvider>(
+        gpu_service_, surface_handle, gpu_memory_buffer_manager_.get(),
+        image_factory_, gpu::SharedMemoryLimits(),
+        nullptr /* shared_context */);
+
+    // TODO(rjkroege): If there is something better to do than CHECK, add it.
+    // TODO(danakj): Should retry if the result is kTransientFailure.
+    auto result = context_provider->BindToCurrentThread();
+    CHECK_EQ(result, gpu::ContextResult::kSuccess);
+
+    if (context_provider->ContextCapabilities().surfaceless) {
+#if defined(USE_OZONE)
+      output_surface = base::MakeUnique<GLOutputSurfaceOzone>(
+          std::move(context_provider), widget,
+          synthetic_begin_frame_source.get(), gpu_memory_buffer_manager_.get(),
+          GL_TEXTURE_2D, GL_RGB);
+#else
+      NOTREACHED();
+#endif
+    } else {
+      output_surface = base::MakeUnique<GLOutputSurface>(
+          std::move(context_provider), synthetic_begin_frame_source.get());
+    }
   }
 
-  int max_frames_pending =
-      display_output_surface->capabilities().max_frames_pending;
+  int max_frames_pending = output_surface->capabilities().max_frames_pending;
   DCHECK_GT(max_frames_pending, 0);
 
   auto scheduler = base::MakeUnique<DisplayScheduler>(
@@ -112,8 +148,46 @@
 
   return base::MakeUnique<Display>(
       ServerSharedBitmapManager::current(), gpu_memory_buffer_manager_.get(),
-      renderer_settings, frame_sink_id, std::move(display_output_surface),
+      renderer_settings, frame_sink_id, std::move(output_surface),
       std::move(scheduler), task_runner_);
 }
 
+std::unique_ptr<SoftwareOutputDevice>
+GpuDisplayProvider::CreateSoftwareOutputDeviceForPlatform(
+    gfx::AcceleratedWidget widget) {
+#if defined(OS_WIN)
+  if (!output_device_backing_)
+    output_device_backing_ = std::make_unique<OutputDeviceBacking>();
+  auto device = std::make_unique<SoftwareOutputDeviceWin>(
+      output_device_backing_.get(), widget);
+#elif defined(OS_MACOSX)
+  // TODO(crbug.com/730660): We don't have a widget here, so what do we do to
+  // get something we can draw to? Can we use an IO surface? Can we use CA
+  // layers and overlays like we do for gpu compositing?
+  // See https://chromium-review.googlesource.com/c/chromium/src/+/792295 to
+  // no longer have GpuSurfaceTracker.
+  // Part of the SoftwareOutputDeviceMac::EndPaint probably needs to move to
+  // the browser process, and we need to set up transport of an IO surface to
+  // here?
+  // auto device = std::make_unique<SoftwareOutputDeviceMac>(widget);
+  std::unique_ptr<SoftwareOutputDevice> device;
+  NOTIMPLEMENTED();
+#elif defined(OS_ANDROID)
+  // Android does not do software compositing, so we can't get here.
+  std::unique_ptr<SoftwareOutputDevice> device;
+  NOTREACHED();
+#elif defined(USE_OZONE)
+  ui::SurfaceFactoryOzone* factory =
+      ui::OzonePlatform::GetInstance()->GetSurfaceFactoryOzone();
+  std::unique_ptr<ui::SurfaceOzoneCanvas> surface_ozone =
+      factory->CreateCanvasForWidget(widget);
+  CHECK(surface_ozone);
+  auto device =
+      std::make_unique<SoftwareOutputDeviceOzone>(std::move(surface_ozone));
+#elif defined(USE_X11)
+  auto device = std::make_unique<SoftwareOutputDeviceX11>(widget);
+#endif
+  return device;
+}
+
 }  // namespace viz
diff --git a/components/viz/service/display_embedder/gpu_display_provider.h b/components/viz/service/display_embedder/gpu_display_provider.h
index c0ccb572..4a93727 100644
--- a/components/viz/service/display_embedder/gpu_display_provider.h
+++ b/components/viz/service/display_embedder/gpu_display_provider.h
@@ -10,6 +10,7 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "build/build_config.h"
 #include "components/viz/common/surfaces/frame_sink_id.h"
 #include "components/viz/service/display_embedder/display_provider.h"
 #include "components/viz/service/viz_service_export.h"
@@ -25,6 +26,8 @@
 namespace viz {
 class CompositingModeReporterImpl;
 class Display;
+class OutputDeviceBacking;
+class SoftwareOutputDevice;
 
 // In-process implementation of DisplayProvider.
 class VIZ_SERVICE_EXPORT GpuDisplayProvider : public DisplayProvider {
@@ -36,21 +39,30 @@
       CompositingModeReporterImpl* compositing_mode_reporter);
   ~GpuDisplayProvider() override;
 
-  // DisplayProvider:
+  // DisplayProvider implementation.
   std::unique_ptr<Display> CreateDisplay(
       const FrameSinkId& frame_sink_id,
       gpu::SurfaceHandle surface_handle,
+      bool force_software_compositing,
       const RendererSettings& renderer_settings,
       std::unique_ptr<SyntheticBeginFrameSource>* out_begin_frame_source)
       override;
 
  private:
+  std::unique_ptr<SoftwareOutputDevice> CreateSoftwareOutputDeviceForPlatform(
+      gfx::AcceleratedWidget widget);
+
   const uint32_t restart_id_;
   scoped_refptr<gpu::InProcessCommandBuffer::Service> gpu_service_;
   std::unique_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager_;
   gpu::ImageFactory* const image_factory_;
   CompositingModeReporterImpl* const compositing_mode_reporter_;
 
+#if defined(OS_WIN)
+  // Used for software compositing output on Windows.
+  std::unique_ptr<OutputDeviceBacking> output_device_backing_;
+#endif
+
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(GpuDisplayProvider);
diff --git a/components/viz/service/display_embedder/software_output_device_ozone.cc b/components/viz/service/display_embedder/software_output_device_ozone.cc
index eed0d38..ea3c84f 100644
--- a/components/viz/service/display_embedder/software_output_device_ozone.cc
+++ b/components/viz/service/display_embedder/software_output_device_ozone.cc
@@ -8,34 +8,13 @@
 
 #include "ui/gfx/skia_util.h"
 #include "ui/gfx/vsync_provider.h"
-#include "ui/ozone/public/ozone_platform.h"
-#include "ui/ozone/public/surface_factory_ozone.h"
 #include "ui/ozone/public/surface_ozone_canvas.h"
 
 namespace viz {
 
-// static
-std::unique_ptr<SoftwareOutputDeviceOzone> SoftwareOutputDeviceOzone::Create(
-    gfx::AcceleratedWidget widget) {
-  std::unique_ptr<SoftwareOutputDeviceOzone> result(
-      new SoftwareOutputDeviceOzone(widget));
-  if (!result->surface_ozone_)
-    return nullptr;
-  return result;
-}
-
 SoftwareOutputDeviceOzone::SoftwareOutputDeviceOzone(
-    gfx::AcceleratedWidget widget) {
-  ui::SurfaceFactoryOzone* factory =
-      ui::OzonePlatform::GetInstance()->GetSurfaceFactoryOzone();
-
-  surface_ozone_ = factory->CreateCanvasForWidget(widget);
-
-  if (!surface_ozone_) {
-    LOG(ERROR) << "Failed to initialize canvas";
-    return;
-  }
-
+    std::unique_ptr<ui::SurfaceOzoneCanvas> surface_ozone)
+    : surface_ozone_(std::move(surface_ozone)) {
   vsync_provider_ = surface_ozone_->CreateVSyncProvider();
 }
 
diff --git a/components/viz/service/display_embedder/software_output_device_ozone.h b/components/viz/service/display_embedder/software_output_device_ozone.h
index d4f3eb2..6565811 100644
--- a/components/viz/service/display_embedder/software_output_device_ozone.h
+++ b/components/viz/service/display_embedder/software_output_device_ozone.h
@@ -24,8 +24,8 @@
 class VIZ_SERVICE_EXPORT SoftwareOutputDeviceOzone
     : public SoftwareOutputDevice {
  public:
-  static std::unique_ptr<SoftwareOutputDeviceOzone> Create(
-      gfx::AcceleratedWidget widget);
+  explicit SoftwareOutputDeviceOzone(
+      std::unique_ptr<ui::SurfaceOzoneCanvas> surface_ozone);
   ~SoftwareOutputDeviceOzone() override;
 
   void Resize(const gfx::Size& viewport_pixel_size,
@@ -34,8 +34,6 @@
   void EndPaint() override;
 
  private:
-  explicit SoftwareOutputDeviceOzone(gfx::AcceleratedWidget widget);
-
   std::unique_ptr<ui::SurfaceOzoneCanvas> surface_ozone_;
 
   DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceOzone);
diff --git a/components/viz/service/display_embedder/software_output_device_ozone_unittest.cc b/components/viz/service/display_embedder/software_output_device_ozone_unittest.cc
index 5ce79b14a..225ae49 100644
--- a/components/viz/service/display_embedder/software_output_device_ozone_unittest.cc
+++ b/components/viz/service/display_embedder/software_output_device_ozone_unittest.cc
@@ -18,10 +18,13 @@
 #include "ui/gfx/vsync_provider.h"
 #include "ui/gl/gl_implementation.h"
 #include "ui/ozone/public/ozone_platform.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
 #include "ui/ozone/public/surface_ozone_canvas.h"
 #include "ui/platform_window/platform_window.h"
 #include "ui/platform_window/platform_window_delegate.h"
 
+namespace viz {
+
 namespace {
 
 class TestPlatformWindowDelegate : public ui::PlatformWindowDelegate {
@@ -63,7 +66,7 @@
   void TearDown() override;
 
  protected:
-  std::unique_ptr<viz::SoftwareOutputDeviceOzone> output_device_;
+  std::unique_ptr<SoftwareOutputDeviceOzone> output_device_;
   bool enable_pixel_output_ = false;
 
  private:
@@ -73,8 +76,8 @@
   DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceOzoneTest);
 };
 
-SoftwareOutputDeviceOzoneTest::SoftwareOutputDeviceOzoneTest() {}
-SoftwareOutputDeviceOzoneTest::~SoftwareOutputDeviceOzoneTest() {}
+SoftwareOutputDeviceOzoneTest::SoftwareOutputDeviceOzoneTest() = default;
+SoftwareOutputDeviceOzoneTest::~SoftwareOutputDeviceOzoneTest() = default;
 
 void SoftwareOutputDeviceOzoneTest::SetUp() {
   ui::ContextFactory* context_factory = nullptr;
@@ -83,16 +86,24 @@
                                        &context_factory_private);
 
   const gfx::Size size(500, 400);
-  compositor_.reset(
-      new ui::Compositor(viz::FrameSinkId(1, 1), context_factory, nullptr,
-                         base::ThreadTaskRunnerHandle::Get(),
-                         false /* enable_surface_synchronization */,
-                         false /* enable_pixel_canvas */));
+  compositor_ = std::make_unique<ui::Compositor>(
+      FrameSinkId(1, 1), context_factory, nullptr,
+      base::ThreadTaskRunnerHandle::Get(),
+      false /* enable_surface_synchronization */,
+      false /* enable_pixel_canvas */);
   compositor_->SetAcceleratedWidget(window_delegate_.GetAcceleratedWidget());
   compositor_->SetScaleAndSize(1.0f, size);
 
-  output_device_ =
-      viz::SoftwareOutputDeviceOzone::Create(compositor_->widget());
+  ui::SurfaceFactoryOzone* factory =
+      ui::OzonePlatform::GetInstance()->GetSurfaceFactoryOzone();
+  std::unique_ptr<ui::SurfaceOzoneCanvas> surface_ozone =
+      factory->CreateCanvasForWidget(compositor_->widget());
+  if (!surface_ozone) {
+    LOG(ERROR) << "SurfaceOzoneCanvas not constructible on this platform";
+  } else {
+    output_device_ =
+        std::make_unique<SoftwareOutputDeviceOzone>(std::move(surface_ozone));
+  }
   if (output_device_)
     output_device_->Resize(size, 1.f);
 }
@@ -138,3 +149,5 @@
                       canvas->getBaseLayerSize().height());
   EXPECT_EQ(size.ToString(), canvas_size.ToString());
 }
+
+}  // namespace viz
diff --git a/components/viz/service/display_embedder/software_output_device_x11.cc b/components/viz/service/display_embedder/software_output_device_x11.cc
index 5662d3b..aba4cae 100644
--- a/components/viz/service/display_embedder/software_output_device_x11.cc
+++ b/components/viz/service/display_embedder/software_output_device_x11.cc
@@ -19,7 +19,6 @@
 
 SoftwareOutputDeviceX11::SoftwareOutputDeviceX11(gfx::AcceleratedWidget widget)
     : widget_(widget), display_(gfx::GetXDisplay()), gc_(nullptr) {
-  // TODO(skaslev) Remove this when crbug.com/180702 is fixed.
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   gc_ = XCreateGC(display_, widget_, 0, nullptr);
diff --git a/components/viz/service/display_embedder/software_output_surface.cc b/components/viz/service/display_embedder/software_output_surface.cc
new file mode 100644
index 0000000..b142ec28
--- /dev/null
+++ b/components/viz/service/display_embedder/software_output_surface.cc
@@ -0,0 +1,131 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/viz/service/display_embedder/software_output_surface.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "components/viz/service/display/output_surface_client.h"
+#include "components/viz/service/display/output_surface_frame.h"
+#include "components/viz/service/display/software_output_device.h"
+#include "ui/gfx/presentation_feedback.h"
+#include "ui/gfx/vsync_provider.h"
+#include "ui/latency/latency_info.h"
+
+namespace viz {
+
+SoftwareOutputSurface::SoftwareOutputSurface(
+    std::unique_ptr<SoftwareOutputDevice> software_device,
+    scoped_refptr<base::SequencedTaskRunner> task_runner)
+    : OutputSurface(std::move(software_device)),
+      task_runner_(std::move(task_runner)),
+      weak_factory_(this) {}
+
+SoftwareOutputSurface::~SoftwareOutputSurface() = default;
+
+void SoftwareOutputSurface::BindToClient(OutputSurfaceClient* client) {
+  DCHECK(client);
+  DCHECK(!client_);
+  client_ = client;
+}
+
+void SoftwareOutputSurface::EnsureBackbuffer() {
+  software_device()->EnsureBackbuffer();
+}
+
+void SoftwareOutputSurface::DiscardBackbuffer() {
+  software_device()->DiscardBackbuffer();
+}
+
+void SoftwareOutputSurface::BindFramebuffer() {
+  // Not used for software surfaces.
+  NOTREACHED();
+}
+
+void SoftwareOutputSurface::SetDrawRectangle(const gfx::Rect& draw_rectangle) {
+  NOTREACHED();
+}
+
+void SoftwareOutputSurface::Reshape(const gfx::Size& size,
+                                    float device_scale_factor,
+                                    const gfx::ColorSpace& color_space,
+                                    bool has_alpha,
+                                    bool use_stencil) {
+  software_device()->Resize(size, device_scale_factor);
+}
+
+void SoftwareOutputSurface::SwapBuffers(OutputSurfaceFrame frame) {
+  DCHECK(client_);
+  base::TimeTicks swap_time = base::TimeTicks::Now();
+  for (auto& latency : frame.latency_info) {
+    latency.AddLatencyNumberWithTimestamp(
+        ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0, swap_time, 1);
+    latency.AddLatencyNumberWithTimestamp(
+        ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0,
+        swap_time, 1);
+  }
+  // TODO(danakj): Send frame.latency_info somewhere like
+  // RenderWidgetHostImpl::OnGpuSwapBuffersCompleted. It should go to the
+  // ui::LatencyTracker in the viz process.
+
+  // TODO(danakj): Update vsync params.
+  // gfx::VSyncProvider* vsync_provider = software_device()->GetVSyncProvider();
+  // if (vsync_provider)
+  //  vsync_provider->GetVSyncParameters(update_vsync_parameters_callback_);
+  // Update refresh_interval_ as well.
+
+  ++swap_id_;
+  task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&SoftwareOutputSurface::SwapBuffersCallback,
+                                weak_factory_.GetWeakPtr(), swap_id_));
+}
+
+bool SoftwareOutputSurface::IsDisplayedAsOverlayPlane() const {
+  return false;
+}
+
+OverlayCandidateValidator* SoftwareOutputSurface::GetOverlayCandidateValidator()
+    const {
+  // No overlay support in software compositing.
+  return nullptr;
+}
+
+unsigned SoftwareOutputSurface::GetOverlayTextureId() const {
+  return 0;
+}
+
+gfx::BufferFormat SoftwareOutputSurface::GetOverlayBufferFormat() const {
+  return gfx::BufferFormat::RGBX_8888;
+}
+
+bool SoftwareOutputSurface::HasExternalStencilTest() const {
+  return false;
+}
+
+void SoftwareOutputSurface::ApplyExternalStencil() {}
+
+bool SoftwareOutputSurface::SurfaceIsSuspendForRecycle() const {
+  return false;
+}
+
+uint32_t SoftwareOutputSurface::GetFramebufferCopyTextureFormat() {
+  // Not used for software surfaces.
+  NOTREACHED();
+  return 0;
+}
+
+void SoftwareOutputSurface::SwapBuffersCallback(uint64_t swap_id) {
+  client_->DidReceiveSwapBuffersAck(swap_id);
+  client_->DidReceivePresentationFeedback(
+      swap_id,
+      gfx::PresentationFeedback(base::TimeTicks::Now(), refresh_interval_, 0u));
+}
+
+}  // namespace viz
diff --git a/components/viz/service/display_embedder/software_output_surface.h b/components/viz/service/display_embedder/software_output_surface.h
new file mode 100644
index 0000000..a6660047
--- /dev/null
+++ b/components/viz/service/display_embedder/software_output_surface.h
@@ -0,0 +1,57 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SOFTWARE_OUTPUT_SURFACE_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SOFTWARE_OUTPUT_SURFACE_H_
+
+#include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "components/viz/service/display/output_surface.h"
+#include "components/viz/service/viz_service_export.h"
+
+namespace viz {
+class SoftwareOutputDevice;
+
+class VIZ_SERVICE_EXPORT SoftwareOutputSurface : public OutputSurface {
+ public:
+  SoftwareOutputSurface(std::unique_ptr<SoftwareOutputDevice> software_device,
+                        scoped_refptr<base::SequencedTaskRunner> task_runner);
+  ~SoftwareOutputSurface() override;
+
+  // OutputSurface implementation.
+  void BindToClient(OutputSurfaceClient* client) override;
+  void EnsureBackbuffer() override;
+  void DiscardBackbuffer() override;
+  void BindFramebuffer() override;
+  void SetDrawRectangle(const gfx::Rect& draw_rectangle) override;
+  void Reshape(const gfx::Size& size,
+               float device_scale_factor,
+               const gfx::ColorSpace& color_space,
+               bool has_alpha,
+               bool use_stencil) override;
+  void SwapBuffers(OutputSurfaceFrame frame) override;
+  bool IsDisplayedAsOverlayPlane() const override;
+  OverlayCandidateValidator* GetOverlayCandidateValidator() const override;
+  unsigned GetOverlayTextureId() const override;
+  gfx::BufferFormat GetOverlayBufferFormat() const override;
+  bool HasExternalStencilTest() const override;
+  void ApplyExternalStencil() override;
+  bool SurfaceIsSuspendForRecycle() const override;
+  uint32_t GetFramebufferCopyTextureFormat() override;
+
+ private:
+  void SwapBuffersCallback(uint64_t swap_id);
+
+  OutputSurfaceClient* client_ = nullptr;
+  scoped_refptr<base::SequencedTaskRunner> task_runner_;
+  base::TimeDelta refresh_interval_;
+  uint64_t swap_id_ = 0;
+  base::WeakPtrFactory<SoftwareOutputSurface> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(SoftwareOutputSurface);
+};
+
+}  // namespace viz
+
+#endif  // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SOFTWARE_OUTPUT_SURFACE_H_
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
index eb7ed9c..fd50f6c 100644
--- a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
+++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
@@ -103,6 +103,7 @@
 void FrameSinkManagerImpl::CreateRootCompositorFrameSink(
     const FrameSinkId& frame_sink_id,
     gpu::SurfaceHandle surface_handle,
+    bool force_software_compositing,
     const RendererSettings& renderer_settings,
     mojom::CompositorFrameSinkAssociatedRequest request,
     mojom::CompositorFrameSinkClientPtr client,
@@ -114,7 +115,8 @@
 
   std::unique_ptr<SyntheticBeginFrameSource> begin_frame_source;
   auto display = display_provider_->CreateDisplay(
-      frame_sink_id, surface_handle, renderer_settings, &begin_frame_source);
+      frame_sink_id, surface_handle, force_software_compositing,
+      renderer_settings, &begin_frame_source);
 
   auto frame_sink = std::make_unique<RootCompositorFrameSinkImpl>(
       this, frame_sink_id, std::move(display), std::move(begin_frame_source),
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_impl.h b/components/viz/service/frame_sinks/frame_sink_manager_impl.h
index 5b3c43c1..ecbebd8e 100644
--- a/components/viz/service/frame_sinks/frame_sink_manager_impl.h
+++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.h
@@ -71,6 +71,7 @@
   void CreateRootCompositorFrameSink(
       const FrameSinkId& frame_sink_id,
       gpu::SurfaceHandle surface_handle,
+      bool force_software_compositing,
       const RendererSettings& renderer_settings,
       mojom::CompositorFrameSinkAssociatedRequest request,
       mojom::CompositorFrameSinkClientPtr client,
diff --git a/components/viz/test/test_frame_sink_manager.h b/components/viz/test/test_frame_sink_manager.h
index 205fca4..5d0bafb9 100644
--- a/components/viz/test/test_frame_sink_manager.h
+++ b/components/viz/test/test_frame_sink_manager.h
@@ -27,6 +27,7 @@
   void CreateRootCompositorFrameSink(
       const FrameSinkId& frame_sink_id,
       gpu::SurfaceHandle surface_handle,
+      bool force_software_compositor,
       const RendererSettings& renderer_settings,
       mojom::CompositorFrameSinkAssociatedRequest request,
       mojom::CompositorFrameSinkClientPtr client,
diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc
index cddd17c..496990c 100644
--- a/content/browser/compositor/gpu_process_transport_factory.cc
+++ b/content/browser/compositor/gpu_process_transport_factory.cc
@@ -88,6 +88,8 @@
 #include "ui/ozone/public/overlay_manager_ozone.h"
 #include "ui/ozone/public/ozone_platform.h"
 #include "ui/ozone/public/ozone_switches.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
+#include "ui/ozone/public/surface_ozone_canvas.h"
 #elif defined(USE_X11)
 #include "components/viz/service/display_embedder/software_output_device_x11.h"
 #elif defined(OS_MACOSX)
@@ -254,7 +256,13 @@
   return std::make_unique<viz::SoftwareOutputDeviceWin>(software_backing_.get(),
                                                         widget);
 #elif defined(USE_OZONE)
-  return viz::SoftwareOutputDeviceOzone::Create(widget);
+  ui::SurfaceFactoryOzone* factory =
+      ui::OzonePlatform::GetInstance()->GetSurfaceFactoryOzone();
+  std::unique_ptr<ui::SurfaceOzoneCanvas> surface_ozone =
+      factory->CreateCanvasForWidget(widget);
+  CHECK(surface_ozone);
+  return std::make_unique<viz::SoftwareOutputDeviceOzone>(
+      std::move(surface_ozone));
 #elif defined(USE_X11)
   return std::make_unique<viz::SoftwareOutputDeviceX11>(widget);
 #elif defined(OS_MACOSX)
diff --git a/content/browser/compositor/viz_process_transport_factory.cc b/content/browser/compositor/viz_process_transport_factory.cc
index 7c85001..4c718787 100644
--- a/content/browser/compositor/viz_process_transport_factory.cc
+++ b/content/browser/compositor/viz_process_transport_factory.cc
@@ -10,6 +10,7 @@
 #include "base/single_thread_task_runner.h"
 #include "cc/raster/single_thread_task_graph_runner.h"
 #include "components/viz/client/client_layer_tree_frame_sink.h"
+#include "components/viz/client/client_shared_bitmap_manager.h"
 #include "components/viz/client/local_surface_id_provider.h"
 #include "components/viz/common/features.h"
 #include "components/viz/common/gpu/context_provider.h"
@@ -400,16 +401,17 @@
 #endif
 
   // Creates the viz end of the root CompositorFrameSink.
-  // TODO(crbug.com/730660): If compositor->force_software_compositor() then
-  // make a software-based RootCompositorFrameSink.
   GetHostFrameSinkManager()->CreateRootCompositorFrameSink(
-      compositor->frame_sink_id(), surface_handle, renderer_settings_,
+      compositor->frame_sink_id(), surface_handle,
+      compositor->force_software_compositor(), renderer_settings_,
       std::move(sink_request), std::move(client),
       std::move(display_private_request));
 
   // Create LayerTreeFrameSink with the browser end of CompositorFrameSink.
   viz::ClientLayerTreeFrameSink::InitParams params;
   params.gpu_memory_buffer_manager = GetGpuMemoryBufferManager();
+  // TODO(crbug.com/730660): Make a ClientSharedBitmapManager to pass here.
+  params.shared_bitmap_manager = shared_bitmap_manager_.get();
   params.pipes.compositor_frame_sink_associated_info = std::move(sink_info);
   params.pipes.client_request = std::move(client_request);
   params.local_surface_id_provider =
diff --git a/content/browser/compositor/viz_process_transport_factory.h b/content/browser/compositor/viz_process_transport_factory.h
index 8a48b55..61e4cea 100644
--- a/content/browser/compositor/viz_process_transport_factory.h
+++ b/content/browser/compositor/viz_process_transport_factory.h
@@ -36,6 +36,7 @@
 }
 
 namespace viz {
+class ClientSharedBitmapManager;
 class ForwardingCompositingModeReporterImpl;
 }
 
@@ -154,6 +155,7 @@
   // TODO(kylechar): Call OnContextLost() on observers when GPU crashes.
   base::ObserverList<ui::ContextFactoryObserver> observer_list_;
 
+  std::unique_ptr<viz::ClientSharedBitmapManager> shared_bitmap_manager_;
   scoped_refptr<ui::ContextProviderCommandBuffer>
       shared_worker_context_provider_;
   scoped_refptr<ui::ContextProviderCommandBuffer> compositor_context_provider_;
diff --git a/content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.cc b/content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.cc
index 1ec201b2b..f351ccf 100644
--- a/content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.cc
+++ b/content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.cc
@@ -282,8 +282,8 @@
   TRACE_EVENT0("gpu", "VideoCaptureGpuJpegDecoder::FinishInitialization");
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  base::AutoLock lock(lock_);
   if (unbound_remote_decoder.is_valid()) {
+    base::AutoLock lock(lock_);
     decoder_ = base::MakeUnique<media::MojoJpegDecodeAccelerator>(
         BrowserThread::GetTaskRunnerForThread(BrowserThread::IO),
         std::move(unbound_remote_decoder));
diff --git a/extensions/browser/device_local_account_util.cc b/extensions/browser/device_local_account_util.cc
index fc8d079..4ecc3674 100644
--- a/extensions/browser/device_local_account_util.cc
+++ b/extensions/browser/device_local_account_util.cc
@@ -140,6 +140,7 @@
     "aoggjnmghgmcllfenalipjhmooomfdce",  // SAML SSO for Chrome Apps
     "fhndealchbngfhdoncgcokameljahhog",  // Certificate Enrollment for Chrome OS
     "npeicpdbkakmehahjeeohfdhnlpdklia",  // WebRTC Network Limiter
+    "hdkoikmfpncabbdniojdddokkomafcci",  // SSRS Reporting Fix for Chrome
 };
 
 }  // namespace
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_controller.h b/ios/chrome/browser/ui/fullscreen/fullscreen_controller.h
index 4b4f6e24..f899dc9 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_controller.h
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_controller.h
@@ -9,6 +9,7 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "base/supports_user_data.h"
 
 @class ChromeBroadcaster;
 @class ChromeBroadcastOberverBridge;
@@ -20,10 +21,21 @@
 // calculates how much of the toolbar should be visible as a result.  When the
 // user scrolls down the screen, the toolbar should be hidden to allow more of
 // the page's content to be visible.
-class FullscreenController {
+class FullscreenController : public base::SupportsUserData::Data {
  public:
-  explicit FullscreenController(ChromeBroadcaster* broadcaster);
-  ~FullscreenController();
+  ~FullscreenController() override;
+
+  // Creation and getter functions for FullscreenController.
+  // TODO(crbug.com/790886): Convert FullscreenController to a BrowserUserData.
+  static void CreateForUserData(base::SupportsUserData* user_data);
+  static FullscreenController* FromUserData(base::SupportsUserData* user_data);
+
+  // The ChromeBroadcaster through the FullscreenController receives UI
+  // information necessary to calculate fullscreen progress.
+  // TODO(crbug.com/790886): Once FullscreenController is a BrowserUserData,
+  // remove this ad-hoc broadcaster and drive the animations via the Browser's
+  // ChromeBroadcaster.
+  ChromeBroadcaster* broadcaster() { return broadcaster_; }
 
   // Adds and removes FullscreenControllerObservers.
   void AddObserver(FullscreenControllerObserver* observer);
@@ -42,6 +54,9 @@
   void DecrementDisabledCounter();
 
  private:
+  // Private contructor used by CreateForUserData().
+  explicit FullscreenController();
+
   // The broadcaster that drives the model.
   __strong ChromeBroadcaster* broadcaster_ = nil;
   // The model used to calculate fullscreen state.
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_controller.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_controller.mm
index c496895..869cd86d 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_controller.mm
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_controller.mm
@@ -14,8 +14,31 @@
 #error "This file requires ARC support."
 #endif
 
-FullscreenController::FullscreenController(ChromeBroadcaster* broadcaster)
-    : broadcaster_(broadcaster),
+namespace {
+// The key under which FullscreenControllers are associated with their user
+// data.
+const void* const kFullscreenControllerKey = &kFullscreenControllerKey;
+}  // namespace
+
+// static
+void FullscreenController::CreateForUserData(
+    base::SupportsUserData* user_data) {
+  DCHECK(user_data);
+  if (!FullscreenController::FromUserData(user_data)) {
+    user_data->SetUserData(kFullscreenControllerKey,
+                           base::WrapUnique(new FullscreenController()));
+  }
+}
+
+// static
+FullscreenController* FullscreenController::FromUserData(
+    base::SupportsUserData* user_data) {
+  return static_cast<FullscreenController*>(
+      user_data->GetUserData(kFullscreenControllerKey));
+}
+
+FullscreenController::FullscreenController()
+    : broadcaster_([[ChromeBroadcaster alloc] init]),
       model_(base::MakeUnique<FullscreenModel>()),
       bridge_([[ChromeBroadcastOberverBridge alloc]
           initWithObserver:model_.get()]) {
diff --git a/media/capture/video/android/video_capture_device_android.cc b/media/capture/video/android/video_capture_device_android.cc
index b98c0bb..785fc1b 100644
--- a/media/capture/video/android/video_capture_device_android.cc
+++ b/media/capture/video/android/video_capture_device_android.cc
@@ -146,7 +146,7 @@
   capture_format_.frame_rate =
       Java_VideoCapture_queryFrameRate(env, j_capture_);
   capture_format_.pixel_format = GetColorspace();
-  DCHECK_NE(capture_format_.pixel_format, media::PIXEL_FORMAT_UNKNOWN);
+  DCHECK_NE(capture_format_.pixel_format, PIXEL_FORMAT_UNKNOWN);
   CHECK(capture_format_.frame_size.GetArea() > 0);
   CHECK(!(capture_format_.frame_size.width() % 2));
   CHECK(!(capture_format_.frame_size.height() % 2));
@@ -429,14 +429,14 @@
       Java_VideoCapture_getColorspace(env, j_capture_);
   switch (current_capture_colorspace) {
     case ANDROID_IMAGE_FORMAT_YV12:
-      return media::PIXEL_FORMAT_YV12;
+      return PIXEL_FORMAT_YV12;
     case ANDROID_IMAGE_FORMAT_YUV_420_888:
-      return media::PIXEL_FORMAT_I420;
+      return PIXEL_FORMAT_I420;
     case ANDROID_IMAGE_FORMAT_NV21:
-      return media::PIXEL_FORMAT_NV21;
+      return PIXEL_FORMAT_NV21;
     case ANDROID_IMAGE_FORMAT_UNKNOWN:
     default:
-      return media::PIXEL_FORMAT_UNKNOWN;
+      return PIXEL_FORMAT_UNKNOWN;
   }
 }
 
diff --git a/media/capture/video/android/video_capture_device_factory_android.cc b/media/capture/video/android/video_capture_device_factory_android.cc
index 064d69d08..d9ee746 100644
--- a/media/capture/video/android/video_capture_device_factory_android.cc
+++ b/media/capture/video/android/video_capture_device_factory_android.cc
@@ -104,14 +104,13 @@
     base::android::ScopedJavaLocalRef<jobject> format(
         env, env->GetObjectArrayElement(collected_formats.obj(), i));
 
-    VideoPixelFormat pixel_format = media::PIXEL_FORMAT_UNKNOWN;
-    switch (media::Java_VideoCaptureFactory_getCaptureFormatPixelFormat(
-        env, format)) {
+    VideoPixelFormat pixel_format = PIXEL_FORMAT_UNKNOWN;
+    switch (Java_VideoCaptureFactory_getCaptureFormatPixelFormat(env, format)) {
       case VideoCaptureDeviceAndroid::ANDROID_IMAGE_FORMAT_YV12:
-        pixel_format = media::PIXEL_FORMAT_YV12;
+        pixel_format = PIXEL_FORMAT_YV12;
         break;
       case VideoCaptureDeviceAndroid::ANDROID_IMAGE_FORMAT_NV21:
-        pixel_format = media::PIXEL_FORMAT_NV21;
+        pixel_format = PIXEL_FORMAT_NV21;
         break;
       default:
         // TODO(mcasas): break here and let the enumeration continue with
@@ -120,11 +119,9 @@
         continue;
     }
     VideoCaptureFormat capture_format(
-        gfx::Size(
-            media::Java_VideoCaptureFactory_getCaptureFormatWidth(env, format),
-            media::Java_VideoCaptureFactory_getCaptureFormatHeight(env,
-                                                                   format)),
-        media::Java_VideoCaptureFactory_getCaptureFormatFramerate(env, format),
+        gfx::Size(Java_VideoCaptureFactory_getCaptureFormatWidth(env, format),
+                  Java_VideoCaptureFactory_getCaptureFormatHeight(env, format)),
+        Java_VideoCaptureFactory_getCaptureFormatFramerate(env, format),
         pixel_format);
     capture_formats->push_back(capture_format);
     DVLOG(1) << device.display_name << " "
diff --git a/media/capture/video/chromeos/mock_video_capture_client.cc b/media/capture/video/chromeos/mock_video_capture_client.cc
index b9be6f7..7c22b95f 100644
--- a/media/capture/video/chromeos/mock_video_capture_client.cc
+++ b/media/capture/video/chromeos/mock_video_capture_client.cc
@@ -55,8 +55,8 @@
 // Trampoline methods to workaround GMOCK problems with std::unique_ptr<>.
 VideoCaptureDevice::Client::Buffer MockVideoCaptureClient::ReserveOutputBuffer(
     const gfx::Size& dimensions,
-    media::VideoPixelFormat format,
-    media::VideoPixelStorage storage,
+    VideoPixelFormat format,
+    VideoPixelStorage storage,
     int frame_feedback_id) {
   DoReserveOutputBuffer();
   NOTREACHED() << "This should never be called";
@@ -82,11 +82,10 @@
 }
 
 VideoCaptureDevice::Client::Buffer
-MockVideoCaptureClient::ResurrectLastOutputBuffer(
-    const gfx::Size& dimensions,
-    media::VideoPixelFormat format,
-    media::VideoPixelStorage storage,
-    int frame_feedback_id) {
+MockVideoCaptureClient::ResurrectLastOutputBuffer(const gfx::Size& dimensions,
+                                                  VideoPixelFormat format,
+                                                  VideoPixelStorage storage,
+                                                  int frame_feedback_id) {
   DoResurrectLastOutputBuffer();
   NOTREACHED() << "This should never be called";
   return Buffer();
diff --git a/media/capture/video/chromeos/mock_video_capture_client.h b/media/capture/video/chromeos/mock_video_capture_client.h
index e9be4a7..897be99 100644
--- a/media/capture/video/chromeos/mock_video_capture_client.h
+++ b/media/capture/video/chromeos/mock_video_capture_client.h
@@ -42,8 +42,8 @@
                               int frame_feedback_id) override;
   // Trampoline methods to workaround GMOCK problems with std::unique_ptr<>.
   Buffer ReserveOutputBuffer(const gfx::Size& dimensions,
-                             media::VideoPixelFormat format,
-                             media::VideoPixelStorage storage,
+                             VideoPixelFormat format,
+                             VideoPixelStorage storage,
                              int frame_feedback_id) override;
   void OnIncomingCapturedBuffer(Buffer buffer,
                                 const VideoCaptureFormat& format,
@@ -57,8 +57,8 @@
       gfx::Rect visible_rect,
       const VideoFrameMetadata& additional_metadata) override;
   Buffer ResurrectLastOutputBuffer(const gfx::Size& dimensions,
-                                   media::VideoPixelFormat format,
-                                   media::VideoPixelStorage storage,
+                                   VideoPixelFormat format,
+                                   VideoPixelStorage storage,
                                    int frame_feedback_id) override;
 
  private:
diff --git a/media/capture/video/fake_video_capture_device.cc b/media/capture/video/fake_video_capture_device.cc
index 6662752..8f6532e 100644
--- a/media/capture/video/fake_video_capture_device.cc
+++ b/media/capture/video/fake_video_capture_device.cc
@@ -49,10 +49,10 @@
 };
 
 PixelFormatMatchType DetermineFormatMatchType(
-    media::VideoPixelFormat supported_format,
-    media::VideoPixelFormat requested_format) {
-  if (requested_format == media::PIXEL_FORMAT_I420 &&
-      supported_format == media::PIXEL_FORMAT_MJPEG) {
+    VideoPixelFormat supported_format,
+    VideoPixelFormat requested_format) {
+  if (requested_format == PIXEL_FORMAT_I420 &&
+      supported_format == PIXEL_FORMAT_MJPEG) {
     return PixelFormatMatchType::SUPPORTED_THROUGH_CONVERSION;
   }
   return (requested_format == supported_format)
@@ -60,7 +60,7 @@
              : PixelFormatMatchType::INCOMPATIBLE;
 }
 
-const media::VideoCaptureFormat& FindClosestSupportedFormat(
+const VideoCaptureFormat& FindClosestSupportedFormat(
     const VideoCaptureFormat& requested_format,
     const VideoCaptureFormats& supported_formats) {
   DCHECK(!supported_formats.empty());
diff --git a/media/capture/video/fake_video_capture_device_unittest.cc b/media/capture/video/fake_video_capture_device_unittest.cc
index 3abc9a1..ec081a23 100644
--- a/media/capture/video/fake_video_capture_device_unittest.cc
+++ b/media/capture/video/fake_video_capture_device_unittest.cc
@@ -121,10 +121,10 @@
   }
   // Virtual methods for capturing using Client's Buffers.
   Buffer ReserveOutputBuffer(const gfx::Size& dimensions,
-                             media::VideoPixelFormat format,
-                             media::VideoPixelStorage storage,
+                             VideoPixelFormat format,
+                             VideoPixelStorage storage,
                              int frame_feedback_id) override {
-    EXPECT_EQ(media::PIXEL_STORAGE_CPU, storage);
+    EXPECT_EQ(PIXEL_STORAGE_CPU, storage);
     EXPECT_GT(dimensions.GetArea(), 0);
     const VideoCaptureFormat frame_format(dimensions, 0.0, format);
     return CreateStubBuffer(0, frame_format.ImageAllocationSize());
@@ -145,8 +145,8 @@
     frame_cb_.Run(format);
   }
   Buffer ResurrectLastOutputBuffer(const gfx::Size& dimensions,
-                                   media::VideoPixelFormat format,
-                                   media::VideoPixelStorage storage,
+                                   VideoPixelFormat format,
+                                   VideoPixelStorage storage,
                                    int frame_feedback_id) override {
     return Buffer();
   }
@@ -241,7 +241,7 @@
 TEST_P(FakeVideoCaptureDeviceTest, CaptureUsing) {
   if (testing::get<1>(GetParam()) ==
           FakeVideoCaptureDevice::DeliveryMode::USE_CLIENT_PROVIDED_BUFFERS &&
-      testing::get<0>(GetParam()) == media::PIXEL_FORMAT_MJPEG) {
+      testing::get<0>(GetParam()) == PIXEL_FORMAT_MJPEG) {
     // Unsupported case
     return;
   }
@@ -512,7 +512,7 @@
   video_capture_device_factory_->SetToCustomDevicesConfig(config);
   video_capture_device_factory_->GetDeviceDescriptors(descriptors_.get());
   EXPECT_EQ(1u, descriptors_->size());
-  media::VideoCaptureFormats supported_formats;
+  VideoCaptureFormats supported_formats;
   video_capture_device_factory_->GetSupportedFormats(descriptors_->at(0),
                                                      &supported_formats);
   EXPECT_EQ(0u, supported_formats.size());
@@ -539,7 +539,7 @@
 
   int device_index = 0;
   for (const auto& descriptors_iterator : *descriptors_) {
-    media::VideoCaptureFormats supported_formats;
+    VideoCaptureFormats supported_formats;
     video_capture_device_factory_->GetSupportedFormats(descriptors_iterator,
                                                        &supported_formats);
     for (const auto& supported_formats_entry : supported_formats) {
diff --git a/media/capture/video/file_video_capture_device.cc b/media/capture/video/file_video_capture_device.cc
index cacd868..57f4b58 100644
--- a/media/capture/video/file_video_capture_device.cc
+++ b/media/capture/video/file_video_capture_device.cc
@@ -54,9 +54,9 @@
 // format, in this case it means I420.
 // This code was inspired by third_party/libvpx/.../y4minput.* .
 void ParseY4MTags(const std::string& file_header,
-                  media::VideoCaptureFormat* video_format) {
-  media::VideoCaptureFormat format;
-  format.pixel_format = media::PIXEL_FORMAT_I420;
+                  VideoCaptureFormat* video_format) {
+  VideoCaptureFormat format;
+  format.pixel_format = PIXEL_FORMAT_I420;
   size_t index = 0;
   size_t blank_position = 0;
   base::StringPiece token;
@@ -114,7 +114,7 @@
   virtual ~VideoFileParser();
 
   // Parses file header and collects format information in |capture_format|.
-  virtual bool Initialize(media::VideoCaptureFormat* capture_format) = 0;
+  virtual bool Initialize(VideoCaptureFormat* capture_format) = 0;
 
   // Gets the start pointer of next frame and stores current frame size in
   // |frame_size|.
@@ -133,7 +133,7 @@
 
   // VideoFileParser implementation, class methods.
   ~Y4mFileParser() override;
-  bool Initialize(media::VideoCaptureFormat* capture_format) override;
+  bool Initialize(VideoCaptureFormat* capture_format) override;
   const uint8_t* GetNextFrame(int* frame_size) override;
 
  private:
@@ -149,7 +149,7 @@
 
   // VideoFileParser implementation, class methods.
   ~MjpegFileParser() override;
-  bool Initialize(media::VideoCaptureFormat* capture_format) override;
+  bool Initialize(VideoCaptureFormat* capture_format) override;
   const uint8_t* GetNextFrame(int* frame_size) override;
 
  private:
@@ -171,7 +171,7 @@
 
 Y4mFileParser::~Y4mFileParser() = default;
 
-bool Y4mFileParser::Initialize(media::VideoCaptureFormat* capture_format) {
+bool Y4mFileParser::Initialize(VideoCaptureFormat* capture_format) {
   file_.reset(new base::File(file_path_,
                              base::File::FLAG_OPEN | base::File::FLAG_READ));
   if (!file_->IsValid()) {
@@ -220,7 +220,7 @@
 
 MjpegFileParser::~MjpegFileParser() = default;
 
-bool MjpegFileParser::Initialize(media::VideoCaptureFormat* capture_format) {
+bool MjpegFileParser::Initialize(VideoCaptureFormat* capture_format) {
   mapped_file_.reset(new base::MemoryMappedFile());
 
   if (!mapped_file_->Initialize(file_path_) || !mapped_file_->IsValid()) {
@@ -239,7 +239,7 @@
   }
 
   VideoCaptureFormat format;
-  format.pixel_format = media::PIXEL_FORMAT_MJPEG;
+  format.pixel_format = PIXEL_FORMAT_MJPEG;
   format.frame_size.set_width(result.frame_header.visible_width);
   format.frame_size.set_height(result.frame_header.visible_height);
   format.frame_rate = kMJpegFrameRate;
@@ -268,7 +268,7 @@
 // static
 bool FileVideoCaptureDevice::GetVideoCaptureFormat(
     const base::FilePath& file_path,
-    media::VideoCaptureFormat* video_format) {
+    VideoCaptureFormat* video_format) {
   std::unique_ptr<VideoFileParser> file_parser =
       GetVideoFileParser(file_path, video_format);
   return file_parser != nullptr;
@@ -277,7 +277,7 @@
 // static
 std::unique_ptr<VideoFileParser> FileVideoCaptureDevice::GetVideoFileParser(
     const base::FilePath& file_path,
-    media::VideoCaptureFormat* video_format) {
+    VideoCaptureFormat* video_format) {
   std::unique_ptr<VideoFileParser> file_parser;
   std::string file_name(file_path.value().begin(), file_path.value().end());
 
diff --git a/media/capture/video/file_video_capture_device.h b/media/capture/video/file_video_capture_device.h
index 53d2670..161efd59 100644
--- a/media/capture/video/file_video_capture_device.h
+++ b/media/capture/video/file_video_capture_device.h
@@ -39,7 +39,7 @@
   // or false.
   // Restrictions: Only trivial Y4M per-frame headers and MJPEG are supported.
   static bool GetVideoCaptureFormat(const base::FilePath& file_path,
-                                    media::VideoCaptureFormat* video_format);
+                                    VideoCaptureFormat* video_format);
 
   // Constructor of the class, with a fully qualified file path as input, which
   // represents the Y4M or MJPEG file to stream repeatedly.
@@ -58,7 +58,7 @@
   // caller, who is responsible for closing it.
   static std::unique_ptr<VideoFileParser> GetVideoFileParser(
       const base::FilePath& file_path,
-      media::VideoCaptureFormat* video_format);
+      VideoCaptureFormat* video_format);
 
   // Called on the |capture_thread_|.
   void OnAllocateAndStart(const VideoCaptureParams& params,
diff --git a/media/capture/video/linux/v4l2_capture_delegate.cc b/media/capture/video/linux/v4l2_capture_delegate.cc
index 7cb3b857..ce969d7 100644
--- a/media/capture/video/linux/v4l2_capture_delegate.cc
+++ b/media/capture/video/linux/v4l2_capture_delegate.cc
@@ -447,11 +447,10 @@
     // Now check if the device is able to accept a capture framerate set.
     if (streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) {
       // |frame_rate| is float, approximate by a fraction.
-      streamparm.parm.capture.timeperframe.numerator =
-          media::kFrameRatePrecision;
+      streamparm.parm.capture.timeperframe.numerator = kFrameRatePrecision;
       streamparm.parm.capture.timeperframe.denominator =
-          (frame_rate) ? (frame_rate * media::kFrameRatePrecision)
-                       : (kTypicalFramerate * media::kFrameRatePrecision);
+          (frame_rate) ? (frame_rate * kFrameRatePrecision)
+                       : (kTypicalFramerate * kFrameRatePrecision);
 
       if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_PARM, &streamparm)) <
           0) {
diff --git a/media/capture/video/linux/v4l2_capture_delegate_unittest.cc b/media/capture/video/linux/v4l2_capture_delegate_unittest.cc
index 04f7b9f..71a1edff 100644
--- a/media/capture/video/linux/v4l2_capture_delegate_unittest.cc
+++ b/media/capture/video/linux/v4l2_capture_delegate_unittest.cc
@@ -182,11 +182,9 @@
                     base::TimeTicks,
                     base::TimeDelta,
                     int));
-  MOCK_METHOD4(ReserveOutputBuffer,
-               Buffer(const gfx::Size&,
-                      media::VideoPixelFormat,
-                      media::VideoPixelStorage,
-                      int));
+  MOCK_METHOD4(
+      ReserveOutputBuffer,
+      Buffer(const gfx::Size&, VideoPixelFormat, VideoPixelStorage, int));
   void OnIncomingCapturedBuffer(Buffer buffer,
                                 const VideoCaptureFormat& frame_format,
                                 base::TimeTicks reference_time,
diff --git a/media/capture/video/linux/video_capture_device_linux.cc b/media/capture/video/linux/video_capture_device_linux.cc
index e247368..2883ccee 100644
--- a/media/capture/video/linux/video_capture_device_linux.cc
+++ b/media/capture/video/linux/video_capture_device_linux.cc
@@ -139,9 +139,9 @@
 int VideoCaptureDeviceLinux::TranslatePowerLineFrequencyToV4L2(
     PowerLineFrequency frequency) {
   switch (frequency) {
-    case media::PowerLineFrequency::FREQUENCY_50HZ:
+    case PowerLineFrequency::FREQUENCY_50HZ:
       return V4L2_CID_POWER_LINE_FREQUENCY_50HZ;
-    case media::PowerLineFrequency::FREQUENCY_60HZ:
+    case PowerLineFrequency::FREQUENCY_60HZ:
       return V4L2_CID_POWER_LINE_FREQUENCY_60HZ;
     default:
       // If we have no idea of the frequency, at least try and set it to AUTO.
diff --git a/media/capture/video/mac/video_capture_device_decklink_mac.mm b/media/capture/video/mac/video_capture_device_decklink_mac.mm
index 6d7e8457..10d598c 100644
--- a/media/capture/video/mac/video_capture_device_decklink_mac.mm
+++ b/media/capture/video/mac/video_capture_device_decklink_mac.mm
@@ -446,8 +446,7 @@
       // is only available on capture.
       const media::VideoCaptureFormat format(
           gfx::Size(display_mode->GetWidth(), display_mode->GetHeight()),
-          GetDisplayModeFrameRate(display_mode),
-          PIXEL_FORMAT_UNKNOWN);
+          GetDisplayModeFrameRate(display_mode), PIXEL_FORMAT_UNKNOWN);
       supported_formats->push_back(format);
       DVLOG(2) << device.display_name << " "
                << VideoCaptureFormat::ToString(format);
diff --git a/media/capture/video/mock_video_frame_receiver.h b/media/capture/video/mock_video_frame_receiver.h
index 35c5fc4..241566cf0e 100644
--- a/media/capture/video/mock_video_frame_receiver.h
+++ b/media/capture/video/mock_video_frame_receiver.h
@@ -19,8 +19,9 @@
   MOCK_METHOD3(
       MockOnFrameReadyInBuffer,
       void(int buffer_id,
-           std::unique_ptr<media::VideoCaptureDevice::Client::Buffer::
-                               ScopedAccessPermission>* buffer_read_permission,
+           std::unique_ptr<
+               VideoCaptureDevice::Client::Buffer::ScopedAccessPermission>*
+               buffer_read_permission,
            const gfx::Size&));
   MOCK_METHOD0(OnError, void());
   MOCK_METHOD1(OnLog, void(const std::string& message));
@@ -30,7 +31,7 @@
 
   void OnNewBufferHandle(
       int buffer_id,
-      std::unique_ptr<media::VideoCaptureDevice::Client::Buffer::HandleProvider>
+      std::unique_ptr<VideoCaptureDevice::Client::Buffer::HandleProvider>
           handle_provider) override {
     MockOnNewBufferHandle(buffer_id);
   }
@@ -39,7 +40,7 @@
       int32_t buffer_id,
       int frame_feedback_id,
       std::unique_ptr<
-          media::VideoCaptureDevice::Client::Buffer::ScopedAccessPermission>
+          VideoCaptureDevice::Client::Buffer::ScopedAccessPermission>
           buffer_read_permission,
       media::mojom::VideoFrameInfoPtr frame_info) override {
     MockOnFrameReadyInBuffer(buffer_id, &buffer_read_permission,
diff --git a/media/capture/video/shared_memory_handle_provider.h b/media/capture/video/shared_memory_handle_provider.h
index d844a98..8a14f3a 100644
--- a/media/capture/video/shared_memory_handle_provider.h
+++ b/media/capture/video/shared_memory_handle_provider.h
@@ -19,7 +19,7 @@
 
 // Provides handles from a single, owned base::SharedMemory instance.
 class CAPTURE_EXPORT SharedMemoryHandleProvider
-    : public media::VideoCaptureDevice::Client::Buffer::HandleProvider {
+    : public VideoCaptureDevice::Client::Buffer::HandleProvider {
  public:
   // Note: One of the two InitXYZ() methods must be called before using any of
   // the HandleProvider methods.
@@ -39,7 +39,7 @@
   mojo::ScopedSharedBufferHandle GetHandleForInterProcessTransit(
       bool read_only) override;
   base::SharedMemoryHandle GetNonOwnedSharedMemoryHandleForLegacyIPC() override;
-  std::unique_ptr<media::VideoCaptureBufferHandle> GetHandleForInProcessAccess()
+  std::unique_ptr<VideoCaptureBufferHandle> GetHandleForInProcessAccess()
       override;
 
  private:
diff --git a/media/capture/video/video_capture_buffer_pool.h b/media/capture/video/video_capture_buffer_pool.h
index 050f487..5fb47c5 100644
--- a/media/capture/video/video_capture_buffer_pool.h
+++ b/media/capture/video/video_capture_buffer_pool.h
@@ -68,8 +68,8 @@
   // new allocation at a larger size. If so, the ID of the destroyed buffer is
   // returned via |buffer_id_to_drop|.
   virtual int ReserveForProducer(const gfx::Size& dimensions,
-                                 media::VideoPixelFormat format,
-                                 media::VideoPixelStorage storage,
+                                 VideoPixelFormat format,
+                                 VideoPixelStorage storage,
                                  int frame_feedback_id,
                                  int* buffer_id_to_drop) = 0;
 
@@ -87,8 +87,8 @@
   // A producer may assume the content of the buffer has been preserved and may
   // also make modifications.
   virtual int ResurrectLastForProducer(const gfx::Size& dimensions,
-                                       media::VideoPixelFormat format,
-                                       media::VideoPixelStorage storage) = 0;
+                                       VideoPixelFormat format,
+                                       VideoPixelStorage storage) = 0;
 
   // Returns a snapshot of the current number of buffers in-use divided by the
   // maximum |count_|.
diff --git a/media/capture/video/video_capture_buffer_pool_impl.cc b/media/capture/video/video_capture_buffer_pool_impl.cc
index e983383..4c6d696 100644
--- a/media/capture/video/video_capture_buffer_pool_impl.cc
+++ b/media/capture/video/video_capture_buffer_pool_impl.cc
@@ -66,12 +66,11 @@
   return tracker->GetMemoryMappedAccess();
 }
 
-int VideoCaptureBufferPoolImpl::ReserveForProducer(
-    const gfx::Size& dimensions,
-    media::VideoPixelFormat format,
-    media::VideoPixelStorage storage,
-    int frame_feedback_id,
-    int* buffer_id_to_drop) {
+int VideoCaptureBufferPoolImpl::ReserveForProducer(const gfx::Size& dimensions,
+                                                   VideoPixelFormat format,
+                                                   VideoPixelStorage storage,
+                                                   int frame_feedback_id,
+                                                   int* buffer_id_to_drop) {
   base::AutoLock lock(lock_);
   return ReserveForProducerInternal(dimensions, format, storage,
                                     frame_feedback_id, buffer_id_to_drop);
@@ -103,7 +102,7 @@
   tracker->set_consumer_hold_count(num_clients);
   // Note: |held_by_producer()| will stay true until
   // RelinquishProducerReservation() (usually called by destructor of the object
-  // wrapping this tracker, e.g. a media::VideoFrame).
+  // wrapping this tracker, e.g. a VideoFrame).
 }
 
 void VideoCaptureBufferPoolImpl::RelinquishConsumerHold(int buffer_id,
@@ -122,8 +121,8 @@
 
 int VideoCaptureBufferPoolImpl::ResurrectLastForProducer(
     const gfx::Size& dimensions,
-    media::VideoPixelFormat format,
-    media::VideoPixelStorage storage) {
+    VideoPixelFormat format,
+    VideoPixelStorage storage) {
   base::AutoLock lock(lock_);
 
   // Return early if the last relinquished buffer has been re-used already.
@@ -163,8 +162,8 @@
 
 int VideoCaptureBufferPoolImpl::ReserveForProducerInternal(
     const gfx::Size& dimensions,
-    media::VideoPixelFormat pixel_format,
-    media::VideoPixelStorage storage_type,
+    VideoPixelFormat pixel_format,
+    VideoPixelStorage storage_type,
     int frame_feedback_id,
     int* buffer_id_to_drop) {
   lock_.AssertAcquired();
diff --git a/media/capture/video/video_capture_buffer_pool_impl.h b/media/capture/video/video_capture_buffer_pool_impl.h
index 72b0c43..5a0fafd 100644
--- a/media/capture/video/video_capture_buffer_pool_impl.h
+++ b/media/capture/video/video_capture_buffer_pool_impl.h
@@ -43,14 +43,14 @@
   std::unique_ptr<VideoCaptureBufferHandle> GetHandleForInProcessAccess(
       int buffer_id) override;
   int ReserveForProducer(const gfx::Size& dimensions,
-                         media::VideoPixelFormat format,
-                         media::VideoPixelStorage storage,
+                         VideoPixelFormat format,
+                         VideoPixelStorage storage,
                          int frame_feedback_id,
                          int* buffer_id_to_drop) override;
   void RelinquishProducerReservation(int buffer_id) override;
   int ResurrectLastForProducer(const gfx::Size& dimensions,
-                               media::VideoPixelFormat format,
-                               media::VideoPixelStorage storage) override;
+                               VideoPixelFormat format,
+                               VideoPixelStorage storage) override;
   double GetBufferPoolUtilization() const override;
   void HoldForConsumers(int buffer_id, int num_clients) override;
   void RelinquishConsumerHold(int buffer_id, int num_clients) override;
@@ -60,8 +60,8 @@
   ~VideoCaptureBufferPoolImpl() override;
 
   int ReserveForProducerInternal(const gfx::Size& dimensions,
-                                 media::VideoPixelFormat format,
-                                 media::VideoPixelStorage storage,
+                                 VideoPixelFormat format,
+                                 VideoPixelStorage storage,
                                  int frame_feedback_id,
                                  int* tracker_id_to_drop);
 
diff --git a/media/capture/video/video_capture_buffer_tracker.h b/media/capture/video/video_capture_buffer_tracker.h
index b0e4e34..e7f03da 100644
--- a/media/capture/video/video_capture_buffer_tracker.h
+++ b/media/capture/video/video_capture_buffer_tracker.h
@@ -26,20 +26,18 @@
         consumer_hold_count_(0),
         frame_feedback_id_(0) {}
   virtual bool Init(const gfx::Size& dimensions,
-                    media::VideoPixelFormat format,
-                    media::VideoPixelStorage storage_type) = 0;
+                    VideoPixelFormat format,
+                    VideoPixelStorage storage_type) = 0;
   virtual ~VideoCaptureBufferTracker(){};
 
   const gfx::Size& dimensions() const { return dimensions_; }
   void set_dimensions(const gfx::Size& dim) { dimensions_ = dim; }
   size_t max_pixel_count() const { return max_pixel_count_; }
   void set_max_pixel_count(size_t count) { max_pixel_count_ = count; }
-  media::VideoPixelFormat pixel_format() const { return pixel_format_; }
-  void set_pixel_format(media::VideoPixelFormat format) {
-    pixel_format_ = format;
-  }
-  media::VideoPixelStorage storage_type() const { return storage_type_; }
-  void set_storage_type(media::VideoPixelStorage storage_type) {
+  VideoPixelFormat pixel_format() const { return pixel_format_; }
+  void set_pixel_format(VideoPixelFormat format) { pixel_format_ = format; }
+  VideoPixelStorage storage_type() const { return storage_type_; }
+  void set_storage_type(VideoPixelStorage storage_type) {
     storage_type_ = storage_type;
   }
   bool held_by_producer() const { return held_by_producer_; }
@@ -61,8 +59,8 @@
   // the lifetime of a VideoCaptureBufferTracker.
   gfx::Size dimensions_;
   size_t max_pixel_count_;
-  media::VideoPixelFormat pixel_format_;
-  media::VideoPixelStorage storage_type_;
+  VideoPixelFormat pixel_format_;
+  VideoPixelStorage storage_type_;
 
   // Indicates whether this VideoCaptureBufferTracker is currently referenced by
   // the producer.
diff --git a/media/capture/video/video_capture_device.cc b/media/capture/video/video_capture_device.cc
index f39cdba..86dc8a74 100644
--- a/media/capture/video/video_capture_device.cc
+++ b/media/capture/video/video_capture_device.cc
@@ -58,16 +58,16 @@
       countries_using_60Hz + arraysize(countries_using_60Hz);
   if (std::find(countries_using_60Hz, countries_using_60Hz_end,
                 current_country) == countries_using_60Hz_end) {
-    return media::PowerLineFrequency::FREQUENCY_50HZ;
+    return PowerLineFrequency::FREQUENCY_50HZ;
   }
-  return media::PowerLineFrequency::FREQUENCY_60HZ;
+  return PowerLineFrequency::FREQUENCY_60HZ;
 }
 
 PowerLineFrequency VideoCaptureDevice::GetPowerLineFrequency(
     const VideoCaptureParams& params) const {
   switch (params.power_line_frequency) {
-    case media::PowerLineFrequency::FREQUENCY_50HZ:  // fall through
-    case media::PowerLineFrequency::FREQUENCY_60HZ:
+    case PowerLineFrequency::FREQUENCY_50HZ:  // fall through
+    case PowerLineFrequency::FREQUENCY_60HZ:
       return params.power_line_frequency;
     default:
       return GetPowerLineFrequencyForLocation();
diff --git a/media/capture/video/video_capture_device_client.cc b/media/capture/video/video_capture_device_client.cc
index 311605a5..b4dbff5c 100644
--- a/media/capture/video/video_capture_device_client.cc
+++ b/media/capture/video/video_capture_device_client.cc
@@ -24,10 +24,6 @@
 #include "media/capture/video_capture_types.h"
 #include "third_party/libyuv/include/libyuv.h"
 
-using media::VideoCaptureFormat;
-using media::VideoFrame;
-using media::VideoFrameMetadata;
-
 namespace {
 
 bool IsFormatSupported(media::VideoPixelFormat pixel_format) {
@@ -73,7 +69,7 @@
       jpeg_decoder_factory_callback_(jpeg_decoder_factory),
       external_jpeg_decoder_initialized_(false),
       buffer_pool_(std::move(buffer_pool)),
-      last_captured_pixel_format_(media::PIXEL_FORMAT_UNKNOWN) {
+      last_captured_pixel_format_(PIXEL_FORMAT_UNKNOWN) {
   on_started_using_gpu_cb_ =
       base::Bind(&VideoFrameReceiver::OnStartedUsingGpuDecode,
                  base::Unretained(receiver_.get()));
@@ -109,14 +105,13 @@
     base::TimeDelta timestamp,
     int frame_feedback_id) {
   TRACE_EVENT0("video", "VideoCaptureDeviceClient::OnIncomingCapturedData");
-  DCHECK_EQ(media::PIXEL_STORAGE_CPU, format.pixel_storage);
+  DCHECK_EQ(PIXEL_STORAGE_CPU, format.pixel_storage);
 
   if (last_captured_pixel_format_ != format.pixel_format) {
-    OnLog("Pixel format: " +
-          media::VideoPixelFormatToString(format.pixel_format));
+    OnLog("Pixel format: " + VideoPixelFormatToString(format.pixel_format));
     last_captured_pixel_format_ = format.pixel_format;
 
-    if (format.pixel_format == media::PIXEL_FORMAT_MJPEG &&
+    if (format.pixel_format == PIXEL_FORMAT_MJPEG &&
         !external_jpeg_decoder_initialized_) {
       external_jpeg_decoder_initialized_ = true;
       external_jpeg_decoder_ = jpeg_decoder_factory_callback_.Run();
@@ -128,7 +123,7 @@
   if (!format.IsValid())
     return;
 
-  if (format.pixel_format == media::PIXEL_FORMAT_Y16) {
+  if (format.pixel_format == PIXEL_FORMAT_Y16) {
     return OnIncomingCapturedY16Data(data, length, format, reference_time,
                                      timestamp, frame_feedback_id);
   }
@@ -156,9 +151,8 @@
     rotation_mode = libyuv::kRotate270;
 
   const gfx::Size dimensions(destination_width, destination_height);
-  Buffer buffer =
-      ReserveOutputBuffer(dimensions, media::PIXEL_FORMAT_I420,
-                          media::PIXEL_STORAGE_CPU, frame_feedback_id);
+  Buffer buffer = ReserveOutputBuffer(dimensions, PIXEL_FORMAT_I420,
+                                      PIXEL_STORAGE_CPU, frame_feedback_id);
 #if DCHECK_IS_ON()
   dropped_frame_counter_ = buffer.is_valid() ? 0 : dropped_frame_counter_ + 1;
   if (dropped_frame_counter_ >= kMaxDroppedFrames)
@@ -174,13 +168,13 @@
   auto buffer_access = buffer.handle_provider->GetHandleForInProcessAccess();
   uint8_t* y_plane_data = buffer_access->data();
   uint8_t* u_plane_data =
-      y_plane_data + VideoFrame::PlaneSize(media::PIXEL_FORMAT_I420,
-                                           VideoFrame::kYPlane, dimensions)
-                         .GetArea();
+      y_plane_data +
+      VideoFrame::PlaneSize(PIXEL_FORMAT_I420, VideoFrame::kYPlane, dimensions)
+          .GetArea();
   uint8_t* v_plane_data =
-      u_plane_data + VideoFrame::PlaneSize(media::PIXEL_FORMAT_I420,
-                                           VideoFrame::kUPlane, dimensions)
-                         .GetArea();
+      u_plane_data +
+      VideoFrame::PlaneSize(PIXEL_FORMAT_I420, VideoFrame::kUPlane, dimensions)
+          .GetArea();
 
   const int yplane_stride = dimensions.width();
   const int uv_plane_stride = yplane_stride / 2;
@@ -190,33 +184,33 @@
 
   bool flip = false;
   switch (format.pixel_format) {
-    case media::PIXEL_FORMAT_UNKNOWN:  // Color format not set.
+    case PIXEL_FORMAT_UNKNOWN:  // Color format not set.
       break;
-    case media::PIXEL_FORMAT_I420:
+    case PIXEL_FORMAT_I420:
       DCHECK(!chopped_width && !chopped_height);
       origin_colorspace = libyuv::FOURCC_I420;
       break;
-    case media::PIXEL_FORMAT_YV12:
+    case PIXEL_FORMAT_YV12:
       DCHECK(!chopped_width && !chopped_height);
       origin_colorspace = libyuv::FOURCC_YV12;
       break;
-    case media::PIXEL_FORMAT_NV12:
+    case PIXEL_FORMAT_NV12:
       DCHECK(!chopped_width && !chopped_height);
       origin_colorspace = libyuv::FOURCC_NV12;
       break;
-    case media::PIXEL_FORMAT_NV21:
+    case PIXEL_FORMAT_NV21:
       DCHECK(!chopped_width && !chopped_height);
       origin_colorspace = libyuv::FOURCC_NV21;
       break;
-    case media::PIXEL_FORMAT_YUY2:
+    case PIXEL_FORMAT_YUY2:
       DCHECK(!chopped_width && !chopped_height);
       origin_colorspace = libyuv::FOURCC_YUY2;
       break;
-    case media::PIXEL_FORMAT_UYVY:
+    case PIXEL_FORMAT_UYVY:
       DCHECK(!chopped_width && !chopped_height);
       origin_colorspace = libyuv::FOURCC_UYVY;
       break;
-    case media::PIXEL_FORMAT_RGB24:
+    case PIXEL_FORMAT_RGB24:
 // Linux RGB24 defines red at lowest byte address,
 // see http://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html.
 // Windows RGB24 defines blue at lowest byte,
@@ -236,16 +230,16 @@
       flip = true;
 #endif
       break;
-    case media::PIXEL_FORMAT_RGB32:
+    case PIXEL_FORMAT_RGB32:
 // Fallback to PIXEL_FORMAT_ARGB setting |flip| in Windows
 // platforms.
 #if defined(OS_WIN)
       flip = true;
 #endif
-    case media::PIXEL_FORMAT_ARGB:
+    case PIXEL_FORMAT_ARGB:
       origin_colorspace = libyuv::FOURCC_ARGB;
       break;
-    case media::PIXEL_FORMAT_MJPEG:
+    case PIXEL_FORMAT_MJPEG:
       origin_colorspace = libyuv::FOURCC_MJPG;
       break;
     default:
@@ -262,8 +256,8 @@
     if (status == VideoCaptureJpegDecoder::FAILED) {
       external_jpeg_decoder_.reset();
     } else if (status == VideoCaptureJpegDecoder::INIT_PASSED &&
-               format.pixel_format == media::PIXEL_FORMAT_MJPEG &&
-               rotation == 0 && !flip) {
+               format.pixel_format == PIXEL_FORMAT_MJPEG && rotation == 0 &&
+               !flip) {
       if (on_started_using_gpu_cb_)
         std::move(on_started_using_gpu_cb_).Run();
       external_jpeg_decoder_->DecodeCapturedData(
@@ -279,23 +273,21 @@
           (flip ? -1 : 1) * format.frame_size.height(), new_unrotated_width,
           new_unrotated_height, rotation_mode, origin_colorspace) != 0) {
     DLOG(WARNING) << "Failed to convert buffer's pixel format to I420 from "
-                  << media::VideoPixelFormatToString(format.pixel_format);
+                  << VideoPixelFormatToString(format.pixel_format);
     return;
   }
 
-  const VideoCaptureFormat output_format =
-      VideoCaptureFormat(dimensions, format.frame_rate,
-                         media::PIXEL_FORMAT_I420, media::PIXEL_STORAGE_CPU);
+  const VideoCaptureFormat output_format = VideoCaptureFormat(
+      dimensions, format.frame_rate, PIXEL_FORMAT_I420, PIXEL_STORAGE_CPU);
   OnIncomingCapturedBuffer(std::move(buffer), output_format, reference_time,
                            timestamp);
 }
 
-media::VideoCaptureDevice::Client::Buffer
-VideoCaptureDeviceClient::ReserveOutputBuffer(
-    const gfx::Size& frame_size,
-    media::VideoPixelFormat pixel_format,
-    media::VideoPixelStorage pixel_storage,
-    int frame_feedback_id) {
+VideoCaptureDevice::Client::Buffer
+VideoCaptureDeviceClient::ReserveOutputBuffer(const gfx::Size& frame_size,
+                                              VideoPixelFormat pixel_format,
+                                              VideoPixelStorage pixel_storage,
+                                              int frame_feedback_id) {
   DFAKE_SCOPED_RECURSIVE_LOCK(call_from_producer_);
   DCHECK_GT(frame_size.width(), 0);
   DCHECK_GT(frame_size.height(), 0);
@@ -351,9 +343,8 @@
 
   VideoFrameMetadata metadata;
   metadata.MergeMetadataFrom(&additional_metadata);
-  metadata.SetDouble(media::VideoFrameMetadata::FRAME_RATE, format.frame_rate);
-  metadata.SetTimeTicks(media::VideoFrameMetadata::REFERENCE_TIME,
-                        reference_time);
+  metadata.SetDouble(VideoFrameMetadata::FRAME_RATE, format.frame_rate);
+  metadata.SetTimeTicks(VideoFrameMetadata::REFERENCE_TIME, reference_time);
 
   mojom::VideoFrameInfoPtr info = mojom::VideoFrameInfo::New();
   info->timestamp = timestamp;
@@ -371,12 +362,11 @@
       std::move(info));
 }
 
-media::VideoCaptureDevice::Client::Buffer
-VideoCaptureDeviceClient::ResurrectLastOutputBuffer(
-    const gfx::Size& dimensions,
-    media::VideoPixelFormat format,
-    media::VideoPixelStorage storage,
-    int new_frame_feedback_id) {
+VideoCaptureDevice::Client::Buffer
+VideoCaptureDeviceClient::ResurrectLastOutputBuffer(const gfx::Size& dimensions,
+                                                    VideoPixelFormat format,
+                                                    VideoPixelStorage storage,
+                                                    int new_frame_feedback_id) {
   DFAKE_SCOPED_RECURSIVE_LOCK(call_from_producer_);
   const int buffer_id =
       buffer_pool_->ResurrectLastForProducer(dimensions, format, storage);
@@ -416,9 +406,8 @@
     base::TimeTicks reference_time,
     base::TimeDelta timestamp,
     int frame_feedback_id) {
-  Buffer buffer =
-      ReserveOutputBuffer(format.frame_size, media::PIXEL_FORMAT_Y16,
-                          media::PIXEL_STORAGE_CPU, frame_feedback_id);
+  Buffer buffer = ReserveOutputBuffer(format.frame_size, PIXEL_FORMAT_Y16,
+                                      PIXEL_STORAGE_CPU, frame_feedback_id);
   // The input |length| can be greater than the required buffer size because of
   // paddings and/or alignments, but it cannot be smaller.
   DCHECK_GE(static_cast<size_t>(length), format.ImageAllocationSize());
@@ -433,8 +422,8 @@
   auto buffer_access = buffer.handle_provider->GetHandleForInProcessAccess();
   memcpy(buffer_access->data(), data, length);
   const VideoCaptureFormat output_format =
-      VideoCaptureFormat(format.frame_size, format.frame_rate,
-                         media::PIXEL_FORMAT_Y16, media::PIXEL_STORAGE_CPU);
+      VideoCaptureFormat(format.frame_size, format.frame_rate, PIXEL_FORMAT_Y16,
+                         PIXEL_STORAGE_CPU);
   OnIncomingCapturedBuffer(std::move(buffer), output_format, reference_time,
                            timestamp);
 }
diff --git a/media/capture/video/video_capture_device_client.h b/media/capture/video/video_capture_device_client.h
index c863a6ee..77bc796 100644
--- a/media/capture/video/video_capture_device_client.h
+++ b/media/capture/video/video_capture_device_client.h
@@ -25,7 +25,7 @@
 using VideoCaptureJpegDecoderFactoryCB =
     base::Callback<std::unique_ptr<VideoCaptureJpegDecoder>()>;
 
-// Implementation of media::VideoCaptureDevice::Client that uses a buffer pool
+// Implementation of VideoCaptureDevice::Client that uses a buffer pool
 // to provide buffers and converts incoming data to the I420 format for
 // consumption by a given VideoFrameReceiver.
 //
@@ -36,7 +36,7 @@
 // The owner is responsible for making sure that the instance outlives these
 // calls.
 class CAPTURE_EXPORT VideoCaptureDeviceClient
-    : public media::VideoCaptureDevice::Client {
+    : public VideoCaptureDevice::Client {
  public:
   VideoCaptureDeviceClient(
       std::unique_ptr<VideoFrameReceiver> receiver,
@@ -52,14 +52,14 @@
   // VideoCaptureDevice::Client implementation.
   void OnIncomingCapturedData(const uint8_t* data,
                               int length,
-                              const media::VideoCaptureFormat& frame_format,
+                              const VideoCaptureFormat& frame_format,
                               int rotation,
                               base::TimeTicks reference_time,
                               base::TimeDelta timestamp,
                               int frame_feedback_id = 0) override;
   Buffer ReserveOutputBuffer(const gfx::Size& dimensions,
-                             media::VideoPixelFormat format,
-                             media::VideoPixelStorage storage,
+                             VideoPixelFormat format,
+                             VideoPixelStorage storage,
                              int frame_feedback_id) override;
   void OnIncomingCapturedBuffer(Buffer buffer,
                                 const VideoCaptureFormat& format,
@@ -73,8 +73,8 @@
       gfx::Rect visible_rect,
       const VideoFrameMetadata& additional_metadata) override;
   Buffer ResurrectLastOutputBuffer(const gfx::Size& dimensions,
-                                   media::VideoPixelFormat format,
-                                   media::VideoPixelStorage storage,
+                                   VideoPixelFormat format,
+                                   VideoPixelStorage storage,
                                    int new_frame_feedback_id) override;
   void OnError(const base::Location& from_here,
                const std::string& reason) override;
@@ -113,7 +113,7 @@
   static const int kMaxDroppedFrames = 150;
 #endif  // DCHECK_IS_ON()
 
-  media::VideoPixelFormat last_captured_pixel_format_;
+  VideoPixelFormat last_captured_pixel_format_;
 
   // Thread collision warner to ensure that producer-facing API is not called
   // concurrently. Producers are allowed to call from multiple threads, but not
diff --git a/media/capture/video/video_capture_device_client_unittest.cc b/media/capture/video/video_capture_device_client_unittest.cc
index b1287313..a53f28e 100644
--- a/media/capture/video/video_capture_device_client_unittest.cc
+++ b/media/capture/video/video_capture_device_client_unittest.cc
@@ -31,7 +31,7 @@
 
 namespace {
 
-std::unique_ptr<media::VideoCaptureJpegDecoder> ReturnNullPtrAsJpecDecoder() {
+std::unique_ptr<VideoCaptureJpegDecoder> ReturnNullPtrAsJpecDecoder() {
   return nullptr;
 }
 
@@ -45,13 +45,12 @@
 class VideoCaptureDeviceClientTest : public ::testing::Test {
  public:
   VideoCaptureDeviceClientTest() {
-    scoped_refptr<media::VideoCaptureBufferPoolImpl> buffer_pool(
-        new media::VideoCaptureBufferPoolImpl(
-            base::MakeUnique<media::VideoCaptureBufferTrackerFactoryImpl>(),
-            1));
+    scoped_refptr<VideoCaptureBufferPoolImpl> buffer_pool(
+        new VideoCaptureBufferPoolImpl(
+            base::MakeUnique<VideoCaptureBufferTrackerFactoryImpl>(), 1));
     auto controller = base::MakeUnique<MockVideoFrameReceiver>();
     receiver_ = controller.get();
-    device_client_ = base::MakeUnique<media::VideoCaptureDeviceClient>(
+    device_client_ = base::MakeUnique<VideoCaptureDeviceClient>(
         std::move(controller), buffer_pool,
         base::Bind(&ReturnNullPtrAsJpecDecoder));
   }
@@ -59,7 +58,7 @@
 
  protected:
   MockVideoFrameReceiver* receiver_;
-  std::unique_ptr<media::VideoCaptureDeviceClient> device_client_;
+  std::unique_ptr<VideoCaptureDeviceClient> device_client_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(VideoCaptureDeviceClientTest);
@@ -70,9 +69,8 @@
 TEST_F(VideoCaptureDeviceClientTest, Minimal) {
   const size_t kScratchpadSizeInBytes = 400;
   unsigned char data[kScratchpadSizeInBytes] = {};
-  const media::VideoCaptureFormat kFrameFormat(
-      gfx::Size(10, 10), 30.0f /*frame_rate*/, media::PIXEL_FORMAT_I420,
-      media::PIXEL_STORAGE_CPU);
+  const VideoCaptureFormat kFrameFormat(gfx::Size(10, 10), 30.0f /*frame_rate*/,
+                                        PIXEL_FORMAT_I420, PIXEL_STORAGE_CPU);
   DCHECK(device_client_.get());
   {
     InSequence s;
@@ -94,11 +92,10 @@
   const size_t kScratchpadSizeInBytes = 400;
   unsigned char data[kScratchpadSizeInBytes] = {};
   // kFrameFormat is invalid in a number of ways.
-  const media::VideoCaptureFormat kFrameFormat(
-      gfx::Size(media::limits::kMaxDimension + 1, media::limits::kMaxDimension),
-      media::limits::kMaxFramesPerSecond + 1,
-      media::VideoPixelFormat::PIXEL_FORMAT_I420,
-      media::VideoPixelStorage::PIXEL_STORAGE_CPU);
+  const VideoCaptureFormat kFrameFormat(
+      gfx::Size(limits::kMaxDimension + 1, limits::kMaxDimension),
+      limits::kMaxFramesPerSecond + 1, VideoPixelFormat::PIXEL_FORMAT_I420,
+      VideoPixelStorage::PIXEL_STORAGE_CPU);
   DCHECK(device_client_.get());
   // Expect the the call to fail silently inside the VideoCaptureDeviceClient.
   EXPECT_CALL(*receiver_, OnLog(_)).Times(1);
@@ -113,9 +110,8 @@
 TEST_F(VideoCaptureDeviceClientTest, DropsFrameIfNoBuffer) {
   const size_t kScratchpadSizeInBytes = 400;
   unsigned char data[kScratchpadSizeInBytes] = {};
-  const media::VideoCaptureFormat kFrameFormat(
-      gfx::Size(10, 10), 30.0f /*frame_rate*/, media::PIXEL_FORMAT_I420,
-      media::PIXEL_STORAGE_CPU);
+  const VideoCaptureFormat kFrameFormat(gfx::Size(10, 10), 30.0f /*frame_rate*/,
+                                        PIXEL_FORMAT_I420, PIXEL_STORAGE_CPU);
   EXPECT_CALL(*receiver_, OnLog(_)).Times(1);
   // Simulate that receiver still holds |buffer_read_permission| for the first
   // buffer when the second call to OnIncomingCapturedData comes in.
@@ -124,14 +120,15 @@
   std::unique_ptr<VideoCaptureDevice::Client::Buffer::ScopedAccessPermission>
       read_permission;
   EXPECT_CALL(*receiver_, MockOnFrameReadyInBuffer(_, _, _))
-      .WillOnce(Invoke([&read_permission](
-                           int buffer_id,
-                           std::unique_ptr<media::VideoCaptureDevice::Client::
-                                               Buffer::ScopedAccessPermission>*
-                               buffer_read_permission,
-                           const gfx::Size&) {
-        read_permission = std::move(*buffer_read_permission);
-      }));
+      .WillOnce(Invoke(
+          [&read_permission](
+              int buffer_id,
+              std::unique_ptr<
+                  VideoCaptureDevice::Client::Buffer::ScopedAccessPermission>*
+                  buffer_read_permission,
+              const gfx::Size&) {
+            read_permission = std::move(*buffer_read_permission);
+          }));
   // Pass two frames. The second will be dropped.
   device_client_->OnIncomingCapturedData(data, kScratchpadSizeInBytes,
                                          kFrameFormat, 0 /*clockwise rotation*/,
@@ -154,28 +151,28 @@
   ASSERT_GE(kScratchpadSizeInBytes, kCaptureResolution.GetArea() * 4u)
       << "Scratchpad is too small to hold the largest pixel format (ARGB).";
 
-  media::VideoCaptureParams params;
-  params.requested_format = media::VideoCaptureFormat(
-      kCaptureResolution, 30.0f, media::PIXEL_FORMAT_UNKNOWN);
+  VideoCaptureParams params;
+  params.requested_format =
+      VideoCaptureFormat(kCaptureResolution, 30.0f, PIXEL_FORMAT_UNKNOWN);
 
   // Only use the VideoPixelFormats that we know supported. Do not add
   // PIXEL_FORMAT_MJPEG since it would need a real JPEG header.
-  const media::VideoPixelFormat kSupportedFormats[] = {
-    media::PIXEL_FORMAT_I420,
-    media::PIXEL_FORMAT_YV12,
-    media::PIXEL_FORMAT_NV12,
-    media::PIXEL_FORMAT_NV21,
-    media::PIXEL_FORMAT_YUY2,
-    media::PIXEL_FORMAT_UYVY,
+  const VideoPixelFormat kSupportedFormats[] = {
+    PIXEL_FORMAT_I420,
+    PIXEL_FORMAT_YV12,
+    PIXEL_FORMAT_NV12,
+    PIXEL_FORMAT_NV21,
+    PIXEL_FORMAT_YUY2,
+    PIXEL_FORMAT_UYVY,
 #if defined(OS_WIN) || defined(OS_LINUX)
-    media::PIXEL_FORMAT_RGB24,
+    PIXEL_FORMAT_RGB24,
 #endif
-    media::PIXEL_FORMAT_RGB32,
-    media::PIXEL_FORMAT_ARGB,
-    media::PIXEL_FORMAT_Y16,
+    PIXEL_FORMAT_RGB32,
+    PIXEL_FORMAT_ARGB,
+    PIXEL_FORMAT_Y16,
   };
 
-  for (media::VideoPixelFormat format : kSupportedFormats) {
+  for (VideoPixelFormat format : kSupportedFormats) {
     params.requested_format.pixel_format = format;
 
     EXPECT_CALL(*receiver_, OnLog(_)).Times(1);
@@ -209,13 +206,13 @@
 
   EXPECT_CALL(*receiver_, OnLog(_)).Times(1);
 
-  media::VideoCaptureParams params;
+  VideoCaptureParams params;
   for (const auto& size_and_rotation : kSizeAndRotations) {
     ASSERT_GE(kScratchpadSizeInBytes,
               size_and_rotation.input_resolution.GetArea() * 4u)
         << "Scratchpad is too small to hold the largest pixel format (ARGB).";
-    params.requested_format = media::VideoCaptureFormat(
-        size_and_rotation.input_resolution, 30.0f, media::PIXEL_FORMAT_ARGB);
+    params.requested_format = VideoCaptureFormat(
+        size_and_rotation.input_resolution, 30.0f, PIXEL_FORMAT_ARGB);
     gfx::Size coded_size;
     EXPECT_CALL(*receiver_, MockOnFrameReadyInBuffer(_, _, _))
         .Times(1)
diff --git a/media/capture/video/video_capture_device_factory.cc b/media/capture/video/video_capture_device_factory.cc
index cefeb5c0..2f535ec 100644
--- a/media/capture/video/video_capture_device_factory.cc
+++ b/media/capture/video/video_capture_device_factory.cc
@@ -26,14 +26,14 @@
   if (command_line->HasSwitch(switches::kUseFakeDeviceForMediaStream)) {
     if (command_line->HasSwitch(switches::kUseFileForFakeVideoCapture)) {
       return std::unique_ptr<VideoCaptureDeviceFactory>(
-          new media::FileVideoCaptureDeviceFactory());
+          new FileVideoCaptureDeviceFactory());
     } else {
       std::vector<FakeVideoCaptureDeviceSettings> config;
       FakeVideoCaptureDeviceFactory::ParseFakeDevicesConfigFromOptionsString(
           command_line->GetSwitchValueASCII(
               switches::kUseFakeDeviceForMediaStream),
           &config);
-      auto result = base::MakeUnique<media::FakeVideoCaptureDeviceFactory>();
+      auto result = base::MakeUnique<FakeVideoCaptureDeviceFactory>();
       result->SetToCustomDevicesConfig(config);
       return std::move(result);
     }
diff --git a/media/capture/video/video_capture_device_info.cc b/media/capture/video/video_capture_device_info.cc
index 50f999b..90a097fd 100644
--- a/media/capture/video/video_capture_device_info.cc
+++ b/media/capture/video/video_capture_device_info.cc
@@ -9,7 +9,7 @@
 VideoCaptureDeviceInfo::VideoCaptureDeviceInfo() = default;
 
 VideoCaptureDeviceInfo::VideoCaptureDeviceInfo(
-    media::VideoCaptureDeviceDescriptor descriptor)
+    VideoCaptureDeviceDescriptor descriptor)
     : descriptor(descriptor) {}
 
 VideoCaptureDeviceInfo::VideoCaptureDeviceInfo(
diff --git a/media/capture/video/video_capture_device_info.h b/media/capture/video/video_capture_device_info.h
index 32f61c6..88445cb9 100644
--- a/media/capture/video/video_capture_device_info.h
+++ b/media/capture/video/video_capture_device_info.h
@@ -10,17 +10,17 @@
 
 namespace media {
 
-// Bundles a media::VideoCaptureDeviceDescriptor with corresponding supported
+// Bundles a VideoCaptureDeviceDescriptor with corresponding supported
 // video formats.
 struct CAPTURE_EXPORT VideoCaptureDeviceInfo {
   VideoCaptureDeviceInfo();
-  VideoCaptureDeviceInfo(media::VideoCaptureDeviceDescriptor descriptor);
+  VideoCaptureDeviceInfo(VideoCaptureDeviceDescriptor descriptor);
   VideoCaptureDeviceInfo(const VideoCaptureDeviceInfo& other);
   ~VideoCaptureDeviceInfo();
   VideoCaptureDeviceInfo& operator=(const VideoCaptureDeviceInfo& other);
 
-  media::VideoCaptureDeviceDescriptor descriptor;
-  media::VideoCaptureFormats supported_formats;
+  VideoCaptureDeviceDescriptor descriptor;
+  VideoCaptureFormats supported_formats;
 };
 
 }  // namespace media
diff --git a/media/capture/video/video_capture_device_unittest.cc b/media/capture/video/video_capture_device_unittest.cc
index 5160067..c9d9cf4 100644
--- a/media/capture/video/video_capture_device_unittest.cc
+++ b/media/capture/video/video_capture_device_unittest.cc
@@ -148,8 +148,8 @@
 
   // Trampoline methods to workaround GMOCK problems with std::unique_ptr<>.
   Buffer ReserveOutputBuffer(const gfx::Size& dimensions,
-                             media::VideoPixelFormat format,
-                             media::VideoPixelStorage storage,
+                             VideoPixelFormat format,
+                             VideoPixelStorage storage,
                              int frame_feedback_id) override {
     DoReserveOutputBuffer();
     NOTREACHED() << "This should never be called";
@@ -171,8 +171,8 @@
     DoOnIncomingCapturedVideoFrame();
   }
   Buffer ResurrectLastOutputBuffer(const gfx::Size& dimensions,
-                                   media::VideoPixelFormat format,
-                                   media::VideoPixelStorage storage,
+                                   VideoPixelFormat format,
+                                   VideoPixelStorage storage,
                                    int frame_feedback_id) {
     DoResurrectLastOutputBuffer();
     NOTREACHED() << "This should never be called";
@@ -638,7 +638,7 @@
       &MockImageCaptureClient::DoOnPhotoTaken, image_capture_client_);
 
   base::RunLoop run_loop;
-  base::Closure quit_closure = media::BindToCurrentLoop(run_loop.QuitClosure());
+  base::Closure quit_closure = BindToCurrentLoop(run_loop.QuitClosure());
   EXPECT_CALL(*image_capture_client_.get(), OnCorrectPhotoTaken())
       .Times(1)
       .WillOnce(RunClosure(quit_closure));
@@ -688,7 +688,7 @@
                      image_capture_client_);
 
   base::RunLoop run_loop;
-  base::Closure quit_closure = media::BindToCurrentLoop(run_loop.QuitClosure());
+  base::Closure quit_closure = BindToCurrentLoop(run_loop.QuitClosure());
   EXPECT_CALL(*image_capture_client_.get(), OnCorrectGetPhotoState())
       .Times(1)
       .WillOnce(RunClosure(quit_closure));
diff --git a/media/capture/video/video_capture_jpeg_decoder.h b/media/capture/video/video_capture_jpeg_decoder.h
index 535349c..54a0113 100644
--- a/media/capture/video/video_capture_jpeg_decoder.h
+++ b/media/capture/video/video_capture_jpeg_decoder.h
@@ -43,10 +43,10 @@
   virtual void DecodeCapturedData(
       const uint8_t* data,
       size_t in_buffer_size,
-      const media::VideoCaptureFormat& frame_format,
+      const VideoCaptureFormat& frame_format,
       base::TimeTicks reference_time,
       base::TimeDelta timestamp,
-      media::VideoCaptureDevice::Client::Buffer out_buffer) = 0;
+      VideoCaptureDevice::Client::Buffer out_buffer) = 0;
 };
 
 }  // namespace media
diff --git a/media/capture/video/video_capture_system_impl.cc b/media/capture/video/video_capture_system_impl.cc
index 84cc8a2f..7f75104 100644
--- a/media/capture/video/video_capture_system_impl.cc
+++ b/media/capture/video/video_capture_system_impl.cc
@@ -104,11 +104,11 @@
 const VideoCaptureDeviceInfo* VideoCaptureSystemImpl::LookupDeviceInfoFromId(
     const std::string& device_id) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  auto iter = std::find_if(
-      devices_info_cache_.begin(), devices_info_cache_.end(),
-      [&device_id](const media::VideoCaptureDeviceInfo& device_info) {
-        return device_info.descriptor.device_id == device_id;
-      });
+  auto iter =
+      std::find_if(devices_info_cache_.begin(), devices_info_cache_.end(),
+                   [&device_id](const VideoCaptureDeviceInfo& device_info) {
+                     return device_info.descriptor.device_id == device_id;
+                   });
   if (iter == devices_info_cache_.end())
     return nullptr;
   return &(*iter);
diff --git a/media/capture/video/win/sink_input_pin_win.cc b/media/capture/video/win/sink_input_pin_win.cc
index 75b5c42e..8b8db29 100644
--- a/media/capture/video/win/sink_input_pin_win.cc
+++ b/media/capture/video/win/sink_input_pin_win.cc
@@ -219,7 +219,7 @@
     return S_FALSE;
 
   REFERENCE_TIME start_time, end_time;
-  base::TimeDelta timestamp = media::kNoTimestamp;
+  base::TimeDelta timestamp = kNoTimestamp;
   if (SUCCEEDED(sample->GetTime(&start_time, &end_time))) {
     DCHECK(start_time <= end_time);
     timestamp = base::TimeDelta::FromMicroseconds(start_time / 10);
diff --git a/media/capture/video/win/video_capture_device_win.cc b/media/capture/video/win/video_capture_device_win.cc
index e1e9ac7..5afe42b 100644
--- a/media/capture/video/win/video_capture_device_win.cc
+++ b/media/capture/video/win/video_capture_device_win.cc
@@ -844,7 +844,7 @@
 
   // There is a chance that the platform does not provide us with the timestamp,
   // in which case, we use reference time to calculate a timestamp.
-  if (timestamp == media::kNoTimestamp)
+  if (timestamp == kNoTimestamp)
     timestamp = base::TimeTicks::Now() - first_ref_time_;
 
   client_->OnIncomingCapturedData(buffer, length, format, 0,
@@ -871,8 +871,8 @@
 void VideoCaptureDeviceWin::SetAntiFlickerInCaptureFilter(
     const VideoCaptureParams& params) {
   const PowerLineFrequency power_line_frequency = GetPowerLineFrequency(params);
-  if (power_line_frequency != media::PowerLineFrequency::FREQUENCY_50HZ &&
-      power_line_frequency != media::PowerLineFrequency::FREQUENCY_60HZ) {
+  if (power_line_frequency != PowerLineFrequency::FREQUENCY_50HZ &&
+      power_line_frequency != PowerLineFrequency::FREQUENCY_60HZ) {
     return;
   }
   ComPtr<IKsPropertySet> ks_propset;
@@ -889,8 +889,7 @@
     data.Property.Id = KSPROPERTY_VIDEOPROCAMP_POWERLINE_FREQUENCY;
     data.Property.Flags = KSPROPERTY_TYPE_SET;
     data.Value =
-        (power_line_frequency == media::PowerLineFrequency::FREQUENCY_50HZ) ? 1
-                                                                            : 2;
+        (power_line_frequency == PowerLineFrequency::FREQUENCY_50HZ) ? 1 : 2;
     data.Flags = KSPROPERTY_VIDEOPROCAMP_FLAGS_MANUAL;
     hr = ks_propset->Set(PROPSETID_VIDCAP_VIDEOPROCAMP,
                          KSPROPERTY_VIDEOPROCAMP_POWERLINE_FREQUENCY, &data,
diff --git a/services/ui/ws/window_server.cc b/services/ui/ws/window_server.cc
index b0ab2c9..d3c5a17 100644
--- a/services/ui/ws/window_server.cc
+++ b/services/ui/ws/window_server.cc
@@ -90,9 +90,12 @@
       viz::mojom::DisplayPrivateAssociatedRequest display_private_request)
       override {
     if (manager_) {
+      // No software compositing on ChromeOS.
+      bool force_software_compositing = false;
       manager_->CreateRootCompositorFrameSink(
-          frame_sink_id, surface_handle, renderer_settings, std::move(request),
-          std::move(client), std::move(display_private_request));
+          frame_sink_id, surface_handle, force_software_compositing,
+          renderer_settings, std::move(request), std::move(client),
+          std::move(display_private_request));
     }
   }
 
diff --git a/services/viz/privileged/interfaces/compositing/frame_sink_manager.mojom b/services/viz/privileged/interfaces/compositing/frame_sink_manager.mojom
index 06f8d8a..b1bf5f69 100644
--- a/services/viz/privileged/interfaces/compositing/frame_sink_manager.mojom
+++ b/services/viz/privileged/interfaces/compositing/frame_sink_manager.mojom
@@ -47,10 +47,13 @@
 
   // Create a CompositorFrameSink for a privileged client (e.g. WindowServer).
   // This is only used by privileged clients. The client can call methods that
-  // talks to the Display (e.g. ResizeDisplay(), SetDisplayVisible(), etc)
+  // talks to the Display (e.g. ResizeDisplay(), SetDisplayVisible(), etc).
+  // If |force_software_compositing| is true, then the resulting display
+  // compositor will not use Gpu acceleration even if it would by default.
   CreateRootCompositorFrameSink(
       FrameSinkId frame_sink_id,
       gpu.mojom.SurfaceHandle widget,
+      bool force_software_compositing,
       RendererSettings renderer_settings,
       associated CompositorFrameSink& compositor_frame_sink,
       CompositorFrameSinkClient compositor_frame_sink_client,
diff --git a/testing/buildbot/filters/ash_unittests_mash.filter b/testing/buildbot/filters/ash_unittests_mash.filter
index c20b032..181542d 100644
--- a/testing/buildbot/filters/ash_unittests_mash.filter
+++ b/testing/buildbot/filters/ash_unittests_mash.filter
@@ -54,15 +54,10 @@
 # TODO: Top-of-screen mouse reveal doesn't work, maybe problem with
 # EventGenerator. http://crbug.com/698085
 -ImmersiveFullscreenControllerTest.Bubbles
--ImmersiveFullscreenControllerTest.Delegate
 -ImmersiveFullscreenControllerTest.DifferentModalityEnterExit
 -ImmersiveFullscreenControllerTest.EndRevealViaGesture
--ImmersiveFullscreenControllerTest.EventsDoNotLeakToWindowUnderneath
 -ImmersiveFullscreenControllerTest.Focus
--ImmersiveFullscreenControllerTest.Inactive
 -ImmersiveFullscreenControllerTest.MouseEventsVerticalDisplayLayout
--ImmersiveFullscreenControllerTest.MouseHoveredWithoutMoving
--ImmersiveFullscreenControllerTest.OnMouseEvent
 -ImmersiveFullscreenControllerTest.RevealViaGestureChildConsumesEvents
 -ImmersiveFullscreenControllerTest.Transient
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/audio-worklet-common.js b/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/audio-worklet-common.js
index f8f3fcf..72957465 100644
--- a/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/audio-worklet-common.js
+++ b/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/audio-worklet-common.js
@@ -1,16 +1,13 @@
-/**
- * Assert AudioWorklet is enabled.
- *
- * The content_shell driven by run-webkit-tests.py is supposed to enable all the
- * experimental web platform features.
- *
- * We also want to run the test on the browser. So we check both cases for
- * the content shell and the browser.
- */
+// Check if AudioWorklet is available before running a test.
 function assertAudioWorklet() {
+  let offlineContext = new OfflineAudioContext(1, 1, 44100);
+
+  // We want to be able to run tests both on the browser and the content shell.
+  // So check if AudioWorklet runtime flag is enabled, or check the context
+  // has AudioWorklet object.
   if ((Boolean(window.internals) &&
        Boolean(window.internals.runtimeFlags.audioWorkletEnabled)) ||
-      (Boolean(window.Worklet) && Boolean(window.audioWorklet))) {
+      offlineContext.audioWorklet instanceof AudioWorklet) {
     return;
   }
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/audio-worklet-gain-node.html b/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/audio-worklet-gain-node.html
index 12843b47..0f0ac3ed 100644
--- a/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/audio-worklet-gain-node.html
+++ b/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/audio-worklet-gain-node.html
@@ -21,8 +21,8 @@
 
       // Sets up AudioWorklet and OfflineAudioContext.
       audit.define('Initializing AudioWorklet and Context', (task, should) => {
-        audioWorklet.addModule('gain-processor.js').then(() => {
-          context = new OfflineAudioContext(1, renderLength, sampleRate);
+        context = new OfflineAudioContext(1, renderLength, sampleRate);
+        context.audioWorklet.addModule('gain-processor.js').then(() => {
           task.done();
         });
       });
diff --git a/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/audio-worklet-node-construction.html b/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/audio-worklet-node-construction.html
index d0aae9cb..63c1e72 100644
--- a/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/audio-worklet-node-construction.html
+++ b/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/audio-worklet-node-construction.html
@@ -36,17 +36,19 @@
       audit.define(
           {label: 'construction-after-module-loading'},
           (task, should) => {
-            audioWorklet.addModule('dummy-processor.js').then(() => {
-              let dummyWorkletNode =
-                  new AudioWorkletNode(realtimeContext, 'dummy');
-              should(dummyWorkletNode instanceof AudioWorkletNode,
-                     '"dummyWorkletNode" is an instance of AudioWorkletNode')
-                  .beTrue();
-              should(() => new AudioWorkletNode(realtimeContext, 'foobar'),
-                     'Unregistered name "foobar" must throw an exception.')
-                  .throw();
-              task.done();
-            });
+            realtimeContext.audioWorklet.addModule('dummy-processor.js')
+                .then(() => {
+                  let dummyWorkletNode =
+                      new AudioWorkletNode(realtimeContext, 'dummy');
+                  should(dummyWorkletNode instanceof AudioWorkletNode,
+                         '"dummyWorkletNode" is an instance of '
+                         + 'AudioWorkletNode')
+                      .beTrue();
+                  should(() => new AudioWorkletNode(realtimeContext, 'foobar'),
+                         'Unregistered name "foobar" must throw an exception.')
+                      .throw();
+                  task.done();
+                });
           });
 
       audit.run();
diff --git a/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/audio-worklet-node-options.html b/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/audio-worklet-node-options.html
index 0ef5cb2..6e4461d 100644
--- a/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/audio-worklet-node-options.html
+++ b/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/audio-worklet-node-options.html
@@ -21,8 +21,8 @@
 
       // Load script file and create a OfflineAudiocontext.
       audit.define('setup', (task, should) => {
-        audioWorklet.addModule('dummy-processor.js').then(() => {
-          context = new OfflineAudioContext(1, 1, sampleRate);
+        context = new OfflineAudioContext(1, 1, sampleRate);
+        context.audioWorklet.addModule('dummy-processor.js').then(() => {
           task.done();
         });
       });
diff --git a/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/audio-worklet-processor-state.html b/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/audio-worklet-processor-state.html
index 09f79c1..c1c51740 100644
--- a/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/audio-worklet-processor-state.html
+++ b/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/audio-worklet-processor-state.html
@@ -23,59 +23,63 @@
       audit.define('pending-running-stopped',
           (task, should) => {
             let context = new OfflineAudioContext(1, renderLength, sampleRate);
-            let timedWorkletNode = new AudioWorkletNode(context, 'timed');
+            context.audioWorklet.addModule('state-processor.js').then(() => {
+              let timedWorkletNode = new AudioWorkletNode(context, 'timed');
 
-            // The construction of associated processor has not been
-            // completed. In this state, no audio processing can happen and
-            // all messages to the processor will be queued.
-            should(timedWorkletNode.processorState,
-                   'Checking the processor state upon the constructor call')
-                .beEqualTo('pending');
+              // The construction of associated processor has not been
+              // completed. In this state, no audio processing can happen and
+              // all messages to the processor will be queued.
+              should(timedWorkletNode.processorState,
+                     'Checking the processor state upon the constructor call')
+                  .beEqualTo('pending');
 
-            timedWorkletNode.connect(context.destination);
+              timedWorkletNode.connect(context.destination);
 
-            // Checks the handler of |onprocessorstatechange|. Because the
-            // processor script is correct, the |running| state change MUST
-            // be fired.
-            let isFirstPhase = true;
-            timedWorkletNode.onprocessorstatechange = () => {
-              // The first phase should be "running".
-              if (isFirstPhase) {
-                should(timedWorkletNode.processorState,
-                       'Checking the processor state upon ' +
-                       'processorstatechange event')
-                    .beEqualTo('running');
-                isFirstPhase = false;
-              } else {
-                // The second phase in this test must be "stopped".
-                should(timedWorkletNode.processorState,
-                       'Checking the processor state after ' +
-                       'processor stopped processing')
-                    .beEqualTo('stopped');
-                task.done();
-              }
-            };
+              // Checks the handler of |onprocessorstatechange|. Because the
+              // processor script is correct, the |running| state change MUST
+              // be fired.
+              let isFirstPhase = true;
+              timedWorkletNode.onprocessorstatechange = () => {
+                // The first phase should be "running".
+                if (isFirstPhase) {
+                  should(timedWorkletNode.processorState,
+                         'Checking the processor state upon ' +
+                         'processorstatechange event')
+                      .beEqualTo('running');
+                  isFirstPhase = false;
+                } else {
+                  // The second phase in this test must be "stopped".
+                  should(timedWorkletNode.processorState,
+                         'Checking the processor state after ' +
+                         'processor stopped processing')
+                      .beEqualTo('stopped');
+                  task.done();
+                }
+              };
 
-            context.startRendering();
+              context.startRendering();
+            });
           });
 
       // Test the error state caused by the failure of processor constructor.
       audit.define('constructor-error',
           (task, should) => {
             let context = new OfflineAudioContext(1, renderLength, sampleRate);
-            let constructorErrorWorkletNode =
-                new AudioWorkletNode(context, 'constructor-error');
-            should(constructorErrorWorkletNode.processorState,
-                   'constructorErrorWorkletNode.processorState after ' +
-                   'its construction')
-                .beEqualTo('pending');
-            constructorErrorWorkletNode.onprocessorstatechange = () => {
+            context.audioWorklet.addModule('state-processor.js').then(() => {
+              let constructorErrorWorkletNode =
+                  new AudioWorkletNode(context, 'constructor-error');
               should(constructorErrorWorkletNode.processorState,
-                     'workletNode.processorState upon processorstatechange ' +
-                     'event after the failure from processor.constructor()')
-                  .beEqualTo('error');
-              task.done();
-            };
+                     'constructorErrorWorkletNode.processorState after ' +
+                     'its construction')
+                  .beEqualTo('pending');
+              constructorErrorWorkletNode.onprocessorstatechange = () => {
+                should(constructorErrorWorkletNode.processorState,
+                       'workletNode.processorState upon processorstatechange ' +
+                       'event after the failure from processor.constructor()')
+                    .beEqualTo('error');
+                task.done();
+              };
+            });
           });
 
       // Test the error state caused by the failure of processor's process()
@@ -83,35 +87,35 @@
       audit.define('process-error',
           (task, should) => {
             let context = new OfflineAudioContext(1, renderLength, sampleRate);
-            let processErrorWorkletNode =
-                new AudioWorkletNode(context, 'process-error');
-            should(processErrorWorkletNode.processorState,
-                   'processErrorWorkletNode.processorState after ' +
-                   'its construction')
-                  .beEqualTo('pending');
+            context.audioWorklet.addModule('state-processor.js').then(() => {
+              let processErrorWorkletNode =
+                  new AudioWorkletNode(context, 'process-error');
+              should(processErrorWorkletNode.processorState,
+                     'processErrorWorkletNode.processorState after ' +
+                     'its construction')
+                    .beEqualTo('pending');
 
-            processErrorWorkletNode.connect(context.destination);
+              processErrorWorkletNode.connect(context.destination);
 
-            let isFirstPhase = true;
-            processErrorWorkletNode.onprocessorstatechange = () => {
-              if (isFirstPhase) {
-                // Ignore the first state change event, which is "running";
-                isFirstPhase = false;
-              } else {
-                should(processErrorWorkletNode.processorState,
-                       'workletNode.processorState upon processorstatechange ' +
-                       'event after the failure from processor.process()')
-                    .beEqualTo('error');
-                task.done();
-              }
-            };
+              let isFirstPhase = true;
+              processErrorWorkletNode.onprocessorstatechange = () => {
+                if (isFirstPhase) {
+                  // Ignore the first state change event, which is "running";
+                  isFirstPhase = false;
+                } else {
+                  should(processErrorWorkletNode.processorState,
+                         'workletNode.processorState upon processorstatechange ' +
+                         'event after the failure from processor.process()')
+                      .beEqualTo('error');
+                  task.done();
+                }
+              };
 
-            context.startRendering();
+              context.startRendering();
+            });
           });
 
-      audioWorklet.addModule('state-processor.js').then(() => {
-        audit.run();
-      });
+      audit.run();
     </script>
   </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/context-audio-worklet.html b/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/context-audio-worklet.html
new file mode 100644
index 0000000..adadbdbc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/context-audio-worklet.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>
+      Checking BaseAudioContext.audioWorklet
+    </title>
+    <script src="../../resources/testharness.js"></script>
+    <script src="../../resources/testharnessreport.js"></script>
+    <script src="../../../webaudio-resources/audit.js"></script>
+    <script src="audio-worklet-common.js"></script>
+  </head>
+  <body>
+    <script id="layout-test-code">
+      // TODO(hongchan): remove this assertion when AudioWorklet shipped.
+      assertAudioWorklet();
+
+      let audit = Audit.createTaskRunner();
+
+      let realtimeContext = new AudioContext();
+      let offlineContext = new OfflineAudioContext(1, 1, 44100);
+
+      // Test if AudioWorklet exists.
+      audit.define('Test if AudioWorklet exists', (task, should) => {
+        should(realtimeContext.audioWorklet instanceof AudioWorklet &&
+               offlineContext.audioWorklet instanceof AudioWorklet,
+               'BaseAudioContext.audioWorklet is an instance of AudioWorklet')
+            .beTrue();
+        task.done();
+      });
+
+      audit.run();
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/dynamic-channel-count.html b/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/dynamic-channel-count.html
index 64f95669..e196dfa 100644
--- a/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/dynamic-channel-count.html
+++ b/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/dynamic-channel-count.html
@@ -36,7 +36,7 @@
         context.channeCountMode = 'explicit';
         context.channelInterpretation = 'discrete';
 
-        audioWorklet.addModule('gain-processor.js').then(() => {
+        context.audioWorklet.addModule('gain-processor.js').then(() => {
           let testBuffer = createConstantBuffer(context, 1, testChannelValues);
           let sourceNode = new AudioBufferSourceNode(context);
           let gainWorkletNode = new AudioWorkletNode(context, 'gain');
diff --git a/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/message-port.html b/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/message-port.html
index 7d55dc82..aef39cc 100644
--- a/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/message-port.html
+++ b/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/message-port.html
@@ -60,7 +60,7 @@
             porterWorkletNode.port.postMessage('hello');
           });
 
-      audioWorklet.addModule('port-processor.js').then(() => {
+      context.audioWorklet.addModule('port-processor.js').then(() => {
         audit.run();
       });
     </script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/window-audio-worklet.html b/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/window-audio-worklet.html
deleted file mode 100644
index 5e390ed..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/window-audio-worklet.html
+++ /dev/null
@@ -1,46 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <title>
-      Checking window.audioWorklet
-    </title>
-    <script src="../../resources/testharness.js"></script>
-    <script src="../../resources/testharnessreport.js"></script>
-    <script src="../../../webaudio-resources/audit.js"></script>
-    <script src="audio-worklet-common.js"></script>
-  </head>
-  <body>
-    <script id="layout-test-code">
-      // TODO(hongchan): remove this assertion when AudioWorklet shipped.
-      assertAudioWorklet();
-
-      let audit = Audit.createTaskRunner();
-
-      // Test if AudioWorklet exists.
-      audit.define('Test if AudioWorklet exists', (task, should) => {
-        should(window.audioWorklet instanceof Worklet,
-               'window.audioWorklet is an instance of Worklet')
-            .beTrue();
-        task.done();
-      });
-
-      // Test the construction of BaseAudioContext before |worklet.addModule()|.
-      audit.define(
-          'Test invocation of addModule() after BaseAudioContext construction',
-          (task, should) => {
-            should(
-              () => {
-                let context = new AudioContext();
-                audioWorklet.addModule('bypass-processor.js');
-              },
-              'Calling audioWorklet.addModule() before construction of ' +
-                  'BaseAudioContext')
-              .notThrow();
-
-            task.done();
-          });
-
-      audit.run();
-    </script>
-  </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/worklet-context-interaction.html b/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/worklet-context-interaction.html
index a2dc5da..75428e6 100644
--- a/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/worklet-context-interaction.html
+++ b/third_party/WebKit/LayoutTests/http/tests/webaudio/audio-worklet/worklet-context-interaction.html
@@ -50,9 +50,12 @@
             task.done();
           });
 
-      audioWorklet.addModule('dummy-processor.js').then(() => {
-        audit.run();
-      });
+      Promise.all([
+          realtimeContext.audioWorklet.addModule('dummy-processor.js'),
+          offlineContext.audioWorklet.addModule('dummy-processor.js')
+        ]).then(() => {
+          audit.run();
+        });
     </script>
   </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/worklet/import-on-insecure-context.html b/third_party/WebKit/LayoutTests/http/tests/worklet/import-on-insecure-context.html
index 12ac80c..1832af6 100644
--- a/third_party/WebKit/LayoutTests/http/tests/worklet/import-on-insecure-context.html
+++ b/third_party/WebKit/LayoutTests/http/tests/worklet/import-on-insecure-context.html
@@ -7,14 +7,18 @@
 <script src="/resources/get-host-info.js"></script>
 <script>
 
-// This test should not be upstreamed to WPT because Worklets are now restrected
+// This test should not be upstreamed to WPT because Worklets are now restricted
 // to secure contexts by Chrome's policy.
 
+const realTimeContext = new AudioContext();
+const offlineContext = new OfflineAudioContext(1, 1, 44100);
+
 if (window.location.origin != get_host_info().UNAUTHENTICATED_ORIGIN) {
   test(t => {
     assert_not_equals(undefined, CSS.paintWorklet);
     assert_not_equals(undefined, window.animationWorklet);
-    assert_not_equals(undefined, window.audioWorklet);
+    assert_not_equals(undefined, realTimeContext.audioWorklet);
+    assert_not_equals(undefined, offlineContext.audioWorklet);
   }, 'Worklets should be available on a secure context.');
   window.location = get_host_info().UNAUTHENTICATED_ORIGIN +
                     window.location.pathname;
@@ -22,7 +26,8 @@
   test(t => {
     assert_equals(undefined, CSS.paintWorklet);
     assert_equals(undefined, window.animationWorklet);
-    assert_equals(undefined, window.audioWorklet);
+    assert_equals(undefined, realTimeContext.audioWorklet);
+    assert_equals(undefined, offlineContext.audioWorklet);
   }, 'Worklets should not be available on an insecure context.');
 }
 
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-filter-all-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-filter-all-expected.png
index 5953f52..555795d 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-filter-all-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-filter-all-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-layer-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-layer-expected.png
index 3202c248..a3f242f7 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-layer-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-layer-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-filter-all-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-filter-all-expected.png
index e548b7d..bcd3bd55 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-filter-all-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-filter-all-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/worklet-warnings.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/worklet-warnings.html
index 8778a1c..f8f1d60 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/worklet-warnings.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/worklet-warnings.html
@@ -20,36 +20,37 @@
             description: 'Generate warnings if outside nominal range'
           },
           (task, should) => {
-              window.audioWorklet.addModule(NoiseGenWorkletUrl).then(() => {
-                // Any reasonable sample rate will work
-                let sampleRate = 16000;
-                let renderTime = 1;
-                let renderLength = renderTime * sampleRate;
-                let context =
-                    new OfflineAudioContext(1, renderLength, sampleRate);
-                let noiseGenerator =
-                    new AudioWorkletNode(context, 'noise-generator');
-                noiseGenerator.connect(context.destination);
-                let param = noiseGenerator.parameters.get('amplitude');
-                // Set the value inside the nominal range; no warning should be
-                // generated.
-                param.value = .1;
-                // Set the value outside the nominal range to generate a
-                // warning.
-                param.value = 99;
+            // Any reasonable sample rate will work
+            let sampleRate = 16000;
+            let renderTime = 1;
+            let renderLength = renderTime * sampleRate;
+            let context =
+                new OfflineAudioContext(1, renderLength, sampleRate);
+            context.audioWorklet.addModule(NoiseGenWorkletUrl).then(() => {
+              let noiseGenerator =
+                  new AudioWorkletNode(context, 'noise-generator');
+              noiseGenerator.connect(context.destination);
+              let param = noiseGenerator.parameters.get('amplitude');
+              // Set the value inside the nominal range; no warning should be
+              // generated.
+              param.value = .1;
+              // Set the value outside the nominal range to generate a
+              // warning.
+              param.value = 99;
 
-                // Set up automation outside the nominal range to generate a
-                // warning.
-                param.setValueAtTime(-1, renderTime / 4);
-                param.linearRampToValueAtTime(5, renderTime);
+              // Set up automation outside the nominal range to generate a
+              // warning.
+              param.setValueAtTime(-1, renderTime / 4);
+              param.linearRampToValueAtTime(5, renderTime);
 
-                // Render; we don't care what the generated result is.
-                context.startRendering()
-                    .then(() => {
-                      should(true, 'Rendering succeeded').beTrue();
-                    })
-                    .then(() => task.done());
-              })});
+              // Render; we don't care what the generated result is.
+              context.startRendering()
+                  .then(() => {
+                    should(true, 'Rendering succeeded').beTrue();
+                  })
+                  .then(() => task.done());
+            });
+          });
 
       audit.run();
     </script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/resources/context-properties.js b/third_party/WebKit/LayoutTests/webaudio/resources/context-properties.js
index 931a19dd..4961bec9 100644
--- a/third_party/WebKit/LayoutTests/webaudio/resources/context-properties.js
+++ b/third_party/WebKit/LayoutTests/webaudio/resources/context-properties.js
@@ -7,6 +7,7 @@
 
 
 let BaseAudioContextOwnProperties = [
+  'audioWorklet',
   'constructor',
   'createAnalyser',
   'createBiquadFilter',
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 afe8278..a2b83059 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -402,6 +402,9 @@
     setter onaddtrack
     setter onchange
     setter onremovetrack
+interface AudioWorklet : Worklet
+    attribute @@toStringTag
+    method constructor
 interface AudioWorkletNode : AudioNode
     attribute @@toStringTag
     method constructor
@@ -451,6 +454,7 @@
     method detect
 interface BaseAudioContext : EventTarget
     attribute @@toStringTag
+    getter audioWorklet
     getter currentTime
     getter destination
     getter listener
@@ -9154,7 +9158,6 @@
     attribute window
     getter animationWorklet
     getter applicationCache
-    getter audioWorklet
     getter caches
     getter clientInformation
     getter cookieStore
diff --git a/third_party/WebKit/Source/core/css/cssom/FilteredComputedStylePropertyMap.cpp b/third_party/WebKit/Source/core/css/cssom/FilteredComputedStylePropertyMap.cpp
index 3a55305..272d87b 100644
--- a/third_party/WebKit/Source/core/css/cssom/FilteredComputedStylePropertyMap.cpp
+++ b/third_party/WebKit/Source/core/css/cssom/FilteredComputedStylePropertyMap.cpp
@@ -7,10 +7,9 @@
 namespace blink {
 
 FilteredComputedStylePropertyMap::FilteredComputedStylePropertyMap(
-    CSSComputedStyleDeclaration* computed_style_declaration,
+    Node* node,
     const Vector<CSSPropertyID>& native_properties,
-    const Vector<AtomicString>& custom_properties,
-    Node* node)
+    const Vector<AtomicString>& custom_properties)
     : ComputedStylePropertyMap(node) {
   for (const auto& native_property : native_properties) {
     native_properties_.insert(native_property);
diff --git a/third_party/WebKit/Source/core/css/cssom/FilteredComputedStylePropertyMap.h b/third_party/WebKit/Source/core/css/cssom/FilteredComputedStylePropertyMap.h
index 78ad45d..79cb4a70d 100644
--- a/third_party/WebKit/Source/core/css/cssom/FilteredComputedStylePropertyMap.h
+++ b/third_party/WebKit/Source/core/css/cssom/FilteredComputedStylePropertyMap.h
@@ -16,22 +16,20 @@
     : public ComputedStylePropertyMap {
  public:
   static FilteredComputedStylePropertyMap* Create(
-      CSSComputedStyleDeclaration* computed_style_declaration,
+      Node* node,
       const Vector<CSSPropertyID>& native_properties,
-      const Vector<AtomicString>& custom_properties,
-      Node* node) {
-    return new FilteredComputedStylePropertyMap(
-        computed_style_declaration, native_properties, custom_properties, node);
+      const Vector<AtomicString>& custom_properties) {
+    return new FilteredComputedStylePropertyMap(node, native_properties,
+                                                custom_properties);
   }
 
   Vector<String> getProperties() override;
 
  private:
   FilteredComputedStylePropertyMap(
-      CSSComputedStyleDeclaration*,
+      Node*,
       const Vector<CSSPropertyID>& native_properties,
-      const Vector<AtomicString>& custom_properties,
-      Node*);
+      const Vector<AtomicString>& custom_properties);
 
   const CSSValue* GetProperty(CSSPropertyID) override;
   const CSSValue* GetCustomProperty(AtomicString) override;
diff --git a/third_party/WebKit/Source/core/css/cssom/FilteredComputedStylePropertyMapTest.cpp b/third_party/WebKit/Source/core/css/cssom/FilteredComputedStylePropertyMapTest.cpp
index 2125df0..77c1273 100644
--- a/third_party/WebKit/Source/core/css/cssom/FilteredComputedStylePropertyMapTest.cpp
+++ b/third_party/WebKit/Source/core/css/cssom/FilteredComputedStylePropertyMapTest.cpp
@@ -38,20 +38,20 @@
   Vector<AtomicString> empty_custom_properties;
 
   FilteredComputedStylePropertyMap* map =
-      FilteredComputedStylePropertyMap::Create(Declaration(), native_properties,
-                                               custom_properties, PageNode());
+      FilteredComputedStylePropertyMap::Create(PageNode(), native_properties,
+                                               custom_properties);
   EXPECT_TRUE(map->getProperties().Contains("color"));
   EXPECT_TRUE(map->getProperties().Contains("align-items"));
   EXPECT_TRUE(map->getProperties().Contains("--foo"));
   EXPECT_TRUE(map->getProperties().Contains("--bar"));
 
-  map = FilteredComputedStylePropertyMap::Create(
-      Declaration(), native_properties, empty_custom_properties, PageNode());
+  map = FilteredComputedStylePropertyMap::Create(PageNode(), native_properties,
+                                                 empty_custom_properties);
   EXPECT_TRUE(map->getProperties().Contains("color"));
   EXPECT_TRUE(map->getProperties().Contains("align-items"));
 
   map = FilteredComputedStylePropertyMap::Create(
-      Declaration(), empty_native_properties, custom_properties, PageNode());
+      PageNode(), empty_native_properties, custom_properties);
   EXPECT_TRUE(map->getProperties().Contains("--foo"));
   EXPECT_TRUE(map->getProperties().Contains("--bar"));
 }
@@ -61,9 +61,8 @@
       {CSSPropertyColor, CSSPropertyAlignItems});
   Vector<AtomicString> empty_custom_properties;
   FilteredComputedStylePropertyMap* map =
-      FilteredComputedStylePropertyMap::Create(Declaration(), native_properties,
-                                               empty_custom_properties,
-                                               PageNode());
+      FilteredComputedStylePropertyMap::Create(PageNode(), native_properties,
+                                               empty_custom_properties);
 
   DummyExceptionStateForTesting exception_state;
 
@@ -93,9 +92,8 @@
   Vector<CSSPropertyID> empty_native_properties;
   Vector<AtomicString> custom_properties({"--foo", "--bar"});
   FilteredComputedStylePropertyMap* map =
-      FilteredComputedStylePropertyMap::Create(Declaration(),
-                                               empty_native_properties,
-                                               custom_properties, PageNode());
+      FilteredComputedStylePropertyMap::Create(
+          PageNode(), empty_native_properties, custom_properties);
 
   DummyExceptionStateForTesting exception_state;
 
diff --git a/third_party/WebKit/Source/modules/csspaint/CSSPaintDefinition.cpp b/third_party/WebKit/Source/modules/csspaint/CSSPaintDefinition.cpp
index 16adf4a..0512893 100644
--- a/third_party/WebKit/Source/modules/csspaint/CSSPaintDefinition.cpp
+++ b/third_party/WebKit/Source/modules/csspaint/CSSPaintDefinition.cpp
@@ -105,10 +105,9 @@
       context_settings_, zoom);
   PaintSize* paint_size = PaintSize::Create(specified_size);
   StylePropertyMapReadonly* style_map =
-      FilteredComputedStylePropertyMap::Create(
-          CSSComputedStyleDeclaration::Create(layout_object.GetNode()),
-          native_invalidation_properties_, custom_invalidation_properties_,
-          layout_object.GetNode());
+      FilteredComputedStylePropertyMap::Create(layout_object.GetNode(),
+                                               native_invalidation_properties_,
+                                               custom_invalidation_properties_);
 
   v8::Local<v8::Value> argv[] = {
       ToV8(rendering_context, script_state_->GetContext()->Global(), isolate),
diff --git a/third_party/WebKit/Source/modules/modules_idl_files.gni b/third_party/WebKit/Source/modules/modules_idl_files.gni
index bfa3a065..ad0eeac 100644
--- a/third_party/WebKit/Source/modules/modules_idl_files.gni
+++ b/third_party/WebKit/Source/modules/modules_idl_files.gni
@@ -329,6 +329,7 @@
           "webaudio/AudioParamMap.idl",
           "webaudio/AudioProcessingEvent.idl",
           "webaudio/AudioScheduledSourceNode.idl",
+          "webaudio/AudioWorklet.idl",
           "webaudio/AudioWorkletGlobalScope.idl",
           "webaudio/AudioWorkletProcessor.idl",
           "webaudio/AudioWorkletNode.idl",
@@ -722,7 +723,6 @@
           "vibration/NavigatorVibration.idl",
           "vr/NavigatorVR.idl",
           "wake_lock/ScreenWakeLock.idl",
-          "webaudio/WindowAudioWorklet.idl",
           "webdatabase/WindowWebDatabase.idl",
           "webgl/WebGL2RenderingContextBase.idl",
           "webgl/WebGLRenderingContextBase.idl",
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioWorklet.cpp b/third_party/WebKit/Source/modules/webaudio/AudioWorklet.cpp
index f2e4490..2760b3b 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioWorklet.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AudioWorklet.cpp
@@ -6,77 +6,90 @@
 
 #include "bindings/core/v8/V8BindingForCore.h"
 #include "core/dom/Document.h"
+#include "core/frame/LocalDOMWindow.h"
 #include "core/frame/LocalFrame.h"
 #include "core/workers/WorkerClients.h"
 #include "modules/webaudio/AudioWorkletMessagingProxy.h"
 #include "modules/webaudio/BaseAudioContext.h"
+#include "modules/webaudio/CrossThreadAudioWorkletProcessorInfo.h"
 
 namespace blink {
 
-AudioWorklet* AudioWorklet::Create(LocalFrame* frame) {
-  return new AudioWorklet(frame);
+AudioWorklet* AudioWorklet::Create(BaseAudioContext* context) {
+  return RuntimeEnabledFeatures::AudioWorkletEnabled()
+      ? new AudioWorklet(context)
+      : nullptr;
 }
 
-AudioWorklet::AudioWorklet(LocalFrame* frame) : Worklet(frame) {}
+AudioWorklet::AudioWorklet(BaseAudioContext* context)
+    : Worklet(context->GetExecutionContext()->ExecutingWindow()->GetFrame()),
+      context_(context) {}
 
-AudioWorklet::~AudioWorklet() {
-  contexts_.clear();
+void AudioWorklet::CreateProcessor(AudioWorkletHandler* handler,
+                                   MessagePortChannel message_port_channel) {
+  DCHECK(IsMainThread());
+  DCHECK(GetMessagingProxy());
+  GetMessagingProxy()->CreateProcessor(handler,
+                                       std::move(message_port_channel));
 }
 
-void AudioWorklet::RegisterContext(BaseAudioContext* context) {
-  DCHECK(!contexts_.Contains(context));
-  contexts_.insert(context);
+void AudioWorklet::NotifyGlobalScopeIsUpdated() {
+  DCHECK(IsMainThread());
 
-  // Check if AudioWorklet loads the script and has an active
-  // AudioWorkletGlobalScope before getting the messaging proxy.
-  if (IsWorkletMessagingProxyCreated())
-    context->SetWorkletMessagingProxy(FindAvailableMessagingProxy());
+  if (!worklet_started_) {
+    context_->NotifyWorkletIsReady();
+    worklet_started_ = true;
+  }
 }
 
-void AudioWorklet::UnregisterContext(BaseAudioContext* context) {
-  // This may be called multiple times from BaseAudioContext.
-  if (!contexts_.Contains(context))
-    return;
-
-  contexts_.erase(context);
+WebThread* AudioWorklet::GetBackingThread() {
+  DCHECK(IsMainThread());
+  DCHECK(GetMessagingProxy());
+  return GetMessagingProxy()->GetWorkletBackingThread();
 }
 
-AudioWorkletMessagingProxy* AudioWorklet::FindAvailableMessagingProxy() {
-  return static_cast<AudioWorkletMessagingProxy*>(FindAvailableGlobalScope());
+const Vector<CrossThreadAudioParamInfo>
+    AudioWorklet::GetParamInfoListForProcessor(
+    const String& name) {
+  DCHECK(IsMainThread());
+  DCHECK(GetMessagingProxy());
+  return GetMessagingProxy()->GetParamInfoListForProcessor(name);
 }
 
-bool AudioWorklet::IsWorkletMessagingProxyCreated() const {
-  return GetNumberOfGlobalScopes() > 0;
+bool AudioWorklet::IsProcessorRegistered(const String& name) {
+  DCHECK(IsMainThread());
+  DCHECK(GetMessagingProxy());
+  return GetMessagingProxy()->IsProcessorRegistered(name);
+}
+
+bool AudioWorklet::IsReady() {
+  DCHECK(IsMainThread());
+  return GetMessagingProxy() && GetBackingThread();
 }
 
 bool AudioWorklet::NeedsToCreateGlobalScope() {
-  // TODO(hongchan): support multiple WorkletGlobalScopes, one scope per a
-  // BaseAudioContext. In order to do it, FindAvailableGlobalScope() needs to
-  // be inherited and rewritten.
   return GetNumberOfGlobalScopes() == 0;
 }
 
 WorkletGlobalScopeProxy* AudioWorklet::CreateGlobalScope() {
   DCHECK(NeedsToCreateGlobalScope());
 
-  WorkerClients* worker_clients = WorkerClients::Create();
   AudioWorkletMessagingProxy* proxy =
-      new AudioWorkletMessagingProxy(GetExecutionContext(), worker_clients);
+      new AudioWorkletMessagingProxy(GetExecutionContext(),
+                                     WorkerClients::Create(),
+                                     this);
   proxy->Initialize();
-
-  for (BaseAudioContext* context : contexts_) {
-    // TODO(hongchan): Currently all BaseAudioContexts shares a single
-    // AudioWorkletMessagingProxy. Fix this to support one messaging proxy for
-    // each BaseAudioContext.
-    if (!context->HasWorkletMessagingProxy())
-      context->SetWorkletMessagingProxy(proxy);
-  }
-
   return proxy;
 }
 
+AudioWorkletMessagingProxy* AudioWorklet::GetMessagingProxy() {
+  return NeedsToCreateGlobalScope()
+      ? nullptr
+      : static_cast<AudioWorkletMessagingProxy*>(FindAvailableGlobalScope());
+}
+
 void AudioWorklet::Trace(blink::Visitor* visitor) {
-  visitor->Trace(contexts_);
+  visitor->Trace(context_);
   Worklet::Trace(visitor);
 }
 
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioWorklet.h b/third_party/WebKit/Source/modules/webaudio/AudioWorklet.h
index 3cde775..27c1ce4 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioWorklet.h
+++ b/third_party/WebKit/Source/modules/webaudio/AudioWorklet.h
@@ -11,36 +11,59 @@
 
 namespace blink {
 
+class AudioWorkletHandler;
 class AudioWorkletMessagingProxy;
 class BaseAudioContext;
-class LocalFrame;
+class CrossThreadAudioParamInfo;
+class MessagePortChannel;
 
 class MODULES_EXPORT AudioWorklet final : public Worklet {
+  DEFINE_WRAPPERTYPEINFO();
+  USING_GARBAGE_COLLECTED_MIXIN(AudioWorklet);
   WTF_MAKE_NONCOPYABLE(AudioWorklet);
 
  public:
-  static AudioWorklet* Create(LocalFrame*);
-  ~AudioWorklet() override;
+  // When the AudioWorklet runtime flag is not enabled, this constructor returns
+  // |nullptr|.
+  static AudioWorklet* Create(BaseAudioContext*);
 
-  void RegisterContext(BaseAudioContext*);
-  void UnregisterContext(BaseAudioContext*);
+  ~AudioWorklet() = default;
 
-  AudioWorkletMessagingProxy* FindAvailableMessagingProxy();
+  void CreateProcessor(AudioWorkletHandler*, MessagePortChannel);
 
-  virtual void Trace(blink::Visitor*);
+  // Invoked by AudioWorkletMessagingProxy. Notifies |context_| when
+  // AudioWorkletGlobalScope finishes the first script evaluation and is ready
+  // for the worklet operation. Can be used for other post-evaluation tasks
+  // in AudioWorklet or BaseAudioContext.
+  void NotifyGlobalScopeIsUpdated();
+
+  WebThread* GetBackingThread();
+
+  const Vector<CrossThreadAudioParamInfo> GetParamInfoListForProcessor(
+      const String& name);
+
+  bool IsProcessorRegistered(const String& name);
+
+  // Returns |true| when a AudioWorkletMessagingProxy and a WorkletBackingThread
+  // are ready.
+  bool IsReady();
+
+  void Trace(blink::Visitor*) override;
 
  private:
-  explicit AudioWorklet(LocalFrame*);
+  explicit AudioWorklet(BaseAudioContext*);
 
-  // Implements Worklet.
+  // Implements Worklet
   bool NeedsToCreateGlobalScope() final;
   WorkletGlobalScopeProxy* CreateGlobalScope() final;
 
-  bool IsWorkletMessagingProxyCreated() const;
+  // Returns |nullptr| if there is no active WorkletGlobalScope().
+  AudioWorkletMessagingProxy* GetMessagingProxy();
 
-  // AudioWorklet keeps the reference of all active BaseAudioContexts, so it
-  // can notify the contexts when a script is loaded in AudioWorkletGlobalScope.
-  HeapHashSet<Member<BaseAudioContext>> contexts_;
+  // To catch the first global scope update and notify the context.
+  bool worklet_started_ = false;
+
+  Member<BaseAudioContext> context_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/webaudio/WindowAudioWorklet.idl b/third_party/WebKit/Source/modules/webaudio/AudioWorklet.idl
similarity index 71%
rename from third_party/WebKit/Source/modules/webaudio/WindowAudioWorklet.idl
rename to third_party/WebKit/Source/modules/webaudio/AudioWorklet.idl
index da5d51c..2b42eba8 100644
--- a/third_party/WebKit/Source/modules/webaudio/WindowAudioWorklet.idl
+++ b/third_party/WebKit/Source/modules/webaudio/AudioWorklet.idl
@@ -5,9 +5,7 @@
 // https://webaudio.github.io/web-audio-api/#AudioWorklet
 
 [
-    ImplementedAs=WindowAudioWorklet,
     RuntimeEnabled=AudioWorklet,
     SecureContext
-] partial interface Window {
-    readonly attribute Worklet audioWorklet;
+] interface AudioWorklet : Worklet {
 };
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioWorkletMessagingProxy.cpp b/third_party/WebKit/Source/modules/webaudio/AudioWorkletMessagingProxy.cpp
index e11192a..e1e85d8 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioWorkletMessagingProxy.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AudioWorkletMessagingProxy.cpp
@@ -5,6 +5,7 @@
 #include "modules/webaudio/AudioWorkletMessagingProxy.h"
 
 #include "core/dom/MessagePort.h"
+#include "modules/webaudio/AudioWorklet.h"
 #include "modules/webaudio/AudioWorkletGlobalScope.h"
 #include "modules/webaudio/AudioWorkletNode.h"
 #include "modules/webaudio/AudioWorkletObjectProxy.h"
@@ -17,10 +18,10 @@
 
 AudioWorkletMessagingProxy::AudioWorkletMessagingProxy(
     ExecutionContext* execution_context,
-    WorkerClients* worker_clients)
-    : ThreadedWorkletMessagingProxy(execution_context, worker_clients) {}
-
-AudioWorkletMessagingProxy::~AudioWorkletMessagingProxy() {}
+    WorkerClients* worker_clients,
+    AudioWorklet* worklet)
+    : ThreadedWorkletMessagingProxy(execution_context, worker_clients),
+      worklet_(worklet) {}
 
 void AudioWorkletMessagingProxy::CreateProcessor(
     AudioWorkletHandler* handler,
@@ -61,6 +62,10 @@
     processor_info_map_.insert(processor_info.Name(),
                                processor_info.ParamInfoList());
   }
+
+  // Notify AudioWorklet object that the global scope has been updated after the
+  // script evaluation.
+  worklet_->NotifyGlobalScopeIsUpdated();
 }
 
 bool AudioWorkletMessagingProxy::IsProcessorRegistered(
@@ -94,4 +99,10 @@
                                     WorkletObjectProxy());
 }
 
+void AudioWorkletMessagingProxy::Trace(Visitor* visitor) {
+  visitor->Trace(worklet_);
+  ThreadedWorkletMessagingProxy::Trace(visitor);
+}
+
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioWorkletMessagingProxy.h b/third_party/WebKit/Source/modules/webaudio/AudioWorkletMessagingProxy.h
index 3cc504a..f7eb17a 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioWorkletMessagingProxy.h
+++ b/third_party/WebKit/Source/modules/webaudio/AudioWorkletMessagingProxy.h
@@ -10,6 +10,7 @@
 
 namespace blink {
 
+class AudioWorklet;
 class AudioWorkletHandler;
 class CrossThreadAudioParamInfo;
 class CrossThreadAudioWorkletProcessorInfo;
@@ -23,7 +24,7 @@
 // scope via AudioWorkletObjectProxy.
 class AudioWorkletMessagingProxy final : public ThreadedWorkletMessagingProxy {
  public:
-  AudioWorkletMessagingProxy(ExecutionContext*, WorkerClients*);
+  AudioWorkletMessagingProxy(ExecutionContext*, WorkerClients*, AudioWorklet*);
 
   // Since the creation of AudioWorkletProcessor needs to be done in the
   // different thread, this method is a wrapper for cross-thread task posting.
@@ -54,9 +55,9 @@
 
   WebThread* GetWorkletBackingThread();
 
- private:
-  ~AudioWorkletMessagingProxy() override;
+  void Trace(Visitor*);
 
+ private:
   // Implements ThreadedWorkletMessagingProxy.
   std::unique_ptr<ThreadedWorkletObjectProxy> CreateObjectProxy(
       ThreadedWorkletMessagingProxy*,
@@ -66,6 +67,8 @@
 
   // Each entry consists of processor name and associated AudioParam list.
   HashMap<String, Vector<CrossThreadAudioParamInfo>> processor_info_map_;
+
+  Member<AudioWorklet> worklet_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioWorkletNode.cpp b/third_party/WebKit/Source/modules/webaudio/AudioWorkletNode.cpp
index 09f4e37..9ac2c0ff 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioWorkletNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AudioWorkletNode.cpp
@@ -11,8 +11,7 @@
 #include "modules/webaudio/AudioNodeInput.h"
 #include "modules/webaudio/AudioNodeOutput.h"
 #include "modules/webaudio/AudioParamDescriptor.h"
-#include "modules/webaudio/AudioWorkletGlobalScope.h"
-#include "modules/webaudio/AudioWorkletMessagingProxy.h"
+#include "modules/webaudio/AudioWorklet.h"
 #include "modules/webaudio/AudioWorkletProcessor.h"
 #include "modules/webaudio/AudioWorkletProcessorDefinition.h"
 #include "modules/webaudio/CrossThreadAudioWorkletProcessorInfo.h"
@@ -277,7 +276,7 @@
     }
   }
 
-  if (!context->HasWorkletMessagingProxy()) {
+  if (!context->audioWorklet()->IsReady()) {
     exception_state.ThrowDOMException(
         kInvalidStateError,
         "AudioWorkletNode cannot be created: AudioWorklet does not have a "
@@ -286,9 +285,7 @@
     return nullptr;
   }
 
-  AudioWorkletMessagingProxy* proxy = context->WorkletMessagingProxy();
-
-  if (!proxy->IsProcessorRegistered(name)) {
+  if (!context->audioWorklet()->IsProcessorRegistered(name)) {
     exception_state.ThrowDOMException(
         kInvalidStateError,
         "AudioWorkletNode cannot be created: The node name '" + name +
@@ -302,8 +299,8 @@
 
   AudioWorkletNode* node =
       new AudioWorkletNode(*context, name, options,
-                           proxy->GetParamInfoListForProcessor(name),
-                           channel->port1());
+          context->audioWorklet()->GetParamInfoListForProcessor(name),
+          channel->port1());
 
   if (!node) {
     exception_state.ThrowDOMException(
@@ -319,8 +316,8 @@
 
   // This is non-blocking async call. |node| still can be returned to user
   // before the scheduled async task is completed.
-  proxy->CreateProcessor(&node->GetWorkletHandler(),
-                         std::move(processor_port_channel));
+  context->audioWorklet()->CreateProcessor(&node->GetWorkletHandler(),
+                                           std::move(processor_port_channel));
 
   return node;
 }
diff --git a/third_party/WebKit/Source/modules/webaudio/BUILD.gn b/third_party/WebKit/Source/modules/webaudio/BUILD.gn
index e4824fd..ee8d3e8 100644
--- a/third_party/WebKit/Source/modules/webaudio/BUILD.gn
+++ b/third_party/WebKit/Source/modules/webaudio/BUILD.gn
@@ -125,19 +125,9 @@
     "WaveShaperNode.h",
     "WaveShaperProcessor.cpp",
     "WaveShaperProcessor.h",
-    "WindowAudioWorklet.cpp",
-    "WindowAudioWorklet.h",
   ]
 
   if (is_win) {
-    jumbo_excluded_sources = [
-      # Uses Supplement<LocalDOMWindow> with MODULES_EXPORT while
-      # other files use Supplement<LocalDOMWindow> with
-      # CORE_EXPORT. Mixing those in the same compilation unit
-      # triggers link errors in Windows. https://crbug.com/739340
-      "WindowAudioWorklet.cpp",
-    ]
-
     # Result of 32-bit shift implicitly converted to 64 bits.
     cflags = [ "/wd4334" ]
   }
diff --git a/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp b/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp
index 721247f..a2621ef4 100644
--- a/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp
@@ -71,7 +71,6 @@
 #include "modules/webaudio/ScriptProcessorNode.h"
 #include "modules/webaudio/StereoPannerNode.h"
 #include "modules/webaudio/WaveShaperNode.h"
-#include "modules/webaudio/WindowAudioWorklet.h"
 #include "platform/CrossThreadFunctional.h"
 #include "platform/Histogram.h"
 #include "platform/audio/IIRFilter.h"
@@ -137,9 +136,6 @@
 
 BaseAudioContext::~BaseAudioContext() {
   GetDeferredTaskHandler().ContextWillBeDestroyed();
-  // AudioNodes keep a reference to their context, so there should be no way to
-  // be in the destructor if there are still AudioNodes around.
-  DCHECK(!IsDestinationInitialized());
   DCHECK(!active_source_nodes_.size());
   DCHECK(!is_resolving_resume_promises_);
   DCHECK(!resume_resolvers_.size());
@@ -152,21 +148,16 @@
 
   FFTFrame::Initialize();
 
+  if (RuntimeEnabledFeatures::AudioWorkletEnabled()) {
+    audio_worklet_ = AudioWorklet::Create(this);
+  }
+
   if (destination_node_) {
     destination_node_->Handler().Initialize();
     // The AudioParams in the listener need access to the destination node, so
     // only create the listener if the destination node exists.
     listener_ = AudioListener::Create(*this);
   }
-
-  // Check if a document or a frame supports AudioWorklet. If not, AudioWorklet
-  // cannot be accessed.
-  if (RuntimeEnabledFeatures::AudioWorkletEnabled()) {
-    AudioWorklet* audioWorklet = WindowAudioWorklet::audioWorklet(
-        *GetExecutionContext()->ExecutingWindow());
-    if (audioWorklet)
-      audioWorklet->RegisterContext(this);
-  }
 }
 
 void BaseAudioContext::Clear() {
@@ -180,17 +171,6 @@
 void BaseAudioContext::Uninitialize() {
   DCHECK(IsMainThread());
 
-  // AudioWorklet may be destroyed before the context goes away. So we have to
-  // check the pointer. See: crbug.com/503845
-  if (RuntimeEnabledFeatures::AudioWorkletEnabled()) {
-    AudioWorklet* audioWorklet = WindowAudioWorklet::audioWorklet(
-        *GetExecutionContext()->ExecutingWindow());
-    if (audioWorklet) {
-      audioWorklet->UnregisterContext(this);
-      worklet_messaging_proxy_.Clear();
-    }
-  }
-
   if (!IsDestinationInitialized())
     return;
 
@@ -1012,7 +992,7 @@
   visitor->Trace(periodic_wave_square_);
   visitor->Trace(periodic_wave_sawtooth_);
   visitor->Trace(periodic_wave_triangle_);
-  visitor->Trace(worklet_messaging_proxy_);
+  visitor->Trace(audio_worklet_);
   EventTargetWithInlineData::Trace(visitor);
   PausableObject::Trace(visitor);
 }
@@ -1038,15 +1018,12 @@
   return nullptr;
 }
 
-bool BaseAudioContext::HasWorkletMessagingProxy() const {
-  return has_worklet_messaging_proxy_;
+AudioWorklet* BaseAudioContext::audioWorklet() const {
+  return audio_worklet_.Get();
 }
 
-void BaseAudioContext::SetWorkletMessagingProxy(
-    AudioWorkletMessagingProxy* proxy) {
-  DCHECK(!worklet_messaging_proxy_);
-  worklet_messaging_proxy_ = proxy;
-  has_worklet_messaging_proxy_ = true;
+void BaseAudioContext::NotifyWorkletIsReady() {
+  DCHECK(audioWorklet()->IsReady());
 
   // If the context is running or suspended, restart the destination to switch
   // the render thread with the worklet thread. Note that restarting can happen
@@ -1056,9 +1033,4 @@
   }
 }
 
-AudioWorkletMessagingProxy* BaseAudioContext::WorkletMessagingProxy() {
-  DCHECK(worklet_messaging_proxy_);
-  return worklet_messaging_proxy_;
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.h b/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.h
index 53f7434..0c1f4c3d 100644
--- a/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.h
+++ b/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.h
@@ -55,7 +55,7 @@
 class AudioBufferSourceNode;
 class AudioContextOptions;
 class AudioListener;
-class AudioWorkletMessagingProxy;
+class AudioWorklet;
 class BiquadFilterNode;
 class ChannelMergerNode;
 class ChannelSplitterNode;
@@ -334,9 +334,13 @@
   // gesture while the AudioContext requires a user gesture.
   void MaybeRecordStartAttempt();
 
-  void SetWorkletMessagingProxy(AudioWorkletMessagingProxy*);
-  AudioWorkletMessagingProxy* WorkletMessagingProxy();
-  bool HasWorkletMessagingProxy() const;
+  // AudioWorklet IDL
+  AudioWorklet* audioWorklet() const;
+
+  // Callback from AudioWorklet, invoked when the associated
+  // AudioWorkletGlobalScope is created and the worklet operation is ready after
+  // the first script evaluation.
+  void NotifyWorkletIsReady();
 
   // TODO(crbug.com/764396): Remove this when fixed.
   virtual void CountValueSetterConflict(bool does_conflict){};
@@ -518,8 +522,7 @@
   Optional<AutoplayStatus> autoplay_status_;
   AudioIOPosition output_position_;
 
-  bool has_worklet_messaging_proxy_ = false;
-  Member<AudioWorkletMessagingProxy> worklet_messaging_proxy_;
+  Member<AudioWorklet> audio_worklet_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.idl b/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.idl
index 6e18c353..82a1cce 100644
--- a/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.idl
+++ b/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.idl
@@ -68,5 +68,7 @@
     [RaisesException, MeasureAs=AudioContextCreateMediaStreamSource] MediaStreamAudioSourceNode createMediaStreamSource(MediaStream mediaStream);
     [RaisesException, MeasureAs=AudioContextCreateMediaStreamDestination] MediaStreamAudioDestinationNode createMediaStreamDestination();
 
+    [RuntimeEnabled=AudioWorklet, SecureContext] readonly attribute AudioWorklet audioWorklet;
+
     attribute EventHandler onstatechange;
 };
diff --git a/third_party/WebKit/Source/modules/webaudio/DefaultAudioDestinationNode.cpp b/third_party/WebKit/Source/modules/webaudio/DefaultAudioDestinationNode.cpp
index adc5fd43..f612cf1 100644
--- a/third_party/WebKit/Source/modules/webaudio/DefaultAudioDestinationNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/DefaultAudioDestinationNode.cpp
@@ -28,8 +28,8 @@
 #include "bindings/core/v8/ExceptionMessages.h"
 #include "bindings/core/v8/ExceptionState.h"
 #include "core/dom/ExceptionCode.h"
+#include "modules/webaudio/AudioWorklet.h"
 #include "modules/webaudio/BaseAudioContext.h"
-#include "modules/webaudio/AudioWorkletMessagingProxy.h"
 
 namespace blink {
 
@@ -89,13 +89,12 @@
 
 void DefaultAudioDestinationHandler::StartDestination() {
   DCHECK(!destination_->IsPlaying());
-  // Use Experimental AudioWorkletThread only when AudioWorklet is enabled and
-  // there is an active AudioWorkletGlobalScope.
-  if (RuntimeEnabledFeatures::AudioWorkletEnabled() &&
-      Context()->HasWorkletMessagingProxy()) {
-    DCHECK(Context()->WorkletMessagingProxy()->GetWorkletBackingThread());
+
+  // Use Experimental AudioWorkletThread only when AudioWorklet is enabled, and
+  // the worklet thread and the global scope are ready.
+  if (Context()->audioWorklet() && Context()->audioWorklet()->IsReady()) {
     destination_->StartWithWorkletThread(
-        Context()->WorkletMessagingProxy()->GetWorkletBackingThread());
+        Context()->audioWorklet()->GetBackingThread());
   } else {
     destination_->Start();
   }
diff --git a/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.cpp b/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.cpp
index f680aa3d..4fe1b5f 100644
--- a/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.cpp
@@ -28,8 +28,7 @@
 #include <algorithm>
 #include "modules/webaudio/AudioNodeInput.h"
 #include "modules/webaudio/AudioNodeOutput.h"
-#include "modules/webaudio/AudioWorkletMessagingProxy.h"
-#include "modules/webaudio/AudioWorkletThread.h"
+#include "modules/webaudio/AudioWorklet.h"
 #include "modules/webaudio/BaseAudioContext.h"
 #include "modules/webaudio/OfflineAudioContext.h"
 #include "platform/CrossThreadFunctional.h"
@@ -146,13 +145,10 @@
     AudioBuffer* render_target) {
   DCHECK(IsMainThread());
 
-  // Use Experimental AudioWorkletThread only when AudioWorklet is enabled and
-  // there is an active AudioWorkletGlobalScope.
-  if (RuntimeEnabledFeatures::AudioWorkletEnabled() &&
-      Context()->HasWorkletMessagingProxy()) {
-    DCHECK(Context()->WorkletMessagingProxy()->GetWorkletBackingThread());
-    worklet_backing_thread_ =
-        Context()->WorkletMessagingProxy()->GetWorkletBackingThread();
+  // Use Experimental AudioWorkletThread only when AudioWorklet is enabled, and
+  // the worklet thread and the global scope are ready.
+  if (Context()->audioWorklet() && Context()->audioWorklet()->IsReady()) {
+    worklet_backing_thread_ = Context()->audioWorklet()->GetBackingThread();
   } else {
     render_thread_ =
         Platform::Current()->CreateThread("offline audio renderer");
@@ -365,10 +361,9 @@
 WebThread* OfflineAudioDestinationHandler::GetRenderingThread() {
   DCHECK(IsInitialized());
 
-  // Use Experimental AudioWorkletThread only when AudioWorklet is enabled and
-  // there is an active AudioWorkletGlobalScope.
-  if (RuntimeEnabledFeatures::AudioWorkletEnabled() &&
-      Context()->HasWorkletMessagingProxy()) {
+  // Use Experimental AudioWorkletThread only when AudioWorklet is enabled, and
+  // the worklet thread and the global scope are ready.
+  if (Context()->audioWorklet() && Context()->audioWorklet()->IsReady()) {
     DCHECK(!render_thread_ && worklet_backing_thread_);
     return worklet_backing_thread_;
   }
@@ -381,12 +376,9 @@
   // If the worklet thread is not assigned yet, that means the context has
   // started without a valid WorkletGlobalScope. Assign the worklet thread,
   // and it will be picked up when the GetRenderingThread() is called next.
-  if (RuntimeEnabledFeatures::AudioWorkletEnabled() &&
-      Context()->HasWorkletMessagingProxy() &&
+  if (Context()->audioWorklet() && Context()->audioWorklet()->IsReady() &&
       !worklet_backing_thread_) {
-    DCHECK(Context()->WorkletMessagingProxy()->GetWorkletBackingThread());
-    worklet_backing_thread_ =
-        Context()->WorkletMessagingProxy()->GetWorkletBackingThread();
+    worklet_backing_thread_ = Context()->audioWorklet()->GetBackingThread();
   }
 };
 
diff --git a/third_party/WebKit/Source/modules/webaudio/WindowAudioWorklet.cpp b/third_party/WebKit/Source/modules/webaudio/WindowAudioWorklet.cpp
deleted file mode 100644
index 630331b..0000000
--- a/third_party/WebKit/Source/modules/webaudio/WindowAudioWorklet.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2016 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 "modules/webaudio/WindowAudioWorklet.h"
-
-#include "core/dom/Document.h"
-#include "core/frame/LocalDOMWindow.h"
-#include "core/frame/LocalFrame.h"
-
-namespace blink {
-
-AudioWorklet* WindowAudioWorklet::audioWorklet(LocalDOMWindow& window) {
-  if (!window.GetFrame())
-    return nullptr;
-  return From(window).audio_worklet_.Get();
-}
-
-// Break the following cycle when the context gets detached.
-// Otherwise, the worklet object will leak.
-//
-// window => window.audioWorklet
-// => WindowAudioWorklet
-// => AudioWorklet  <--- break this reference
-// => ThreadedWorkletMessagingProxy
-// => Document
-// => ... => window
-void WindowAudioWorklet::ContextDestroyed(ExecutionContext*) {
-  audio_worklet_ = nullptr;
-}
-
-void WindowAudioWorklet::Trace(blink::Visitor* visitor) {
-  visitor->Trace(audio_worklet_);
-  Supplement<LocalDOMWindow>::Trace(visitor);
-  ContextLifecycleObserver::Trace(visitor);
-}
-
-WindowAudioWorklet& WindowAudioWorklet::From(LocalDOMWindow& window) {
-  WindowAudioWorklet* supplement = static_cast<WindowAudioWorklet*>(
-      Supplement<LocalDOMWindow>::From(window, SupplementName()));
-  if (!supplement) {
-    supplement = new WindowAudioWorklet(window);
-    ProvideTo(window, SupplementName(), supplement);
-  }
-  return *supplement;
-}
-
-WindowAudioWorklet::WindowAudioWorklet(LocalDOMWindow& window)
-    : ContextLifecycleObserver(window.GetFrame()->GetDocument()),
-      audio_worklet_(AudioWorklet::Create(window.GetFrame())) {
-  DCHECK(GetExecutionContext());
-}
-
-const char* WindowAudioWorklet::SupplementName() {
-  return "WindowAudioWorklet";
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/modules/webaudio/WindowAudioWorklet.h b/third_party/WebKit/Source/modules/webaudio/WindowAudioWorklet.h
deleted file mode 100644
index 55e7903c..0000000
--- a/third_party/WebKit/Source/modules/webaudio/WindowAudioWorklet.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2016 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 WindowAudioWorklet_h
-#define WindowAudioWorklet_h
-
-#include "core/dom/ContextLifecycleObserver.h"
-#include "modules/ModulesExport.h"
-#include "modules/webaudio/AudioWorklet.h"
-#include "platform/Supplementable.h"
-#include "platform/heap/Handle.h"
-
-namespace blink {
-
-class LocalDOMWindow;
-
-class MODULES_EXPORT WindowAudioWorklet final
-    : public GarbageCollected<WindowAudioWorklet>,
-      public Supplement<LocalDOMWindow>,
-      public ContextLifecycleObserver {
-  USING_GARBAGE_COLLECTED_MIXIN(WindowAudioWorklet);
-
- public:
-  static AudioWorklet* audioWorklet(LocalDOMWindow&);
-
-  void ContextDestroyed(ExecutionContext*) override;
-
-  void Trace(blink::Visitor*);
-
- private:
-  static WindowAudioWorklet& From(LocalDOMWindow&);
-
-  explicit WindowAudioWorklet(LocalDOMWindow&);
-  static const char* SupplementName();
-
-  Member<AudioWorklet> audio_worklet_;
-};
-
-}  // namespace blink
-
-#endif  // WindowAudioWorklet_h
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/cpu_time_budget_pool.cc b/third_party/WebKit/Source/platform/scheduler/renderer/cpu_time_budget_pool.cc
index 7f6b2040..13c0943 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/cpu_time_budget_pool.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/cpu_time_budget_pool.cc
@@ -14,23 +14,16 @@
 namespace blink {
 namespace scheduler {
 
-namespace {
-
-double TimeDeltaToMilliseconds(const base::TimeDelta& value) {
-  return value.InMillisecondsF();
-}
-
-}  // namespace
-
 CPUTimeBudgetPool::CPUTimeBudgetPool(
     const char* name,
     BudgetPoolController* budget_pool_controller,
     base::TimeTicks now)
     : BudgetPool(name, budget_pool_controller),
-      current_budget_level_(base::TimeDelta(),
-                            "RendererScheduler.BackgroundBudgetMs",
-                            budget_pool_controller,
-                            TimeDeltaToMilliseconds),
+      current_budget_level_(
+          base::TimeDelta(),
+          "RendererScheduler.BackgroundBudgetMs",
+          budget_pool_controller,
+          [](const base::TimeDelta& value) { return value.InMillisecondsF(); }),
       last_checkpoint_(now),
       cpu_percentage_(1) {}
 
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 565a6be..aac34fb 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -9035,6 +9035,20 @@
   </summary>
 </histogram>
 
+<histogram name="Chrome.ProcessSingleton.ProcessTerminateErrorCode.Windows"
+    enum="WinGetLastError">
+  <obsolete>
+    Deprecated as of 12/2017.
+  </obsolete>
+  <owner>aseren@yandex-team.ru</owner>
+  <owner>gab@chromium.org</owner>
+  <summary>
+    The error code of remote process termination on Windows in case when remote
+    process hung. This histogram has been replaced by
+    Chrome.ProcessSingleton.TerminateProcessErrorCode.Windows histogram.
+  </summary>
+</histogram>
+
 <histogram name="Chrome.ProcessSingleton.RemoteHungProcessTerminateReason"
     enum="RemoteHungProcessTerminateReason">
   <owner>aseren@yandex-team.ru</owner>
@@ -12940,6 +12954,15 @@
   </summary>
 </histogram>
 
+<histogram name="DataReductionProxy.NetworkProperties.CacheHit"
+    units="BooleanCacheHit">
+  <owner>tbansal@chromium.org</owner>
+  <summary>
+    Records if the network properties of a network were found in the cache or
+    not. Recorded every time there is a change in the connection type.
+  </summary>
+</histogram>
+
 <histogram name="DataReductionProxy.Pingback.Attempted" enum="BooleanAttempted">
   <owner>bengr@chromium.org</owner>
   <owner>ryansturm@chromium.org</owner>
@@ -93008,7 +93031,31 @@
   </summary>
 </histogram>
 
-<histogram name="VR.AssetsComponent.LoadStatus" enum="VRAssetsLoadStatus">
+<histogram name="VR.Component.Assets.DurationUntilReady.OnChromeStart"
+    units="ms">
+  <owner>tiborg@chromium.org</owner>
+  <summary>
+    Duration from starting Chrome until VR assets component is ready to use.
+  </summary>
+</histogram>
+
+<histogram base="true" name="VR.Component.Assets.DurationUntilReady.OnEnter"
+    units="ms">
+  <owner>tiborg@chromium.org</owner>
+  <summary>
+    Duration from entering a VR mode until the VR assets component is ready to
+    use.
+  </summary>
+</histogram>
+
+<histogram base="true" name="VR.Component.Assets.Status.OnEnter"
+    enum="VRAssetsComponentEnterStatus">
+  <owner>tiborg@chromium.org</owner>
+  <summary>Status of the VR assets component when entering a VR mode.</summary>
+</histogram>
+
+<histogram name="VR.Component.Assets.VersionAndStatus.OnLoad"
+    enum="VRAssetsLoadStatus">
   <owner>tiborg@chromium.org</owner>
   <summary>
     The component version and status of loading the VR assets. The value is
@@ -93018,21 +93065,7 @@
   </summary>
 </histogram>
 
-<histogram base="true" name="VR.AssetsComponent.ReadyLatency.OnEnter"
-    units="ms">
-  <owner>tiborg@chromium.org</owner>
-  <summary>
-    Duration from entering a VR mode until VR assets component is ready to use.
-  </summary>
-</histogram>
-
-<histogram base="true" name="VR.AssetsComponent.Status.OnEnter"
-    enum="VRAssetsComponentEnterStatus">
-  <owner>tiborg@chromium.org</owner>
-  <summary>Status of the VR assets component when entering a VR mode.</summary>
-</histogram>
-
-<histogram name="VR.AssetsComponent.UpdateStatus"
+<histogram name="VR.Component.Assets.VersionAndStatus.OnUpdate"
     enum="VRAssetsComponentUpdateStatus">
   <owner>tiborg@chromium.org</owner>
   <summary>
@@ -93044,16 +93077,18 @@
   </summary>
 </histogram>
 
-<histogram base="true" name="VR.DataConnection.OnEnter"
+<histogram base="true" name="VR.NetworkConnectionType.OnEnter"
     enum="NetworkConnectionType">
   <owner>tiborg@chromium.org</owner>
-  <summary>Data connection when entering a VR mode.</summary>
+  <summary>Network connection type when entering a VR mode.</summary>
 </histogram>
 
-<histogram name="VR.DataConnection.OnRegisterAssetsComponent"
+<histogram name="VR.NetworkConnectionType.OnRegisterComponent"
     enum="NetworkConnectionType">
   <owner>tiborg@chromium.org</owner>
-  <summary>Data connection when registering the VR assets component.</summary>
+  <summary>
+    Network connection type when registering the VR component(s).
+  </summary>
 </histogram>
 
 <histogram name="VR.Session.VoiceSearch.StartedCount" units="searches">
@@ -109179,13 +109214,13 @@
 </histogram_suffixes>
 
 <histogram_suffixes name="VR.Mode" separator=".">
-  <affected-histogram name="VR.AssetsComponent.ReadyLatency.OnEnter"/>
-  <suffix name="VR" label="Entered either VR Browsing or WebVR mode."/>
+  <suffix name="AllVR" label="Entered either VR Browsing or WebVR mode."/>
   <suffix name="VRBrowsing" label="Entered VR Browsing Mode."/>
-  <suffix name="WebVR"
-      label="Entered WebVR mode (also includes splash screen)."/>
-  <affected-histogram name="VR.AssetsComponent.Status.OnEnter"/>
-  <affected-histogram name="VR.DataConnection.OnEnter"/>
+  <suffix name="WebVRPresentation"
+      label="Entered WebVR presentation mode (also includes splash screen)."/>
+  <affected-histogram name="VR.Component.Assets.DurationUntilReady.OnEnter"/>
+  <affected-histogram name="VR.Component.Assets.Status.OnEnter"/>
+  <affected-histogram name="VR.NetworkConnectionType.OnEnter"/>
 </histogram_suffixes>
 
 <histogram_suffixes name="VRFreNotCompleteType" separator=".">
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
index 2128b1852..37d7fa6 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
@@ -413,10 +413,12 @@
 }
 
 bool DesktopWindowTreeHostWin::ShouldWindowContentsBeTransparent() const {
-  // If the window has a native frame, we assume it is an Aero Glass window, and
-  // is therefore transparent. Note: This is not equivalent to calling
-  // IsAeroGlassEnabled, because ShouldUseNativeFrame is overridden in a
-  // subclass.
+  // The window contents need to be transparent when the titlebar area is drawn
+  // by the DWM rather than Chrome, so that area can show through.  This
+  // function does not describe the transparency of the whole window appearance,
+  // but merely of the content Chrome draws, so even when the system titlebars
+  // appear opaque (Win 8+), the content above them needs to be transparent, or
+  // they'll be covered by a black (undrawn) region.
   return ShouldUseNativeFrame() && !IsFullscreen();
 }