diff --git a/AUTHORS b/AUTHORS
index 75487640..be619ba 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -58,6 +58,7 @@
 Andrei Parvu <parvu@adobe.com>
 Andrew Brampton <me@bramp.net>
 Andrew Hung <andrhung@amazon.com>
+Andrew MacPherson <andrew.macpherson@soundtrap.com>
 Andrew Tulloch <andrew@tullo.ch>
 Anish Patankar <anish.p@samsung.com>
 Ankit Kumar <ankit2.kumar@samsung.com>
diff --git a/DEPS b/DEPS
index 625ca46..8a1c4c97 100644
--- a/DEPS
+++ b/DEPS
@@ -44,7 +44,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '6cdbfc6d4134d4ae88b0c30b871789dac175916f',
+  'v8_revision': '017e985b9c81782ac6548fdad2c66b34bc30d72b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -96,7 +96,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': '7ca359550f9531a4c873dd071c73dcc7130eb537',
+  'catapult_revision': 'd77eaf7f69e860436f0245c10ea2c186937ab666',
   # 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/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java
index 2d15b2c..f868572 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -77,6 +77,7 @@
 import org.chromium.ui.base.ActivityWindowAndroid;
 import org.chromium.ui.base.PageTransition;
 import org.chromium.ui.base.ViewAndroidDelegate;
+import org.chromium.ui.base.ViewRoot;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.display.DisplayAndroid.DisplayAndroidObserver;
 
@@ -361,6 +362,8 @@
 
     private static String sCurrentLocales = "";
 
+    private ViewRoot mViewRoot;
+
     private static final class AwContentsDestroyRunnable implements Runnable {
         private final long mNativeAwContents;
         // Hold onto a reference to the window (via its wrapper), so that it is not destroyed
@@ -1202,6 +1205,7 @@
             mNativeAwContents = 0;
             mWebContents = null;
             mNavigationController = null;
+            mViewRoot = null;
 
             mCleanupReference.cleanupNow();
             mCleanupReference = null;
@@ -3205,7 +3209,7 @@
             // to enter fixedLayoutSize mode is sent before the first resize
             // update.
             mLayoutSizer.onSizeChanged(w, h, ow, oh);
-            mContentViewCore.onPhysicalBackingSizeChanged(w, h);
+            getViewRoot().onPhysicalBackingSizeChanged(w, h);
             mContentViewCore.onSizeChanged(w, h, ow, oh);
             nativeOnSizeChanged(mNativeAwContents, w, h, ow, oh);
         }
@@ -3281,6 +3285,13 @@
         }
     }
 
+    private ViewRoot getViewRoot() {
+        if (mViewRoot == null) {
+            mViewRoot = nativeGetViewRoot(mNativeAwContents);
+        }
+        return mViewRoot;
+    }
+
     // Return true if the GeolocationPermissionAPI should be used.
     @CalledByNative
     private boolean useLegacyGeolocationPermissionAPI() {
@@ -3384,4 +3395,5 @@
 
     private native void nativeGrantFileSchemeAccesstoChildProcess(long nativeAwContents);
     private native void nativeResumeLoadingCreatedPopupWebContents(long nativeAwContents);
+    private native ViewRoot nativeGetViewRoot(long nativeAwContents);
 }
diff --git a/android_webview/native/aw_contents.cc b/android_webview/native/aw_contents.cc
index ccd4ff8..66a3c05 100644
--- a/android_webview/native/aw_contents.cc
+++ b/android_webview/native/aw_contents.cc
@@ -1255,6 +1255,12 @@
   web_contents_->ResumeLoadingCreatedWebContents();
 }
 
+ScopedJavaLocalRef<jobject> AwContents::GetViewRoot(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj) {
+  return web_contents_->GetNativeView()->GetViewRoot();
+}
+
 void SetShouldDownloadFavicons(JNIEnv* env,
                                const JavaParamRef<jclass>& jclazz) {
   g_should_download_favicons = true;
diff --git a/android_webview/native/aw_contents.h b/android_webview/native/aw_contents.h
index 3416602..78a94f6 100644
--- a/android_webview/native/aw_contents.h
+++ b/android_webview/native/aw_contents.h
@@ -333,6 +333,9 @@
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj);
 
+  base::android::ScopedJavaLocalRef<jobject> GetViewRoot(JNIEnv* env,
+                              const base::android::JavaParamRef<jobject>& obj);
+
   // content::WebContentsObserver overrides
   void RenderViewHostChanged(content::RenderViewHost* old_host,
                              content::RenderViewHost* new_host) override;
diff --git a/ash/ash_touch_exploration_manager_chromeos.cc b/ash/ash_touch_exploration_manager_chromeos.cc
index 3438d27..c5bf8dd 100644
--- a/ash/ash_touch_exploration_manager_chromeos.cc
+++ b/ash/ash_touch_exploration_manager_chromeos.cc
@@ -102,6 +102,19 @@
     UpdateTouchExplorationState();
 }
 
+void AshTouchExplorationManager::PlaySpokenFeedbackToggleCountdown(
+    int tick_count) {
+  AccessibilityDelegate* delegate = WmShell::Get()->accessibility_delegate();
+  if (delegate->ShouldToggleSpokenFeedbackViaTouch())
+    delegate->PlaySpokenFeedbackToggleCountdown(tick_count);
+}
+
+void AshTouchExplorationManager::ToggleSpokenFeedback() {
+  AccessibilityDelegate* delegate = WmShell::Get()->accessibility_delegate();
+  if (delegate->ShouldToggleSpokenFeedbackViaTouch())
+    delegate->ToggleSpokenFeedback(ash::A11Y_NOTIFICATION_SHOW);
+}
+
 void AshTouchExplorationManager::OnWindowActivated(
     aura::client::ActivationChangeObserver::ActivationReason reason,
     aura::Window* gained_active,
@@ -129,11 +142,18 @@
   const bool spoken_feedback_enabled =
       WmShell::Get()->accessibility_delegate()->IsSpokenFeedbackEnabled();
 
+  if (!touch_accessibility_enabler_) {
+    // Always enable gesture to toggle spoken feedback.
+    touch_accessibility_enabler_.reset(new ui::TouchAccessibilityEnabler(
+        root_window_controller_->GetRootWindow(), this));
+  }
+
   if (spoken_feedback_enabled) {
     if (!touch_exploration_controller_.get()) {
       touch_exploration_controller_ =
           base::MakeUnique<ui::TouchExplorationController>(
-              root_window_controller_->GetRootWindow(), this);
+              root_window_controller_->GetRootWindow(), this,
+              touch_accessibility_enabler_.get());
     }
     if (pass_through_surface) {
       const gfx::Rect& work_area =
diff --git a/ash/ash_touch_exploration_manager_chromeos.h b/ash/ash_touch_exploration_manager_chromeos.h
index 9377059..8b2aa00 100644
--- a/ash/ash_touch_exploration_manager_chromeos.h
+++ b/ash/ash_touch_exploration_manager_chromeos.h
@@ -10,6 +10,7 @@
 #include "ash/ash_export.h"
 #include "ash/common/system/accessibility_observer.h"
 #include "base/macros.h"
+#include "ui/chromeos/touch_accessibility_enabler.h"
 #include "ui/chromeos/touch_exploration_controller.h"
 #include "ui/display/display_observer.h"
 #include "ui/wm/public/activation_change_observer.h"
@@ -28,6 +29,7 @@
 class ASH_EXPORT AshTouchExplorationManager
     : public AccessibilityObserver,
       public ui::TouchExplorationControllerDelegate,
+      public ui::TouchAccessibilityEnablerDelegate,
       public display::DisplayObserver,
       public aura::client::ActivationChangeObserver {
  public:
@@ -52,6 +54,10 @@
   void OnDisplayMetricsChanged(const display::Display& display,
                                uint32_t changed_metrics) override;
 
+  // TouchAccessibilityEnablerDelegate overrides:
+  void PlaySpokenFeedbackToggleCountdown(int tick_count) override;
+  void ToggleSpokenFeedback() override;
+
   // aura::client::ActivationChangeObserver overrides:
   void OnWindowActivated(
       aura::client::ActivationChangeObserver::ActivationReason reason,
@@ -67,6 +73,7 @@
   bool VolumeAdjustSoundEnabled();
 
   std::unique_ptr<ui::TouchExplorationController> touch_exploration_controller_;
+  std::unique_ptr<ui::TouchAccessibilityEnabler> touch_accessibility_enabler_;
   RootWindowController* root_window_controller_;
   chromeos::CrasAudioHandler* audio_handler_;
 
diff --git a/ash/common/accessibility_delegate.h b/ash/common/accessibility_delegate.h
index 36ea7080..25c0665 100644
--- a/ash/common/accessibility_delegate.h
+++ b/ash/common/accessibility_delegate.h
@@ -121,6 +121,13 @@
   // Gets the last accessibility alert that was triggered.
   virtual AccessibilityAlert GetLastAccessibilityAlert() = 0;
 
+  // Whether or not to enable toggling spoken feedback via holding down
+  // two fingers on the screen.
+  virtual bool ShouldToggleSpokenFeedbackViaTouch() = 0;
+
+  // Play tick sound indicating spoken feedback will be toggled after countdown.
+  virtual void PlaySpokenFeedbackToggleCountdown(int tick_count) = 0;
+
   // Plays an earcon. Earcons are brief and distinctive sounds that indicate
   // when their mapped event has occurred. The sound key enums can be found in
   // chromeos/audio/chromeos_sounds.h.
diff --git a/ash/common/default_accessibility_delegate.cc b/ash/common/default_accessibility_delegate.cc
index a4ebb23..6a1bd37 100644
--- a/ash/common/default_accessibility_delegate.cc
+++ b/ash/common/default_accessibility_delegate.cc
@@ -146,6 +146,13 @@
   return accessibility_alert_;
 }
 
+bool DefaultAccessibilityDelegate::ShouldToggleSpokenFeedbackViaTouch() {
+  return false;
+}
+
+void DefaultAccessibilityDelegate::PlaySpokenFeedbackToggleCountdown(
+    int tick_count) {}
+
 void DefaultAccessibilityDelegate::PlayEarcon(int sound_key) {}
 
 base::TimeDelta DefaultAccessibilityDelegate::PlayShutdownSound() const {
diff --git a/ash/common/default_accessibility_delegate.h b/ash/common/default_accessibility_delegate.h
index 07bd8b66..46af280 100644
--- a/ash/common/default_accessibility_delegate.h
+++ b/ash/common/default_accessibility_delegate.h
@@ -52,6 +52,8 @@
   double GetSavedScreenMagnifierScale() override;
   void TriggerAccessibilityAlert(AccessibilityAlert alert) override;
   AccessibilityAlert GetLastAccessibilityAlert() override;
+  bool ShouldToggleSpokenFeedbackViaTouch() override;
+  void PlaySpokenFeedbackToggleCountdown(int tick_count) override;
   void PlayEarcon(int sound_key) override;
   base::TimeDelta PlayShutdownSound() const override;
   void HandleAccessibilityGesture(ui::AXGesture gesture) override;
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
index 096eaf884..258406c 100644
--- a/base/trace_event/memory_dump_manager.cc
+++ b/base/trace_event/memory_dump_manager.cc
@@ -770,14 +770,8 @@
 
     subtle::NoBarrier_Store(&memory_tracing_enabled_, 1);
 
-    // TODO(primiano): This is a temporary hack to disable periodic memory dumps
-    // when running memory benchmarks until telemetry uses TraceConfig to
-    // enable/disable periodic dumps. See crbug.com/529184 .
-    if (!is_coordinator_ ||
-        CommandLine::ForCurrentProcess()->HasSwitch(
-            "enable-memory-benchmarking")) {
+    if (!is_coordinator_)
       return;
-    }
   }
 
   // Enable periodic dumps if necessary.
diff --git a/blimp/client/core/contents/blimp_contents_view_impl_android.cc b/blimp/client/core/contents/blimp_contents_view_impl_android.cc
index ee92657..6205fbd 100644
--- a/blimp/client/core/contents/blimp_contents_view_impl_android.cc
+++ b/blimp/client/core/contents/blimp_contents_view_impl_android.cc
@@ -29,8 +29,8 @@
       ime_dialog_(new ImeHelperDialog(blimp_contents->GetNativeWindow())) {
   blimp_view_ =
       base::MakeUnique<BlimpView>(blimp_contents->GetNativeWindow(), this);
-  view_ = base::MakeUnique<ui::ViewAndroid>(
-      blimp_view_->CreateViewAndroidDelegate());
+  view_ = base::MakeUnique<ui::ViewAndroid>();
+  view_->SetDelegate(blimp_view_->CreateViewAndroidDelegate());
   view_->SetLayer(contents_layer);
   blimp_contents->GetNativeWindow()->AddChild(view_.get());
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
index 1e1b48d..ff5a205 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
@@ -58,6 +58,7 @@
 import org.chromium.content.browser.SPenSupport;
 import org.chromium.ui.UiUtils;
 import org.chromium.ui.base.DeviceFormFactor;
+import org.chromium.ui.base.ViewRoot;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.resources.ResourceManager;
 import org.chromium.ui.resources.dynamics.DynamicResourceLoader;
@@ -123,6 +124,8 @@
     // If we've drawn at least one frame.
     private boolean mHasDrawnOnce;
 
+    private ViewRoot mViewRoot;
+
     /**
      * The information about {@link ContentView} for overlay panel. Used to adjust the backing
      * size of the content accordingly.
@@ -315,6 +318,8 @@
             mCompositorView.getResourceManager().getDynamicResourceLoader().registerResource(
                     R.id.control_container, mControlContainer.getToolbarResourceAdapter());
         }
+
+        mViewRoot = windowAndroid.getViewRoot();
     }
 
     /**
@@ -951,7 +956,8 @@
             width = MeasureSpec.getSize(mOverlayContentWidthMeasureSpec);
             height = MeasureSpec.getSize(mOverlayContentHeightMeasureSpec);
         }
-        contentViewCore.onPhysicalBackingSizeChanged(width, height);
+
+        mViewRoot.onPhysicalBackingSizeChanged(width, height);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java
index e284130..9ded27f4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java
@@ -809,7 +809,7 @@
             panelContent.onSizeChanged((int) (width / mPxToDp),
                     (int) (height / mPxToDp), panelContent.getViewportWidthPix(),
                     panelContent.getViewportHeightPix());
-            panelContent.onPhysicalBackingSizeChanged(
+            panelContent.getWindowAndroid().getViewRoot().onPhysicalBackingSizeChanged(
                     (int) (width / mPxToDp), (int) (height / mPxToDp));
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
index 23f08c89..b3f30ef 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
@@ -592,8 +592,12 @@
      * @param intent Intent with the download operation.
      */
     private void handleDownloadOperation(final Intent intent) {
+        // TODO(qinmin): Figure out how to properly handle this case.
+        boolean isOfflinePage =
+                IntentUtils.safeGetBooleanExtra(intent, EXTRA_IS_OFFLINE_PAGE, false);
         final DownloadSharedPreferenceEntry entry = getDownloadEntryFromIntent(intent);
-        if (entry == null) {
+        if (entry == null
+                && !(isOfflinePage && TextUtils.equals(intent.getAction(), ACTION_DOWNLOAD_OPEN))) {
             handleDownloadOperationForMissingNotification(intent);
             return;
         }
@@ -690,9 +694,12 @@
      * This can happen because the DownloadNotificationService learn about downloads later than
      * Download Home does, and may not yet have a DownloadSharedPreferenceEntry for the item.
      *
-     * TODO(qinmin): Talk with dfalcantara@ about whether this is the best path forward.
+     * TODO(qinmin): Figure out how to fix the SharedPreferences so that it properly tracks entries.
      */
     private void handleDownloadOperationForMissingNotification(Intent intent) {
+        // This function should only be called via Download Home, but catch this case to be safe.
+        if (!DownloadManagerService.hasDownloadManagerService()) return;
+
         String action = intent.getAction();
         String downloadGuid = IntentUtils.safeGetStringExtra(intent, EXTRA_DOWNLOAD_GUID);
         boolean isOffTheRecord =
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
index 6b52c4b..6027c5f9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
@@ -49,7 +49,8 @@
     static final String EXTRA_BROWSER_FALLBACK_URL = "browser_fallback_url";
 
     // Supervisor package name
-    private static final Object SUPERVISOR_PKG = "com.google.android.instantapps.supervisor";
+    @VisibleForTesting
+    static final Object SUPERVISOR_PKG = "com.google.android.instantapps.supervisor";
 
     // An extra that may be specified on an intent:// URL that contains an encoded value for the
     // referrer field passed to the market:// URL in the case where the app is not present.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
index 8cbbbd1e..948efd0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -2461,7 +2461,8 @@
         // (see http://crbug.com/340987).
         newContentViewCore.onSizeChanged(originalWidth, originalHeight, 0, 0);
         if (!bounds.isEmpty()) {
-            newContentViewCore.onPhysicalBackingSizeChanged(bounds.right, bounds.bottom);
+            newContentViewCore.getWindowAndroid().getViewRoot().onPhysicalBackingSizeChanged(
+                    bounds.right, bounds.bottom);
         }
         newContentViewCore.onShow();
         setContentViewCore(newContentViewCore);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
index f0c716f..e479484 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
@@ -28,6 +28,7 @@
 import org.chromium.content.browser.ContentViewCore;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.base.ViewAndroidDelegate;
+import org.chromium.ui.base.ViewRoot;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.display.DisplayAndroid;
 import org.chromium.ui.display.VirtualDisplayAndroid;
@@ -170,7 +171,7 @@
         Point size = new Point(surfaceWidth, surfaceHeight);
         mUiVirtualDisplay.update(size, size, dpr, null, null, null);
         mUiCVC.onSizeChanged(surfaceWidth, surfaceHeight, 0, 0);
-        mUiCVC.onPhysicalBackingSizeChanged(surfaceWidth, surfaceHeight);
+        getViewRoot(mUiCVC).onPhysicalBackingSizeChanged(surfaceWidth, surfaceHeight);
         nativeUIBoundsChanged(mNativeVrShell, surfaceWidth, surfaceHeight, dpr);
     }
 
@@ -183,10 +184,14 @@
         Point size = new Point(surfaceWidth, surfaceHeight);
         mContentVirtualDisplay.update(size, size, dpr, null, null, null);
         mContentCVC.onSizeChanged(surfaceWidth, surfaceHeight, 0, 0);
-        mContentCVC.onPhysicalBackingSizeChanged(surfaceWidth, surfaceHeight);
+        getViewRoot(mContentCVC).onPhysicalBackingSizeChanged(surfaceWidth, surfaceHeight);
         nativeContentBoundsChanged(mNativeVrShell, surfaceWidth, surfaceHeight, dpr);
     }
 
+    private ViewRoot getViewRoot(ContentViewCore cvc) {
+        return cvc.getWindowAndroid().getViewRoot();
+    }
+
     @Override
     public boolean dispatchTouchEvent(MotionEvent event) {
         // Normally, touch event is dispatched to presentation view only if the phone is paired with
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
index 3b2f89ff..960451df 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
@@ -21,6 +21,7 @@
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider;
 import org.chromium.chrome.browser.externalnav.ExternalNavigationHandler.OverrideUrlLoadingResult;
+import org.chromium.chrome.browser.instantapps.InstantAppsHandler;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabRedirectHandler;
 import org.chromium.chrome.browser.webapps.ChromeWebApkHost;
@@ -45,6 +46,7 @@
     private static final int START_FILE = 0x8;
     private static final int START_OTHER_ACTIVITY = 0x10;
     private static final int INTENT_SANITIZATION_EXCEPTION = 0x20;
+    private static final int PROXY_FOR_INSTANT_APPS = 0x40;
 
     private static final String SEARCH_RESULT_URL_FOR_TOM_HANKS =
             "https://www.google.com/search?q=tom+hanks";
@@ -540,6 +542,82 @@
     }
 
     @SmallTest
+    public void testInstantAppsIntent_incomingIntentRedirect() throws Exception {
+        TestContext context = new TestContext();
+        int transTypeLinkFromIntent = PageTransition.LINK
+                | PageTransition.FROM_API;
+        TabRedirectHandler redirectHandler = new TabRedirectHandler(context);
+        Intent fooIntent = Intent.parseUri("http://instantappenabled.com",
+                Intent.URI_INTENT_SCHEME);
+        redirectHandler.updateIntent(fooIntent);
+        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, false, false, 0, 0);
+        redirectHandler.updateNewUrlLoading(transTypeLinkFromIntent, true, false, 0, 0);
+
+        mDelegate.setCanHandleWithInstantApp(true);
+        checkUrl("http://goo.gl/1234")
+                .withPageTransition(transTypeLinkFromIntent)
+                .withIsRedirect(true)
+                .withRedirectHandler(redirectHandler)
+                .expecting(OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT, IGNORE);
+
+        // URL that cannot be handled with instant apps should stay in Chrome.
+        mDelegate.setCanHandleWithInstantApp(false);
+        checkUrl("http://goo.gl/1234")
+                .withPageTransition(transTypeLinkFromIntent)
+                .withIsRedirect(true)
+                .withRedirectHandler(redirectHandler)
+                .expecting(OverrideUrlLoadingResult.NO_OVERRIDE, IGNORE);
+    }
+
+    @SmallTest
+    public void testInstantAppsIntent_handleNavigation() {
+        mDelegate.setCanHandleWithInstantApp(false);
+        checkUrl("http://maybeinstantapp.com")
+                .withPageTransition(PageTransition.LINK)
+                .expecting(OverrideUrlLoadingResult.NO_OVERRIDE, IGNORE);
+
+        mDelegate.setCanHandleWithInstantApp(true);
+        checkUrl("http://maybeinstantapp.com")
+                .withPageTransition(PageTransition.LINK)
+                .expecting(OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT, IGNORE);
+    }
+
+    @SmallTest
+    public void testInstantAppsIntent_serpReferrer() {
+        String intentUrl = "intent://buzzfeed.com/tasty#Intent;scheme=http;"
+                + "package=com.google.android.instantapps.supervisor;"
+                + "action=com.google.android.instantapps.START;"
+                + "S.com.google.android.instantapps.FALLBACK_PACKAGE="
+                + "com.android.chrome;S.com.google.android.instantapps.INSTANT_APP_PACKAGE="
+                + "com.yelp.android;S.android.intent.extra.REFERRER_NAME="
+                + "https%3A%2F%2Fwww.google.com;end";
+        mDelegate.setIsSerpReferrer(true);
+        checkUrl(intentUrl)
+                .expecting(OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT,
+                        START_OTHER_ACTIVITY | PROXY_FOR_INSTANT_APPS);
+        assertTrue(mDelegate.startActivityIntent.hasExtra(
+                InstantAppsHandler.IS_GOOGLE_SEARCH_REFERRER));
+
+        // Check that we block all instant app intent:// URLs not from SERP
+        mDelegate.setIsSerpReferrer(false);
+        checkUrl(intentUrl)
+                .expecting(OverrideUrlLoadingResult.NO_OVERRIDE, IGNORE);
+
+        // Check that IS_GOOGLE_SEARCH_REFERRER param is stripped on non-supervisor intents.
+        mDelegate.setIsSerpReferrer(true);
+        String nonSupervisor = "intent://buzzfeed.com/tasty#Intent;scheme=http;"
+                + "package=com.imdb;action=com.google.VIEW;"
+                + "S.com.google.android.gms.instantapps.IS_GOOGLE_SEARCH_REFERRER="
+                + "true;S.android.intent.extra.REFERRER_NAME="
+                + "https%3A%2F%2Fwww.google.com;end";
+        checkUrl(nonSupervisor)
+                .expecting(OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT,
+                        START_OTHER_ACTIVITY);
+        assertFalse(mDelegate.startActivityIntent.hasExtra(
+                InstantAppsHandler.IS_GOOGLE_SEARCH_REFERRER));
+    }
+
+    @SmallTest
     public void testFallbackUrl_IntentResolutionSucceeds() {
         // IMDB app is installed.
         mDelegate.setCanResolveActivity(true);
@@ -1152,6 +1230,7 @@
             // For simplicity, don't distinguish between startActivityIfNeeded and startActivity
             // until a test requires this distinction.
             startActivityIntent = intent;
+            mCalledWithProxy = proxy;
             return true;
         }
 
@@ -1211,13 +1290,14 @@
 
         @Override
         public boolean isSerpReferrer(Tab tab) {
-            return false;
+            return mIsSerpReferrer;
         }
 
         public void reset() {
             startActivityIntent = null;
             startIncognitoIntentCalled = false;
             startFileIntentCalled = false;
+            mCalledWithProxy = false;
         }
 
         public void setCanResolveActivity(boolean value) {
@@ -1244,6 +1324,10 @@
             mCanHandleWithInstantApp = value;
         }
 
+        public void setIsSerpReferrer(boolean value) {
+            mIsSerpReferrer = value;
+        }
+
         public Intent startActivityIntent;
         public boolean startIncognitoIntentCalled;
 
@@ -1253,6 +1337,8 @@
         private String mNewUrlAfterClobbering;
         private String mReferrerUrlForClobbering;
         private boolean mCanHandleWithInstantApp;
+        private boolean mIsSerpReferrer;
+        public boolean mCalledWithProxy;
         public boolean mIsChromeAppInForeground = true;
         public boolean mIsWithinCurrentWebappScope;
 
@@ -1342,6 +1428,7 @@
             boolean expectStartFile = (otherExpectation & START_FILE) != 0;
             boolean expectSaneIntent = expectStartOtherActivity
                     && (otherExpectation & INTENT_SANITIZATION_EXCEPTION) == 0;
+            boolean expectProxyForIA = (otherExpectation & PROXY_FOR_INSTANT_APPS) != 0;
 
             mDelegate.reset();
 
@@ -1375,6 +1462,7 @@
             assertEquals(expectStartChrome, startChromeCalled);
             assertEquals(expectStartWebApk, startWebApkCalled);
             assertEquals(expectStartFile, mDelegate.startFileIntentCalled);
+            assertEquals(expectProxyForIA, mDelegate.mCalledWithProxy);
 
             if (startActivityCalled && expectSaneIntent) {
                 checkIntentSanity(mDelegate.startActivityIntent, "Intent");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/instantapps/InstantAppsHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/instantapps/InstantAppsHandlerTest.java
index ff77e92..9705f8c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/instantapps/InstantAppsHandlerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/instantapps/InstantAppsHandlerTest.java
@@ -4,27 +4,38 @@
 
 package org.chromium.chrome.browser.instantapps;
 
+import android.app.Instrumentation;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.SharedPreferences;
 import android.net.Uri;
 import android.nfc.NfcAdapter;
 import android.provider.Browser;
-import android.test.InstrumentationTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import org.chromium.base.ContextUtils;
+import org.chromium.base.ThreadUtils;
+import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.IntentHandler;
+import org.chromium.chrome.browser.ShortcutHelper;
+import org.chromium.chrome.test.ChromeActivityTestCaseBase;
+import org.chromium.content_public.browser.WebContents;
 
 /**
  * Unit tests for {@link InstantAppsHandler}.
  */
-public class InstantAppsHandlerTest extends InstrumentationTestCase {
-
+public class InstantAppsHandlerTest extends ChromeActivityTestCaseBase<ChromeActivity> {
     private TestInstantAppsHandler mHandler;
     private Context mContext;
 
     private static final Uri URI = Uri.parse("http://sampleurl.com/foo");
+    private static final String INSTANT_APP_URL = "http://sampleapp.com/boo";
+    private static final Uri REFERRER_URI = Uri.parse("http://www.wikipedia.org/");
+
+    public InstantAppsHandlerTest() {
+        super(ChromeActivity.class);
+    }
 
     private Intent createViewIntent() {
         return new Intent(Intent.ACTION_VIEW, URI);
@@ -99,6 +110,13 @@
     }
 
     @SmallTest
+    public void testInstantAppsDisabled_launchFromShortcut() {
+        Intent i = createViewIntent();
+        i.putExtra(ShortcutHelper.EXTRA_SOURCE, 1);
+        assertFalse(mHandler.handleIncomingIntent(mContext, i, false));
+    }
+
+    @SmallTest
     public void testChromeNotDefault() {
         SharedPreferences prefs = ContextUtils.getAppSharedPreferences();
         SharedPreferences.Editor editor = prefs.edit();
@@ -134,11 +152,99 @@
         assertTrue(mHandler.handleIncomingIntent(getInstrumentation().getContext(), i, false));
     }
 
+    @SmallTest
+    public void testHandleNavigation_noExperiment() {
+        SharedPreferences prefs = ContextUtils.getAppSharedPreferences();
+        SharedPreferences.Editor editor = prefs.edit();
+        editor.putBoolean("applink.app_link_enabled", false);
+        editor.apply();
+
+        assertFalse(mHandler.handleNavigation(mContext, INSTANT_APP_URL, REFERRER_URI, null));
+        assertFalse(mHandler.mLaunchInstantApp);
+        assertFalse(mHandler.mStartedAsyncCall);
+    }
+
+    @SmallTest
+    public void testHandleNavigation_startAsyncCheck() {
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                assertFalse(mHandler.handleNavigation(mContext, INSTANT_APP_URL, REFERRER_URI,
+                        getActivity().getTabModelSelector().getCurrentTab().getWebContents()));
+            }
+        });
+        assertFalse(mHandler.mLaunchInstantApp);
+        assertTrue(mHandler.mStartedAsyncCall);
+    }
+
+    @SmallTest
+    public void testLaunchFromBanner() {
+        // Intent to supervisor
+        final Intent i = new Intent(Intent.ACTION_MAIN);
+        i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        Instrumentation.ActivityMonitor monitor = getInstrumentation().addMonitor(
+                new IntentFilter(Intent.ACTION_MAIN), null, true);
+
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mHandler.launchFromBanner(new InstantAppsBannerData(
+                        "App", null, INSTANT_APP_URL, REFERRER_URI, i, "Launch",
+                        getActivity().getTabModelSelector().getCurrentTab().getWebContents()));
+            }
+        });
+
+        // Started instant apps intent
+        assertEquals(1, monitor.getHits());
+
+        assertEquals(REFERRER_URI, i.getParcelableExtra(Intent.EXTRA_REFERRER));
+        assertTrue(i.getBooleanExtra(InstantAppsHandler.IS_REFERRER_TRUSTED_EXTRA, false));
+        assertTrue(i.getBooleanExtra(InstantAppsHandler.IS_USER_CONFIRMED_LAUNCH_EXTRA, false));
+        assertEquals(mContext.getPackageName(),
+                i.getStringExtra(InstantAppsHandler.TRUSTED_REFERRER_PKG_EXTRA));
+
+        // After a banner launch, test that the next launch happens automatically
+
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                assertTrue(mHandler.handleNavigation(mContext, INSTANT_APP_URL, REFERRER_URI,
+                        getActivity().getTabModelSelector().getCurrentTab().getWebContents()));
+            }
+        });
+        assertFalse(mHandler.mStartedAsyncCall);
+        assertTrue(mHandler.mLaunchInstantApp);
+    }
+
+    @Override
+    public void startMainActivity() throws InterruptedException {
+        startMainActivityOnBlankPage();
+    }
+
     static class TestInstantAppsHandler extends InstantAppsHandler {
+        // Keeps track of whether startCheckForInstantApps() has been called.
+        public volatile boolean mStartedAsyncCall;
+        // Keeps track of whether launchInstantAppForNavigation() has been called.
+        public volatile boolean mLaunchInstantApp;
+
         @Override
         protected boolean tryLaunchingInstantApp(Context context, Intent intent,
                 boolean isCustomTabsIntent, Intent fallbackIntent) {
             return true;
         }
+
+        @Override
+        protected boolean launchInstantAppForNavigation(Context context, String url, Uri referrer) {
+            mLaunchInstantApp = true;
+            return true;
+        }
+
+        @Override
+        protected boolean startCheckForInstantApps(Context context, String url, Uri referrer,
+                WebContents webContents) {
+            mStartedAsyncCall = true;
+            return false;
+        }
     }
 }
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 3e585809..d9c9074b 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -15164,6 +15164,12 @@
       <message name="IDS_FLAGS_ENABLE_NATIVE_CUPS_DESCRIPTION" desc="Description of the native CUPS flag">
         Enables the use of the native CUPS printing backend.
       </message>
+      <message name="IDS_FLAGS_ENABLE_ANDROID_WALLPAPERS_APP_NAME" desc="Name of the Android Wallpapers App flag.">
+        Android Wallpapers App
+      </message>
+      <message name="IDS_FLAGS_ENABLE_ANDROID_WALLPAPERS_APP_DESCRIPTION" desc="Description of the Android Wallpapers App flag.">
+        Enables the Android Wallpapers App as the default Wallpaper App on Chrome OS.
+      </message>
     </if>
 
     <if expr="is_android">
diff --git a/chrome/app/theme/default_100_percent/common/ash/theme_default_inactive.png b/chrome/app/theme/default_100_percent/common/ash/theme_default_inactive.png
deleted file mode 100644
index cd17469..0000000
--- a/chrome/app/theme/default_100_percent/common/ash/theme_default_inactive.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/omnibox_tts.png b/chrome/app/theme/default_100_percent/common/omnibox_tts.png
deleted file mode 100644
index 8f693f50..0000000
--- a/chrome/app/theme/default_100_percent/common/omnibox_tts.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/omnibox_tts_selected.png b/chrome/app/theme/default_100_percent/common/omnibox_tts_selected.png
deleted file mode 100644
index 9f9d5c9..0000000
--- a/chrome/app/theme/default_100_percent/common/omnibox_tts_selected.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/question_mark.png b/chrome/app/theme/default_100_percent/common/question_mark.png
deleted file mode 100644
index 7038584..0000000
--- a/chrome/app/theme/default_100_percent/common/question_mark.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/ash/theme_default_inactive.png b/chrome/app/theme/default_200_percent/common/ash/theme_default_inactive.png
deleted file mode 100644
index ed8750a..0000000
--- a/chrome/app/theme/default_200_percent/common/ash/theme_default_inactive.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/omnibox_tts.png b/chrome/app/theme/default_200_percent/common/omnibox_tts.png
deleted file mode 100644
index fa308bc..0000000
--- a/chrome/app/theme/default_200_percent/common/omnibox_tts.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/question_mark.png b/chrome/app/theme/default_200_percent/common/question_mark.png
deleted file mode 100644
index dda32246..0000000
--- a/chrome/app/theme/default_200_percent/common/question_mark.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 3e31a484..862bf57 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1417,6 +1417,7 @@
     "//components/network_time",
     "//components/ntp_snippets",
     "//components/ntp_tiles",
+    "//components/offline_pages/content/background_loader",
     "//components/offline_pages/core",
     "//components/offline_pages/core/background:background_offliner",
     "//components/offline_pages/core/downloads:offline_pages_ui_adapter",
@@ -3108,6 +3109,8 @@
       "android/ntp/ntp_snippets_bridge.h",
       "android/ntp/ntp_snippets_launcher.cc",
       "android/ntp/ntp_snippets_launcher.h",
+      "android/offline_pages/background_loader_offliner.cc",
+      "android/offline_pages/background_loader_offliner.h",
       "android/offline_pages/background_scheduler_bridge.cc",
       "android/offline_pages/background_scheduler_bridge.h",
       "android/offline_pages/downloads/offline_page_download_bridge.cc",
@@ -3116,6 +3119,8 @@
       "android/offline_pages/downloads/offline_page_infobar_delegate.h",
       "android/offline_pages/downloads/offline_page_notification_bridge.cc",
       "android/offline_pages/downloads/offline_page_notification_bridge.h",
+      "android/offline_pages/downloads/resource_throttle.cc",
+      "android/offline_pages/downloads/resource_throttle.h",
       "android/offline_pages/offline_page_bookmark_observer.cc",
       "android/offline_pages/offline_page_bookmark_observer.h",
       "android/offline_pages/offline_page_bridge.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index ec10a42..62bd08b 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2132,7 +2132,12 @@
     {"cros-comp-updates", IDS_FLAGS_CROS_COMP_UPDATES_NAME,
      IDS_FLAGS_CROS_COMP_UPDATES_DESCRIPTION, kOsCrOS,
      FEATURE_VALUE_TYPE(features::kCrosCompUpdates)},
-#endif
+    {"enable-android-wallpapers-app",
+     IDS_FLAGS_ENABLE_ANDROID_WALLPAPERS_APP_NAME,
+     IDS_FLAGS_ENABLE_ANDROID_WALLPAPERS_APP_DESCRIPTION, kOsCrOS,
+     SINGLE_VALUE_TYPE(chromeos::switches::kEnableAndroidWallpapersApp)},
+#endif  // defined(OS_CHROMEOS)
+
 #if defined(OS_ANDROID)
     {"enable-expanded-autofill-credit-card-popup",
      IDS_FLAGS_ENABLE_EXPANDED_AUTOFILL_CREDIT_CARD_POPUP_LAYOUT,
diff --git a/chrome/browser/android/offline_pages/background_loader_offliner.cc b/chrome/browser/android/offline_pages/background_loader_offliner.cc
new file mode 100644
index 0000000..096a5229
--- /dev/null
+++ b/chrome/browser/android/offline_pages/background_loader_offliner.cc
@@ -0,0 +1,148 @@
+// 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 "chrome/browser/android/offline_pages/background_loader_offliner.h"
+
+#include "base/sys_info.h"
+#include "chrome/browser/android/offline_pages/offline_page_mhtml_archiver.h"
+#include "components/offline_pages/core/background/save_page_request.h"
+#include "components/offline_pages/core/offline_page_model.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/web_contents.h"
+
+namespace offline_pages {
+
+BackgroundLoaderOffliner::BackgroundLoaderOffliner(
+    content::BrowserContext* browser_context,
+    const OfflinerPolicy* policy,
+    OfflinePageModel* offline_page_model)
+    : browser_context_(browser_context),
+      offline_page_model_(offline_page_model),
+      is_low_end_device_(base::SysInfo::IsLowEndDevice()),
+      save_state_(NONE),
+      weak_ptr_factory_(this) {
+  DCHECK(offline_page_model_);
+  DCHECK(browser_context_);
+}
+
+BackgroundLoaderOffliner::~BackgroundLoaderOffliner() {}
+
+bool BackgroundLoaderOffliner::LoadAndSave(const SavePageRequest& request,
+                                           const CompletionCallback& callback) {
+  DCHECK(callback);
+
+  if (pending_request_) {
+    DVLOG(1) << "Already have pending request";
+    return false;
+  }
+
+  if (!OfflinePageModel::CanSaveURL(request.url())) {
+    DVLOG(1) << "Not able to save page for requested url: " << request.url();
+    return false;
+  }
+
+  if (!loader_)
+    ResetState();
+
+  // Track copy of pending request.
+  pending_request_.reset(new SavePageRequest(request));
+  completion_callback_ = callback;
+
+  // Listen for app foreground/background change.
+  app_listener_.reset(new base::android::ApplicationStatusListener(
+      base::Bind(&BackgroundLoaderOffliner::OnApplicationStateChange,
+                 weak_ptr_factory_.GetWeakPtr())));
+
+  loader_.get()->LoadPage(request.url());
+
+  return true;
+}
+
+void BackgroundLoaderOffliner::Cancel() {
+  // TODO(chili): We are not able to cancel a pending
+  // OfflinePageModel::SavePage() operation. We just ignore the callback.
+  if (!pending_request_)
+    return;
+
+  if (save_state_ != NONE) {
+    save_state_ = DELETE_AFTER_SAVE;
+    return;
+  }
+
+  ResetState();
+}
+
+void BackgroundLoaderOffliner::DidStopLoading() {
+  if (!pending_request_.get()) {
+    DVLOG(1) << "DidStopLoading called even though no pending request.";
+    return;
+  }
+
+  save_state_ = SAVING;
+  SavePageRequest request(*pending_request_.get());
+  content::WebContents* web_contents(
+      content::WebContentsObserver::web_contents());
+
+  std::unique_ptr<OfflinePageArchiver> archiver(
+      new OfflinePageMHTMLArchiver(web_contents));
+
+  OfflinePageModel::SavePageParams params;
+  params.url = web_contents->GetLastCommittedURL();
+  params.client_id = request.client_id();
+  params.proposed_offline_id = request.request_id();
+  offline_page_model_->SavePage(
+      params, std::move(archiver),
+      base::Bind(&BackgroundLoaderOffliner::OnPageSaved,
+                 weak_ptr_factory_.GetWeakPtr()));
+}
+
+void BackgroundLoaderOffliner::OnPageSaved(SavePageResult save_result,
+                                           int64_t offline_id) {
+  if (!pending_request_)
+    return;
+
+  SavePageRequest request(*pending_request_.get());
+  ResetState();
+
+  if (save_state_ == DELETE_AFTER_SAVE) {
+    save_state_ = NONE;
+    return;
+  }
+
+  save_state_ = NONE;
+
+  Offliner::RequestStatus save_status;
+  if (save_result == SavePageResult::SUCCESS)
+    save_status = RequestStatus::SAVED;
+  else
+    save_status = RequestStatus::SAVE_FAILED;
+
+  completion_callback_.Run(request, save_status);
+}
+
+void BackgroundLoaderOffliner::ResetState() {
+  pending_request_.reset();
+  // TODO(chili): Remove after RequestCoordinator can handle multiple offliners.
+  // We reset the loader and observer after completion so loaders
+  // will not be re-used across different requests/tries. This is a temporary
+  // solution while there exists assumptions about the number of offliners
+  // there are.
+  loader_.reset(
+      new background_loader::BackgroundLoaderContents(browser_context_));
+  content::WebContentsObserver::Observe(loader_.get()->web_contents());
+}
+
+void BackgroundLoaderOffliner::OnApplicationStateChange(
+    base::android::ApplicationState application_state) {
+  if (pending_request_ && is_low_end_device_ &&
+      application_state ==
+          base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES) {
+    DVLOG(1) << "App became active, canceling current offlining request";
+    SavePageRequest* request = pending_request_.get();
+    Cancel();
+    completion_callback_.Run(*request, RequestStatus::FOREGROUND_CANCELED);
+  }
+}
+
+}  // namespace offline_pages
diff --git a/chrome/browser/android/offline_pages/background_loader_offliner.h b/chrome/browser/android/offline_pages/background_loader_offliner.h
new file mode 100644
index 0000000..f8c6a04c
--- /dev/null
+++ b/chrome/browser/android/offline_pages/background_loader_offliner.h
@@ -0,0 +1,82 @@
+// 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 CHROME_BROWSER_ANDROID_OFFLINE_PAGES_BACKGROUND_LOADER_OFFLINER_H_
+#define CHROME_BROWSER_ANDROID_OFFLINE_PAGES_BACKGROUND_LOADER_OFFLINER_H_
+
+#include <memory>
+
+#include "base/android/application_status_listener.h"
+#include "base/memory/weak_ptr.h"
+#include "components/offline_pages/content/background_loader/background_loader_contents.h"
+#include "components/offline_pages/core/background/offliner.h"
+#include "components/offline_pages/core/offline_page_types.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace content {
+class BrowserContext;
+}  // namespace content
+
+namespace offline_pages {
+
+class OfflinerPolicy;
+class OfflinePageModel;
+
+// An Offliner implementation that attempts client-side rendering and saving
+// of an offline page. It uses the BackgroundLoader to load the page and the
+// OfflinePageModel to save it. Only one request may be active at a time.
+class BackgroundLoaderOffliner : public Offliner,
+                                 public content::WebContentsObserver {
+ public:
+  BackgroundLoaderOffliner(content::BrowserContext* browser_context,
+                           const OfflinerPolicy* policy,
+                           OfflinePageModel* offline_page_model);
+  ~BackgroundLoaderOffliner() override;
+
+  // Offliner implementation.
+  bool LoadAndSave(const SavePageRequest& request,
+                   const CompletionCallback& callback) override;
+  void Cancel() override;
+
+  // WebContentsObserver implementation.
+  void DidStopLoading() override;
+
+ protected:
+  // Called to reset internal loader and observer state.
+  virtual void ResetState();
+
+ private:
+  friend class TestBackgroundLoaderOffliner;
+
+  enum SaveState { NONE, SAVING, DELETE_AFTER_SAVE };
+
+  // Called when the page has been saved.
+  void OnPageSaved(SavePageResult save_result, int64_t offline_id);
+
+  // Called when application state has changed.
+  void OnApplicationStateChange(
+      base::android::ApplicationState application_state);
+
+  std::unique_ptr<background_loader::BackgroundLoaderContents> loader_;
+  // Not owned.
+  content::BrowserContext* browser_context_;
+  // Not owned.
+  OfflinePageModel* offline_page_model_;
+  // Tracks pending request, if any.
+  std::unique_ptr<SavePageRequest> pending_request_;
+  // Callback when pending request completes.
+  CompletionCallback completion_callback_;
+  // ApplicationStatusListener to monitor if Chrome moves to the foreground.
+  std::unique_ptr<base::android::ApplicationStatusListener> app_listener_;
+  // Whether we are on a low-end device.
+  bool is_low_end_device_;
+  // Save state.
+  SaveState save_state_;
+
+  base::WeakPtrFactory<BackgroundLoaderOffliner> weak_ptr_factory_;
+  DISALLOW_COPY_AND_ASSIGN(BackgroundLoaderOffliner);
+};
+
+}  // namespace offline_pages
+#endif  // CHROME_BROWSER_ANDROID_OFFLINE_PAGES_BACKGROUND_LOADER_OFFLINER_H_
diff --git a/chrome/browser/android/offline_pages/background_loader_offliner_unittest.cc b/chrome/browser/android/offline_pages/background_loader_offliner_unittest.cc
new file mode 100644
index 0000000..1ff5b68f
--- /dev/null
+++ b/chrome/browser/android/offline_pages/background_loader_offliner_unittest.cc
@@ -0,0 +1,261 @@
+// 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 "chrome/browser/android/offline_pages/background_loader_offliner.h"
+
+#include "base/bind.h"
+#include "base/run_loop.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/offline_pages/content/background_loader/background_loader_contents_stub.h"
+#include "components/offline_pages/core/background/offliner.h"
+#include "components/offline_pages/core/background/save_page_request.h"
+#include "components/offline_pages/core/stub_offline_page_model.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/web_contents_tester.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace offline_pages {
+
+namespace {
+
+const int64_t kRequestId = 7;
+const GURL kHttpUrl("http://www.tunafish.com");
+const GURL kFileUrl("file://salmon.png");
+const ClientId kClientId("AsyncLoading", "88");
+const bool kUserRequested = true;
+
+// Mock OfflinePageModel for testing the SavePage calls
+class MockOfflinePageModel : public StubOfflinePageModel {
+ public:
+  MockOfflinePageModel() : mock_saving_(false) {}
+  ~MockOfflinePageModel() override {}
+
+  void SavePage(const SavePageParams& save_page_params,
+                std::unique_ptr<OfflinePageArchiver> archiver,
+                const SavePageCallback& callback) override {
+    mock_saving_ = true;
+    save_page_callback_ = callback;
+  }
+
+  void CompleteSavingAsArchiveCreationFailed() {
+    DCHECK(mock_saving_);
+    mock_saving_ = false;
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(save_page_callback_,
+                              SavePageResult::ARCHIVE_CREATION_FAILED, 0));
+  }
+
+  void CompleteSavingAsSuccess() {
+    DCHECK(mock_saving_);
+    mock_saving_ = false;
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::Bind(save_page_callback_, SavePageResult::SUCCESS, 123456));
+  }
+
+  bool mock_saving() const { return mock_saving_; }
+
+ private:
+  bool mock_saving_;
+  SavePageCallback save_page_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockOfflinePageModel);
+};
+
+void PumpLoop() {
+  base::RunLoop().RunUntilIdle();
+}
+}  // namespace
+
+// A BackgroundLoader that we can run tests on.
+// Overrides the ResetState so we don't actually try to create any web contents.
+// This is a temporary solution to test core BackgroundLoaderOffliner
+// functionality until we straighten out assumptions made by RequestCoordinator
+// so that the ResetState method is no longer needed.
+class TestBackgroundLoaderOffliner : public BackgroundLoaderOffliner {
+ public:
+  explicit TestBackgroundLoaderOffliner(
+      content::BrowserContext* browser_context,
+      const OfflinerPolicy* policy,
+      OfflinePageModel* offline_page_model);
+  ~TestBackgroundLoaderOffliner() override;
+  content::WebContentsTester* web_contents() {
+    return content::WebContentsTester::For(stub_->web_contents());
+  }
+
+  bool is_loading() { return stub_->is_loading(); }
+
+ protected:
+  void ResetState() override;
+
+ private:
+  background_loader::BackgroundLoaderContentsStub* stub_;
+};
+
+TestBackgroundLoaderOffliner::TestBackgroundLoaderOffliner(
+    content::BrowserContext* browser_context,
+    const OfflinerPolicy* policy,
+    OfflinePageModel* offline_page_model)
+    : BackgroundLoaderOffliner(browser_context, policy, offline_page_model) {}
+
+TestBackgroundLoaderOffliner::~TestBackgroundLoaderOffliner() {}
+
+void TestBackgroundLoaderOffliner::ResetState() {
+  pending_request_.reset();
+  stub_ = new background_loader::BackgroundLoaderContentsStub(browser_context_);
+  loader_.reset(stub_);
+  content::WebContentsObserver::Observe(stub_->web_contents());
+}
+
+class BackgroundLoaderOfflinerTest : public testing::Test {
+ public:
+  BackgroundLoaderOfflinerTest();
+  ~BackgroundLoaderOfflinerTest() override;
+
+  void SetUp() override;
+
+  TestBackgroundLoaderOffliner* offliner() const { return offliner_.get(); }
+  Offliner::CompletionCallback const callback() {
+    return base::Bind(&BackgroundLoaderOfflinerTest::OnCompletion,
+                      base::Unretained(this));
+  }
+  Profile* profile() { return &profile_; }
+  bool completion_callback_called() { return completion_callback_called_; }
+  Offliner::RequestStatus request_status() { return request_status_; }
+  bool SaveInProgress() const { return model_->mock_saving(); }
+  MockOfflinePageModel* model() const { return model_; }
+
+  void CompleteLoading() {
+    // For some reason, setting loading to True will call DidStopLoading
+    // on the observers.
+    offliner()->web_contents()->TestSetIsLoading(true);
+  }
+
+ private:
+  void OnCompletion(const SavePageRequest& request,
+                    Offliner::RequestStatus status);
+  content::TestBrowserThreadBundle thread_bundle_;
+  TestingProfile profile_;
+  std::unique_ptr<TestBackgroundLoaderOffliner> offliner_;
+  MockOfflinePageModel* model_;
+  bool completion_callback_called_;
+  Offliner::RequestStatus request_status_;
+
+  DISALLOW_COPY_AND_ASSIGN(BackgroundLoaderOfflinerTest);
+};
+
+BackgroundLoaderOfflinerTest::BackgroundLoaderOfflinerTest()
+    : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
+      completion_callback_called_(false),
+      request_status_(Offliner::RequestStatus::UNKNOWN) {}
+
+BackgroundLoaderOfflinerTest::~BackgroundLoaderOfflinerTest() {}
+
+void BackgroundLoaderOfflinerTest::SetUp() {
+  model_ = new MockOfflinePageModel();
+  offliner_.reset(new TestBackgroundLoaderOffliner(profile(), nullptr, model_));
+}
+
+void BackgroundLoaderOfflinerTest::OnCompletion(
+    const SavePageRequest& request,
+    Offliner::RequestStatus status) {
+  DCHECK(!completion_callback_called_);  // Expect 1 callback per request.
+  completion_callback_called_ = true;
+  request_status_ = status;
+}
+
+TEST_F(BackgroundLoaderOfflinerTest, LoadAndSaveStartsLoading) {
+  base::Time creation_time = base::Time::Now();
+  SavePageRequest request(kRequestId, kHttpUrl, kClientId, creation_time,
+                          kUserRequested);
+  EXPECT_TRUE(offliner()->LoadAndSave(request, callback()));
+  EXPECT_TRUE(offliner()->is_loading());
+  EXPECT_FALSE(SaveInProgress());
+  EXPECT_FALSE(completion_callback_called());
+  EXPECT_EQ(Offliner::RequestStatus::UNKNOWN, request_status());
+}
+
+TEST_F(BackgroundLoaderOfflinerTest, CompleteLoadingInitiatesSave) {
+  base::Time creation_time = base::Time::Now();
+  SavePageRequest request(kRequestId, kHttpUrl, kClientId, creation_time,
+                          kUserRequested);
+  EXPECT_TRUE(offliner()->LoadAndSave(request, callback()));
+  CompleteLoading();
+  PumpLoop();
+  EXPECT_FALSE(completion_callback_called());
+  EXPECT_TRUE(SaveInProgress());
+  EXPECT_EQ(Offliner::RequestStatus::UNKNOWN, request_status());
+}
+
+TEST_F(BackgroundLoaderOfflinerTest, CancelWhenLoading) {
+  base::Time creation_time = base::Time::Now();
+  SavePageRequest request(kRequestId, kHttpUrl, kClientId, creation_time,
+                          kUserRequested);
+  EXPECT_TRUE(offliner()->LoadAndSave(request, callback()));
+  offliner()->Cancel();
+  EXPECT_FALSE(offliner()->is_loading());  // Offliner reset.
+}
+
+TEST_F(BackgroundLoaderOfflinerTest, CancelWhenLoaded) {
+  base::Time creation_time = base::Time::Now();
+  SavePageRequest request(kRequestId, kHttpUrl, kClientId, creation_time,
+                          kUserRequested);
+  EXPECT_TRUE(offliner()->LoadAndSave(request, callback()));
+  CompleteLoading();
+  PumpLoop();
+  offliner()->Cancel();
+
+  // Subsequent save callback cause no crash.
+  model()->CompleteSavingAsArchiveCreationFailed();
+  PumpLoop();
+  EXPECT_FALSE(completion_callback_called());
+  EXPECT_FALSE(SaveInProgress());
+  EXPECT_FALSE(offliner()->is_loading());  // Offliner reset.
+}
+
+TEST_F(BackgroundLoaderOfflinerTest, LoadedButSaveFails) {
+  base::Time creation_time = base::Time::Now();
+  SavePageRequest request(kRequestId, kHttpUrl, kClientId, creation_time,
+                          kUserRequested);
+  EXPECT_TRUE(offliner()->LoadAndSave(request, callback()));
+  EXPECT_TRUE(offliner()->is_loading());
+
+  CompleteLoading();
+  PumpLoop();
+  model()->CompleteSavingAsArchiveCreationFailed();
+  PumpLoop();
+  EXPECT_TRUE(completion_callback_called());
+  EXPECT_EQ(Offliner::RequestStatus::SAVE_FAILED, request_status());
+  EXPECT_FALSE(offliner()->is_loading());
+  EXPECT_FALSE(SaveInProgress());
+}
+
+TEST_F(BackgroundLoaderOfflinerTest, LoadAndSaveSuccess) {
+  base::Time creation_time = base::Time::Now();
+  SavePageRequest request(kRequestId, kHttpUrl, kClientId, creation_time,
+                          kUserRequested);
+  EXPECT_TRUE(offliner()->LoadAndSave(request, callback()));
+
+  CompleteLoading();
+  PumpLoop();
+  EXPECT_FALSE(completion_callback_called());
+  EXPECT_TRUE(SaveInProgress());
+
+  model()->CompleteSavingAsSuccess();
+  PumpLoop();
+  EXPECT_TRUE(completion_callback_called());
+  EXPECT_EQ(Offliner::RequestStatus::SAVED, request_status());
+  EXPECT_FALSE(offliner()->is_loading());
+  EXPECT_FALSE(SaveInProgress());
+}
+
+TEST_F(BackgroundLoaderOfflinerTest, FailsOnInvalidURL) {
+  base::Time creation_time = base::Time::Now();
+  SavePageRequest request(kRequestId, kFileUrl, kClientId, creation_time,
+                          kUserRequested);
+  EXPECT_FALSE(offliner()->LoadAndSave(request, callback()));
+}
+
+}  // namespace offline_pages
diff --git a/chrome/browser/android/offline_pages/downloads/resource_throttle.cc b/chrome/browser/android/offline_pages/downloads/resource_throttle.cc
new file mode 100644
index 0000000..a5399b10
--- /dev/null
+++ b/chrome/browser/android/offline_pages/downloads/resource_throttle.cc
@@ -0,0 +1,68 @@
+// 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 "chrome/browser/android/offline_pages/downloads/resource_throttle.h"
+
+#include "base/logging.h"
+#include "chrome/browser/android/offline_pages/offline_page_utils.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/resource_request_info.h"
+#include "content/public/browser/web_contents.h"
+#include "net/base/mime_util.h"
+
+namespace {
+// Mime type of download resource that should trigger handoff to OfflinePages
+// backend for full page load and snapshot.
+bool CanDownloadAsOfflinePage(const std::string& contents_mime_type) {
+  return net::MatchesMimeType(contents_mime_type, "text/html") ||
+         net::MatchesMimeType(contents_mime_type, "application/xhtml+xml");
+}
+
+void WillStartOfflineRequestOnUIThread(
+    const GURL& url,
+    const content::ResourceRequestInfo::WebContentsGetter& contents_getter) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  content::WebContents* web_contents = contents_getter.Run();
+  if (!web_contents)
+    return;
+  offline_pages::OfflinePageUtils::StartOfflinePageDownload(
+      web_contents->GetBrowserContext(), url);
+}
+}  // namespace
+
+namespace offline_pages {
+namespace downloads {
+
+ResourceThrottle::ResourceThrottle(const net::URLRequest* request)
+    : request_(request) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+}
+
+ResourceThrottle::~ResourceThrottle() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+}
+
+void ResourceThrottle::WillProcessResponse(bool* defer) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  std::string mime_type;
+  request_->GetMimeType(&mime_type);
+  if (CanDownloadAsOfflinePage(mime_type)) {
+    const content::ResourceRequestInfo* info =
+        content::ResourceRequestInfo::ForRequest(request_);
+    if (!info)
+      return;
+    content::BrowserThread::PostTask(
+        content::BrowserThread::UI, FROM_HERE,
+        base::Bind(&WillStartOfflineRequestOnUIThread, request_->url(),
+                   info->GetWebContentsGetterForRequest()));
+    Cancel();
+  }
+}
+
+const char* ResourceThrottle::GetNameForLogging() const {
+  return "offline_pages::downloads::ResourceThrottle";
+}
+
+}  // namespace downloads
+}  // namespace offline_pages
diff --git a/chrome/browser/android/offline_pages/downloads/resource_throttle.h b/chrome/browser/android/offline_pages/downloads/resource_throttle.h
new file mode 100644
index 0000000..3bf5fd5
--- /dev/null
+++ b/chrome/browser/android/offline_pages/downloads/resource_throttle.h
@@ -0,0 +1,38 @@
+// 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 CHROME_BROWSER_ANDROID_OFFLINE_PAGES_DOWNLOADS_RESOURCE_THROTTLE_H_
+#define CHROME_BROWSER_ANDROID_OFFLINE_PAGES_DOWNLOADS_RESOURCE_THROTTLE_H_
+
+#include "content/public/browser/resource_throttle.h"
+#include "net/url_request/url_request.h"
+
+namespace offline_pages {
+namespace downloads {
+
+// This ResourceThrottle is used to hook up into the loading process at the
+// moment when headers are available (WillProcessResponse) to determine if the
+// download has text/html mime type and should be canceled as a download and
+// re-scheduled as a OfflinePage download request. This will be handled by
+// Offline Page backend as a full page download rather than a single .html
+// file download.
+class ResourceThrottle : public content::ResourceThrottle {
+ public:
+  explicit ResourceThrottle(const net::URLRequest* request);
+  ~ResourceThrottle() override;
+
+  // content::ResourceThrottle implementation:
+  void WillProcessResponse(bool* defer) override;
+  const char* GetNameForLogging() const override;
+
+ private:
+  const net::URLRequest* request_;
+
+  DISALLOW_COPY_AND_ASSIGN(ResourceThrottle);
+};
+
+}  // namespace downloads
+}  // namespace offline_pages
+
+#endif  // CHROME_BROWSER_ANDROID_OFFLINE_PAGES_DOWNLOADS_RESOURCE_THROTTLE_H_
diff --git a/chrome/browser/android/offline_pages/downloads/resource_throttle_unittest.cc b/chrome/browser/android/offline_pages/downloads/resource_throttle_unittest.cc
new file mode 100644
index 0000000..b6b617a
--- /dev/null
+++ b/chrome/browser/android/offline_pages/downloads/resource_throttle_unittest.cc
@@ -0,0 +1,100 @@
+// 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 "chrome/browser/android/offline_pages/downloads/resource_throttle.h"
+
+#include "base/run_loop.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "chrome/browser/android/offline_pages/offline_page_model_factory.h"
+#include "chrome/browser/android/offline_pages/offline_page_utils.h"
+#include "chrome/browser/android/offline_pages/request_coordinator_factory.h"
+#include "chrome/browser/android/offline_pages/test_offline_page_model_builder.h"
+#include "chrome/browser/android/offline_pages/test_request_coordinator_builder.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "components/offline_pages/core/background/request_coordinator.h"
+#include "components/offline_pages/core/offline_page_item.h"
+#include "components/offline_pages/core/offline_page_model.h"
+#include "components/offline_pages/core/offline_page_test_archiver.h"
+#include "content/public/browser/web_contents.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const GURL kTestPageUrl("http://mystery.site/foo.html");
+const char kClientNamespace[] = "download";
+
+}  // namespace
+
+namespace offline_pages {
+namespace downloads {
+
+class ResourceThrottleTest : public ChromeRenderViewHostTestHarness {
+ public:
+  ResourceThrottleTest();
+  ~ResourceThrottleTest() override;
+
+  void SetUp() override;
+
+  // Runs default thread.
+  void RunUntilIdle();
+
+  const std::vector<std::unique_ptr<SavePageRequest>>& last_requests() const {
+    return last_requests_;
+  }
+
+  // Callback for getting requests.
+  void GetRequestsDone(GetRequestsResult result,
+                       std::vector<std::unique_ptr<SavePageRequest>> requests);
+
+ private:
+  GetRequestsResult last_get_requests_result_;
+  std::vector<std::unique_ptr<SavePageRequest>> last_requests_;
+};
+
+ResourceThrottleTest::ResourceThrottleTest() {}
+
+ResourceThrottleTest::~ResourceThrottleTest() {}
+
+void ResourceThrottleTest::SetUp() {
+  ChromeRenderViewHostTestHarness::SetUp();
+
+  OfflinePageModelFactory::GetInstance()->SetTestingFactoryAndUse(
+      browser_context(), BuildTestOfflinePageModel);
+  RunUntilIdle();
+  RequestCoordinatorFactory::GetInstance()->SetTestingFactoryAndUse(
+      browser_context(), BuildTestRequestCoordinator);
+  RunUntilIdle();
+}
+
+void ResourceThrottleTest::RunUntilIdle() {
+  base::RunLoop().RunUntilIdle();
+}
+
+void ResourceThrottleTest::GetRequestsDone(
+    GetRequestsResult result,
+    std::vector<std::unique_ptr<SavePageRequest>> requests) {
+  last_get_requests_result_ = result;
+  last_requests_ = std::move(requests);
+}
+
+TEST_F(ResourceThrottleTest, StartOfflinePageDownload) {
+  OfflinePageUtils::StartOfflinePageDownload(browser_context(), kTestPageUrl);
+  RequestCoordinator* request_coordinator =
+      RequestCoordinatorFactory::GetForBrowserContext(browser_context());
+
+  request_coordinator->queue()->GetRequests(base::Bind(
+      &ResourceThrottleTest::GetRequestsDone, base::Unretained(this)));
+
+  // Wait for callbacks to finish, both request queue and offliner.
+  RunUntilIdle();
+
+  // Check the request queue is as expected.
+  EXPECT_EQ(1UL, last_requests().size());
+  EXPECT_EQ(kTestPageUrl, last_requests().at(0)->url());
+  EXPECT_EQ(kClientNamespace, last_requests().at(0)->client_id().name_space);
+}
+
+}  // namespace downloads
+}  // namespace offline_pages
diff --git a/chrome/browser/android/offline_pages/offline_page_utils.cc b/chrome/browser/android/offline_pages/offline_page_utils.cc
index 01ac502..2a6afa6 100644
--- a/chrome/browser/android/offline_pages/offline_page_utils.cc
+++ b/chrome/browser/android/offline_pages/offline_page_utils.cc
@@ -5,12 +5,14 @@
 #include "chrome/browser/android/offline_pages/offline_page_utils.h"
 
 #include "base/bind.h"
+#include "base/guid.h"
 #include "base/location.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
+#include "chrome/browser/android/offline_pages/downloads/offline_page_notification_bridge.h"
 #include "chrome/browser/android/offline_pages/offline_page_mhtml_archiver.h"
 #include "chrome/browser/android/offline_pages/offline_page_model_factory.h"
 #include "chrome/browser/android/offline_pages/offline_page_tab_helper.h"
@@ -220,4 +222,25 @@
   return lhs_stripped == rhs_stripped;
 }
 
+// static
+void OfflinePageUtils::StartOfflinePageDownload(
+    content::BrowserContext* context,
+    const GURL& url) {
+  RequestCoordinator* request_coordinator =
+      RequestCoordinatorFactory::GetForBrowserContext(context);
+
+  // TODO(dimich): Enable in Incognito when Android Downloads implement
+  // Incognito story.
+  if (!request_coordinator)
+    return;
+
+  ClientId client_id(kDownloadNamespace, base::GenerateGUID());
+  request_coordinator->SavePageLater(
+      url, client_id, true,
+      RequestCoordinator::RequestAvailability::ENABLED_FOR_OFFLINER);
+
+  android::OfflinePageNotificationBridge notification_bridge;
+  notification_bridge.ShowDownloadingToast();
+}
+
 }  // namespace offline_pages
diff --git a/chrome/browser/android/offline_pages/offline_page_utils.h b/chrome/browser/android/offline_pages/offline_page_utils.h
index 9e7e292..60f94179 100644
--- a/chrome/browser/android/offline_pages/offline_page_utils.h
+++ b/chrome/browser/android/offline_pages/offline_page_utils.h
@@ -88,6 +88,9 @@
       const PagesExistCallback& callback);
 
   static bool EqualsIgnoringFragment(const GURL& lhs, const GURL& rhs);
+
+  static void StartOfflinePageDownload(content::BrowserContext* context,
+                                       const GURL& url);
 };
 
 }  // namespace offline_pages
diff --git a/chrome/browser/android/search_geolocation_disclosure_tab_helper.cc b/chrome/browser/android/search_geolocation_disclosure_tab_helper.cc
index 30d9e8c..c671b62 100644
--- a/chrome/browser/android/search_geolocation_disclosure_tab_helper.cc
+++ b/chrome/browser/android/search_geolocation_disclosure_tab_helper.cc
@@ -138,6 +138,10 @@
   if (!Java_GeolocationHeader_hasGeolocationPermission(env))
     return;
 
+  // Record metrics for the state of permissions before the disclosure has been
+  // shown.
+  RecordPreDisclosureMetrics(gurl);
+
   // Only show the disclosure if the geolocation permission is set to ASK
   // (i.e. has not been explicitly set or revoked).
   blink::mojom::PermissionStatus status =
@@ -147,10 +151,6 @@
   if (status != blink::mojom::PermissionStatus::ASK)
     return;
 
-  // Record metrics for the state of permissions before the disclosure has been
-  // shown.
-  RecordPreDisclosureMetrics(gurl);
-
   // All good, let's show the disclosure and increment the shown count.
   SearchGeolocationDisclosureInfoBarDelegate::Create(web_contents(), gurl);
   shown_count++;
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 3b11be61..62190b9 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -546,8 +546,10 @@
         <include name="IDR_SOUND_PASSTHROUGH_WAV" file="resources\chromeos\sounds\earcons\passthrough.wav" type="BINDATA" />
         <include name="IDR_SOUND_EXIT_SCREEN_WAV" file="resources\chromeos\sounds\earcons\exit_screen.wav" type="BINDATA" />
         <include name="IDR_SOUND_ENTER_SCREEN_WAV" file="resources\chromeos\sounds\earcons\enter_screen.wav" type="BINDATA" />
+        <include name="IDR_SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_HIGH_WAV" file="resources\chromeos\sounds\spoken_feedback_toggle_countdown_high.wav" type="BINDATA" />
+        <include name="IDR_SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_LOW_WAV" file="resources\chromeos\sounds\spoken_feedback_toggle_countdown_low.wav" type="BINDATA" />
       </if>
-      <if expr="chromeos">
+     <if expr="chromeos">
         <include name="IDR_ABOUT_POWER_HTML" file="resources\chromeos\power.html" type="BINDATA" />
         <include name="IDR_ABOUT_POWER_JS" file="resources\chromeos\power.js" type="BINDATA" />
         <include name="IDR_ABOUT_POWER_CSS" file="resources\chromeos\power.css" type="BINDATA" />
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
index 744d724..cf8a8b2 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.cc
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
@@ -39,6 +39,8 @@
 #include "chrome/browser/chromeos/accessibility/accessibility_highlight_manager.h"
 #include "chrome/browser/chromeos/accessibility/magnification_manager.h"
 #include "chrome/browser/chromeos/accessibility/select_to_speak_event_handler.h"
+#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
+#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/ui/accessibility_focus_ring_controller.h"
 #include "chrome/browser/extensions/api/braille_display_private/stub_braille_controller.h"
@@ -296,6 +298,12 @@
                       bundle.GetRawDataResource(IDR_SOUND_EXIT_SCREEN_WAV));
   manager->Initialize(SOUND_ENTER_SCREEN,
                       bundle.GetRawDataResource(IDR_SOUND_ENTER_SCREEN_WAV));
+  manager->Initialize(SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_HIGH,
+                      bundle.GetRawDataResource(
+                          IDR_SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_HIGH_WAV));
+  manager->Initialize(SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_LOW,
+                      bundle.GetRawDataResource(
+                          IDR_SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_LOW_WAV));
 
   base::FilePath resources_path;
   if (!PathService::Get(chrome::DIR_RESOURCES, &resources_path))
@@ -552,6 +560,35 @@
   return media::SoundsManager::Get()->Play(sound_key);
 }
 
+bool AccessibilityManager::ShouldToggleSpokenFeedbackViaTouch() {
+  policy::BrowserPolicyConnectorChromeOS* connector =
+      g_browser_process->platform_part()->browser_policy_connector_chromeos();
+  if (!connector)
+    return false;
+
+  if (!connector->IsEnterpriseManaged())
+    return false;
+
+  const policy::DeviceCloudPolicyManagerChromeOS* const
+      device_cloud_policy_manager = connector->GetDeviceCloudPolicyManager();
+  if (!device_cloud_policy_manager)
+    return false;
+
+  if (!device_cloud_policy_manager->IsRemoraRequisition())
+    return false;
+
+  KioskAppManager* manager = KioskAppManager::Get();
+  KioskAppManager::App app;
+  CHECK(manager->GetApp(manager->GetAutoLaunchApp(), &app));
+  return app.was_auto_launched_with_zero_delay;
+}
+
+bool AccessibilityManager::PlaySpokenFeedbackToggleCountdown(int tick_count) {
+  return media::SoundsManager::Get()->Play(
+      tick_count % 2 ? SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_HIGH
+                     : SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_LOW);
+}
+
 void AccessibilityManager::HandleAccessibilityGesture(ui::AXGesture gesture) {
   extensions::EventRouter* event_router =
       extensions::EventRouter::Get(profile());
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.h b/chrome/browser/chromeos/accessibility/accessibility_manager.h
index 916a336..87684cb 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.h
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.h
@@ -250,6 +250,13 @@
   // Notify accessibility when locale changes occur.
   void OnLocaleChanged();
 
+  // Whether or not to enable toggling spoken feedback via holding down
+  // two fingers on the screen.
+  bool ShouldToggleSpokenFeedbackViaTouch();
+
+  // Play tick sound indicating spoken feedback will be toggled after countdown.
+  bool PlaySpokenFeedbackToggleCountdown(int tick_count);
+
   // Plays an earcon. Earcons are brief and distinctive sounds that indicate
   // when their mapped event has occurred. The sound key enums can be found in
   // chromeos/audio/chromeos_sounds.h.
diff --git a/chrome/browser/chromeos/profiles/profile_helper.cc b/chrome/browser/chromeos/profiles/profile_helper.cc
index 96fef2b..22876498 100644
--- a/chrome/browser/chromeos/profiles/profile_helper.cc
+++ b/chrome/browser/chromeos/profiles/profile_helper.cc
@@ -366,9 +366,11 @@
     return user_manager->GetActiveUser();
   }
 
+  // Finds the matching user in logged-in user list since only a logged-in
+  // user would have a profile.
   const std::string username_hash =
       ProfileHelper::GetUserIdHashFromProfile(profile);
-  const user_manager::UserList& users = user_manager->GetUsers();
+  const user_manager::UserList& users = user_manager->GetLoggedInUsers();
   const user_manager::UserList::const_iterator pos = std::find_if(
       users.begin(), users.end(), UsernameHashMatcher(username_hash));
   if (pos != users.end())
diff --git a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc
index 701a7153..840f60d3 100644
--- a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc
+++ b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc
@@ -29,6 +29,7 @@
 #include "chrome/browser/ui/proximity_auth/proximity_auth_error_bubble.h"
 #include "chrome/common/extensions/api/easy_unlock_private.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/cryptauth/bluetooth_throttler_impl.h"
 #include "components/cryptauth/cryptauth_device_manager.h"
 #include "components/cryptauth/cryptauth_enrollment_manager.h"
 #include "components/cryptauth/cryptauth_enrollment_utils.h"
@@ -37,7 +38,6 @@
 #include "components/cryptauth/secure_message_delegate.h"
 #include "components/proximity_auth/ble/bluetooth_low_energy_connection.h"
 #include "components/proximity_auth/ble/bluetooth_low_energy_connection_finder.h"
-#include "components/proximity_auth/bluetooth_throttler_impl.h"
 #include "components/proximity_auth/bluetooth_util.h"
 #include "components/proximity_auth/logging/logging.h"
 #include "components/proximity_auth/proximity_auth_client.h"
@@ -1050,7 +1050,7 @@
 
 EasyUnlockPrivateFindSetupConnectionFunction::
     EasyUnlockPrivateFindSetupConnectionFunction()
-    : bluetooth_throttler_(new proximity_auth::BluetoothThrottlerImpl(
+    : bluetooth_throttler_(new cryptauth::BluetoothThrottlerImpl(
           base::MakeUnique<base::DefaultTickClock>())) {}
 
 EasyUnlockPrivateFindSetupConnectionFunction::
@@ -1069,7 +1069,7 @@
 }
 
 void EasyUnlockPrivateFindSetupConnectionFunction::OnConnectionFound(
-    std::unique_ptr<proximity_auth::Connection> connection) {
+    std::unique_ptr<cryptauth::Connection> connection) {
   // Connection are not persistent by default.
   std::string device_address = connection->remote_device().bluetooth_address;
   bool persistent = false;
diff --git a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.h b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.h
index 7285b2c..9141650 100644
--- a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.h
+++ b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.h
@@ -28,14 +28,14 @@
 }
 
 namespace cryptauth {
+class BluetoothThrottler;
+class Connection;
 class ExternalDeviceInfo;
 class SecureMessageDelegate;
 }
 
 namespace proximity_auth {
-class Connection;
 class BluetoothLowEnergyConnectionFinder;
-class BluetoothThrottler;
 }
 
 namespace extensions {
@@ -477,8 +477,7 @@
 
   // Called when the connection with the remote device advertising the setup
   // service was found.
-  void OnConnectionFound(
-      std::unique_ptr<proximity_auth::Connection> connection);
+  void OnConnectionFound(std::unique_ptr<cryptauth::Connection> connection);
 
   // Callback when waiting for |connection_finder_| to return.
   void OnConnectionFinderTimedOut();
@@ -488,7 +487,7 @@
       connection_finder_;
 
   // The connection throttler passed to the BLE connection finder.
-  std::unique_ptr<proximity_auth::BluetoothThrottler> bluetooth_throttler_;
+  std::unique_ptr<cryptauth::BluetoothThrottler> bluetooth_throttler_;
 
   // Used for timing out when waiting for the connection finder to return.
   std::unique_ptr<base::Timer> timer_;
diff --git a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_connection.cc b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_connection.cc
index c6265f5a..88fe91b 100644
--- a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_connection.cc
+++ b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_connection.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_connection.h"
 
 #include "base/lazy_instance.h"
-#include "components/proximity_auth/connection.h"
+#include "components/cryptauth/connection.h"
 
 namespace extensions {
 
@@ -22,14 +22,14 @@
 EasyUnlockPrivateConnection::EasyUnlockPrivateConnection(
     bool persistent,
     const std::string& owner_extension_id,
-    std::unique_ptr<proximity_auth::Connection> connection)
+    std::unique_ptr<cryptauth::Connection> connection)
     : ApiResource(owner_extension_id),
       persistent_(persistent),
       connection_(connection.release()) {}
 
 EasyUnlockPrivateConnection::~EasyUnlockPrivateConnection() {}
 
-proximity_auth::Connection* EasyUnlockPrivateConnection::GetConnection() const {
+cryptauth::Connection* EasyUnlockPrivateConnection::GetConnection() const {
   return connection_.get();
 }
 
diff --git a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_connection.h b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_connection.h
index f72f2a7..9c42c0c4 100644
--- a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_connection.h
+++ b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_connection.h
@@ -11,22 +11,22 @@
 #include "extensions/browser/api/api_resource.h"
 #include "extensions/browser/api/api_resource_manager.h"
 
-namespace proximity_auth {
+namespace cryptauth {
 class Connection;
-}  // namespace proximity_auth
+}  // namespace cryptauth
 
 namespace extensions {
-// An ApiResource wrapper for a proximity_auth::Connection.
+// An ApiResource wrapper for a cryptauth::Connection.
 class EasyUnlockPrivateConnection : public ApiResource {
  public:
   EasyUnlockPrivateConnection(
       bool persistent,
       const std::string& owner_extension_id,
-      std::unique_ptr<proximity_auth::Connection> connection);
+      std::unique_ptr<cryptauth::Connection> connection);
   ~EasyUnlockPrivateConnection() override;
 
   // Returns a pointer to the underlying connection object.
-  proximity_auth::Connection* GetConnection() const;
+  cryptauth::Connection* GetConnection() const;
 
   // ApiResource override.
   bool IsPersistent() const override;
@@ -46,7 +46,7 @@
 
   // The connection is owned by this instance and will automatically disconnect
   // when deleted.
-  std::unique_ptr<proximity_auth::Connection> connection_;
+  std::unique_ptr<cryptauth::Connection> connection_;
 
   DISALLOW_COPY_AND_ASSIGN(EasyUnlockPrivateConnection);
 };
diff --git a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_connection_manager.cc b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_connection_manager.cc
index 285ccc0d..9d2923b 100644
--- a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_connection_manager.cc
+++ b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_connection_manager.cc
@@ -10,12 +10,12 @@
 #include "base/memory/ptr_util.h"
 #include "chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_connection.h"
 #include "chrome/common/extensions/api/easy_unlock_private.h"
-#include "components/proximity_auth/connection.h"
-#include "components/proximity_auth/wire_message.h"
+#include "components/cryptauth/connection.h"
+#include "components/cryptauth/wire_message.h"
 #include "extensions/browser/event_router.h"
 
-using proximity_auth::Connection;
-using proximity_auth::WireMessage;
+using cryptauth::Connection;
+using cryptauth::WireMessage;
 
 namespace extensions {
 namespace {
diff --git a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_connection_manager.h b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_connection_manager.h
index be4e4ac..a6d93474 100644
--- a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_connection_manager.h
+++ b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_connection_manager.h
@@ -12,9 +12,9 @@
 #include "base/macros.h"
 #include "chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_connection.h"
 #include "chrome/common/extensions/api/easy_unlock_private.h"
-#include "components/proximity_auth/connection.h"
-#include "components/proximity_auth/connection_observer.h"
-#include "components/proximity_auth/wire_message.h"
+#include "components/cryptauth/connection.h"
+#include "components/cryptauth/connection_observer.h"
+#include "components/cryptauth/wire_message.h"
 
 namespace content {
 class BrowserContext;
@@ -25,9 +25,9 @@
 class Extension;
 
 // EasyUnlockPrivateConnectionManager is used by the EasyUnlockPrivateAPI to
-// interface with proximity_auth::Connection.
+// interface with cryptauth::Connection.
 class EasyUnlockPrivateConnectionManager
-    : public proximity_auth::ConnectionObserver {
+    : public cryptauth::ConnectionObserver {
  public:
   explicit EasyUnlockPrivateConnectionManager(content::BrowserContext* context);
   ~EasyUnlockPrivateConnectionManager() override;
@@ -35,7 +35,7 @@
   // Stores |connection| in the API connection manager. Returns the
   // |connection_id|.
   int AddConnection(const Extension* extension,
-                    std::unique_ptr<proximity_auth::Connection> connection,
+                    std::unique_ptr<cryptauth::Connection> connection,
                     bool persistent);
 
   // Returns the status of the connection with |connection_id|.
@@ -58,15 +58,15 @@
   std::string GetDeviceAddress(const Extension* extension,
                                int connection_id) const;
 
-  // proximity_auth::ConnectionObserver:
+  // cryptauth::ConnectionObserver:
   void OnConnectionStatusChanged(
-      proximity_auth::Connection* connection,
-      proximity_auth::Connection::Status old_status,
-      proximity_auth::Connection::Status new_status) override;
-  void OnMessageReceived(const proximity_auth::Connection& connection,
-                         const proximity_auth::WireMessage& message) override;
-  void OnSendCompleted(const proximity_auth::Connection& connection,
-                       const proximity_auth::WireMessage& message,
+      cryptauth::Connection* connection,
+      cryptauth::Connection::Status old_status,
+      cryptauth::Connection::Status new_status) override;
+  void OnMessageReceived(const cryptauth::Connection& connection,
+                         const cryptauth::WireMessage& message) override;
+  void OnSendCompleted(const cryptauth::Connection& connection,
+                       const cryptauth::WireMessage& message,
                        bool success) override;
 
  private:
@@ -75,7 +75,7 @@
   // in |args| with it.
   void DispatchConnectionEvent(const std::string& event_name,
                                events::HistogramValue histogram_value,
-                               const proximity_auth::Connection* connection,
+                               const cryptauth::Connection* connection,
                                std::unique_ptr<base::ListValue> args);
 
   // Convenience method to get the API resource manager.
@@ -83,13 +83,13 @@
 
   // Convenience method to get the connection with |connection_id| created by
   // extension with |extension_id| from the API resource manager.
-  proximity_auth::Connection* GetConnection(const std::string& extension_id,
-                                            int connection_id) const;
+  cryptauth::Connection* GetConnection(const std::string& extension_id,
+                                       int connection_id) const;
 
   // Find the connection_id for |connection| owned by |extension_id| from the
   // API resource manager.
   int FindConnectionId(const std::string& extension_id,
-                       const proximity_auth::Connection* connection);
+                       const cryptauth::Connection* connection);
 
   // BrowserContext passed during initialization.
   content::BrowserContext* browser_context_;
diff --git a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
index 34440ad..1cccec5 100644
--- a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
+++ b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
@@ -108,6 +108,10 @@
 #include "components/navigation_interception/intercept_navigation_delegate.h"
 #endif
 
+#if BUILDFLAG(ANDROID_JAVA_UI)
+#include "chrome/browser/android/offline_pages/downloads/resource_throttle.h"
+#endif
+
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/login/signin/merge_session_resource_throttle.h"
 #include "chrome/browser/chromeos/login/signin/merge_session_throttling_utils.h"
@@ -545,6 +549,11 @@
                                     resource_context,
                                     content::RESOURCE_TYPE_MAIN_FRAME,
                                     throttles);
+#if BUILDFLAG(ANDROID_JAVA_UI)
+    // On Android, forward text/html downloads to OfflinePages backend.
+    throttles->push_back(
+        new offline_pages::downloads::ResourceThrottle(request));
+#endif
   }
 }
 
diff --git a/chrome/browser/media/webrtc/media_permission.cc b/chrome/browser/media/webrtc/media_permission.cc
index 23b1fb1e..d05a130 100644
--- a/chrome/browser/media/webrtc/media_permission.cc
+++ b/chrome/browser/media/webrtc/media_permission.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/media/webrtc/media_permission.h"
 
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
-#include "chrome/browser/media/webrtc/media_stream_device_permission_context.h"
 #include "chrome/browser/media/webrtc/media_stream_device_permissions.h"
 #include "chrome/browser/permissions/permission_context_base.h"
 #include "chrome/browser/permissions/permission_manager.h"
@@ -15,6 +14,7 @@
 #include "content/public/browser/permission_type.h"
 #include "content/public/common/url_constants.h"
 #include "extensions/common/constants.h"
+#include "third_party/WebKit/public/platform/modules/permissions/permission_status.mojom.h"
 
 namespace {
 
@@ -48,36 +48,32 @@
     return CONTENT_SETTING_BLOCK;
   }
 
-  // Use the Permission Context to find out if the kill switch is on. Set the
-  // denial reason to kill switch.
   content::PermissionType permission_type =
       ContentSettingsTypeToPermission(content_type_);
-  // TODO(raymes): This calls into GetPermissionContext which is a private
-  // member of PermissionManager. Remove this call when this class is refactored
-  // into a PermissionContext. See crbug.com/596786.
-  PermissionContextBase* permission_context =
-      PermissionManager::Get(profile_)->GetPermissionContext(permission_type);
+  PermissionManager* permission_manager = PermissionManager::Get(profile_);
 
-  if (!permission_context) {
-    *denial_reason = content::MEDIA_DEVICE_PERMISSION_DENIED;
-    return CONTENT_SETTING_BLOCK;
-  }
-
-  MediaStreamDevicePermissionContext* media_device_permission_context =
-      static_cast<MediaStreamDevicePermissionContext*>(permission_context);
-
-  if (media_device_permission_context->IsPermissionKillSwitchOn()) {
+  // Find out if the kill switch is on. Set the denial reason to kill switch.
+  if (permission_manager->IsPermissionKillSwitchOn(permission_type)) {
     *denial_reason = content::MEDIA_DEVICE_KILL_SWITCH_ON;
     return CONTENT_SETTING_BLOCK;
   }
 
   // Check policy and content settings.
-  ContentSetting result =
-      GetStoredContentSetting(media_device_permission_context);
-  if (result == CONTENT_SETTING_BLOCK)
-    *denial_reason = content::MEDIA_DEVICE_PERMISSION_DENIED;
+  blink::mojom::PermissionStatus status =
+      permission_manager->GetPermissionStatus(
+          permission_type, requesting_origin_, embedding_origin_);
+  switch (status) {
+    case blink::mojom::PermissionStatus::DENIED:
+      *denial_reason = content::MEDIA_DEVICE_PERMISSION_DENIED;
+      return CONTENT_SETTING_BLOCK;
+    case blink::mojom::PermissionStatus::ASK:
+      return CONTENT_SETTING_ASK;
+    case blink::mojom::PermissionStatus::GRANTED:
+      return CONTENT_SETTING_ALLOW;
+  }
 
-  return result;
+  NOTREACHED();
+  return CONTENT_SETTING_BLOCK;
 }
 
 ContentSetting MediaPermission::GetPermissionStatusWithDeviceRequired(
@@ -93,12 +89,6 @@
   return GetPermissionStatus(denial_reason);
 }
 
-ContentSetting MediaPermission::GetStoredContentSetting(
-    MediaStreamDevicePermissionContext* media_device_permission_context) const {
-  return media_device_permission_context->GetPermissionStatus(
-      requesting_origin_, embedding_origin_);
-}
-
 bool MediaPermission::HasAvailableDevices(const std::string& device_id) const {
   const content::MediaStreamDevices* devices = nullptr;
   if (content_type_ == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) {
diff --git a/chrome/browser/media/webrtc/media_permission.h b/chrome/browser/media/webrtc/media_permission.h
index 5f1a100..708ae39 100644
--- a/chrome/browser/media/webrtc/media_permission.h
+++ b/chrome/browser/media/webrtc/media_permission.h
@@ -13,7 +13,6 @@
 #include "content/public/common/media_stream_request.h"
 #include "url/gurl.h"
 
-class MediaStreamDevicePermissionContext;
 class Profile;
 
 // Represents a permission for microphone/camera access.
@@ -37,9 +36,6 @@
       content::MediaStreamRequestResult* denial_reason) const;
 
  private:
-  ContentSetting GetStoredContentSetting(
-      MediaStreamDevicePermissionContext* media_device_permission_context)
-      const;
   bool HasAvailableDevices(const std::string& device_id) const;
 
   const ContentSettingsType content_type_;
diff --git a/chrome/browser/permissions/permission_manager.cc b/chrome/browser/permissions/permission_manager.cc
index 9925c5a..65f7131 100644
--- a/chrome/browser/permissions/permission_manager.cc
+++ b/chrome/browser/permissions/permission_manager.cc
@@ -156,11 +156,6 @@
   }
 }
 
-PermissionStatus GetPermissionStatusForConstantPermission(PermissionType type) {
-  return ContentSettingToPermissionStatus(
-      GetContentSettingForConstantPermission(type));
-}
-
 }  // anonymous namespace
 
 class PermissionManager::PendingRequest {
@@ -394,15 +389,8 @@
     const GURL& requesting_origin,
     const GURL& embedding_origin) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  if (IsConstantPermission(permission))
-    return GetPermissionStatusForConstantPermission(permission);
-
-  PermissionContextBase* context = GetPermissionContext(permission);
-  if (!context)
-    return PermissionStatus::DENIED;
-
-  return ContentSettingToPermissionStatus(context->GetPermissionStatus(
-      requesting_origin.GetOrigin(), embedding_origin.GetOrigin()));
+  return ContentSettingToPermissionStatus(GetPermissionStatusInternal(
+      permission, requesting_origin, embedding_origin));
 }
 
 void PermissionManager::RegisterPermissionUsage(PermissionType permission,
@@ -435,15 +423,8 @@
   subscription->embedding_origin = embedding_origin;
   subscription->callback = callback;
 
-  if (IsConstantPermission(permission)) {
-    subscription->current_value = GetContentSettingForConstantPermission(
-        permission);
-  } else {
-    subscription->current_value =
-        GetPermissionContext(permission)
-            ->GetPermissionStatus(subscription->requesting_origin,
-                                  subscription->embedding_origin);
-  }
+  subscription->current_value = GetPermissionStatusInternal(
+      permission, requesting_origin, embedding_origin);
 
   return subscriptions_.Add(std::move(subscription));
 }
@@ -458,6 +439,12 @@
         ->RemoveObserver(this);
 }
 
+bool PermissionManager::IsPermissionKillSwitchOn(
+    content::PermissionType permission) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  return GetPermissionContext(permission)->IsPermissionKillSwitchOn();
+}
+
 void PermissionManager::OnContentSettingChanged(
     const ContentSettingsPattern& primary_pattern,
     const ContentSettingsPattern& secondary_pattern,
@@ -483,10 +470,9 @@
         !secondary_pattern.Matches(subscription->embedding_origin))
       continue;
 
-    ContentSetting new_value =
-        GetPermissionContext(subscription->permission)
-            ->GetPermissionStatus(subscription->requesting_origin,
-                                  subscription->embedding_origin);
+    ContentSetting new_value = GetPermissionStatusInternal(
+        subscription->permission, subscription->requesting_origin,
+        subscription->embedding_origin);
     if (subscription->current_value == new_value)
       continue;
 
@@ -502,3 +488,15 @@
   for (const auto& callback : callbacks)
     callback.Run();
 }
+
+ContentSetting PermissionManager::GetPermissionStatusInternal(
+    PermissionType permission,
+    const GURL& requesting_origin,
+    const GURL& embedding_origin) {
+  if (IsConstantPermission(permission))
+    return GetContentSettingForConstantPermission(permission);
+
+  PermissionContextBase* context = GetPermissionContext(permission);
+  return context->GetPermissionStatus(requesting_origin.GetOrigin(),
+                                      embedding_origin.GetOrigin());
+}
diff --git a/chrome/browser/permissions/permission_manager.h b/chrome/browser/permissions/permission_manager.h
index bd90dcf2..bc7e040 100644
--- a/chrome/browser/permissions/permission_manager.h
+++ b/chrome/browser/permissions/permission_manager.h
@@ -68,11 +68,13 @@
       override;
   void UnsubscribePermissionStatusChange(int subscription_id) override;
 
+  // TODO(raymes): Rather than exposing this, expose a denial reason from
+  // GetPermissionStatus so that callers can determine whether a permission is
+  // denied due to the kill switch.
+  bool IsPermissionKillSwitchOn(content::PermissionType permission);
+
  private:
   friend class GeolocationPermissionContextTests;
-  // TODO(raymes): Refactor MediaPermission to not call GetPermissionContext.
-  // See crbug.com/596786.
-  friend class MediaPermission;
 
   class PendingRequest;
   using PendingRequestsMap = IDMap<std::unique_ptr<PendingRequest>>;
@@ -99,6 +101,10 @@
                                ContentSettingsType content_type,
                                std::string resource_identifier) override;
 
+  ContentSetting GetPermissionStatusInternal(content::PermissionType permission,
+                                             const GURL& requesting_origin,
+                                             const GURL& embedding_origin);
+
   Profile* profile_;
   PendingRequestsMap pending_requests_;
   SubscriptionsMap subscriptions_;
diff --git a/chrome/browser/resources/bluetooth_internals/adapter_broker.js b/chrome/browser/resources/bluetooth_internals/adapter_broker.js
index c1cf8fa..13a8eee 100644
--- a/chrome/browser/resources/bluetooth_internals/adapter_broker.js
+++ b/chrome/browser/resources/bluetooth_internals/adapter_broker.js
@@ -15,7 +15,7 @@
    * handles and back when necessary.
    * @constructor
    * @extends {cr.EventTarget}
-   * @param {!interfaces.BluetoothAdapter.Adapter.proxyClass} adapter
+   * @param {!interfaces.BluetoothAdapter.AdapterPtr} adapter
    */
   var AdapterBroker = function(adapter) {
     this.adapter_ = adapter;
@@ -29,7 +29,7 @@
     /**
      * Creates a GATT connection to the device with |address|.
      * @param {string} address
-     * @return {!Promise<!interfaces.BluetoothDevice.Device.proxyClass>}
+     * @return {!Promise<!interfaces.BluetoothDevice.DevicePtr>}
      */
     connectToDevice: function(address) {
       return this.adapter_.connectToDevice(address).then(function(response) {
@@ -45,9 +45,7 @@
           throw new Error(errorString);
         }
 
-        return interfaces.Connection.bindHandleToProxy(
-            response.device.ptr.passInterface().handle,
-            interfaces.BluetoothDevice.Device);
+        return response.device;
       });
     },
 
@@ -145,14 +143,9 @@
     if (adapterBroker) return Promise.resolve(adapterBroker);
 
     return interfaces.setupInterfaces().then(function(adapter) {
-      // Hook up the instance properties.
-      AdapterClient.prototype.__proto__ =
-          interfaces.BluetoothAdapter.AdapterClient.stubClass.prototype;
-
-      var adapterFactory = interfaces.Connection.bindHandleToProxy(
+      var adapterFactory = new interfaces.BluetoothAdapter.AdapterFactoryPtr(
           interfaces.FrameInterfaces.getInterface(
-              interfaces.BluetoothAdapter.AdapterFactory.name),
-          interfaces.BluetoothAdapter.AdapterFactory);
+              interfaces.BluetoothAdapter.AdapterFactory.name));
 
       // Get an Adapter service.
       return adapterFactory.getAdapter();
@@ -161,11 +154,7 @@
         throw new Error('Bluetooth Not Supported on this platform.');
       }
 
-      var adapter = interfaces.Connection.bindHandleToProxy(
-          response.adapter.ptr.passInterface().handle,
-          interfaces.BluetoothAdapter.Adapter);
-
-      adapterBroker = new AdapterBroker(adapter);
+      adapterBroker = new AdapterBroker(response.adapter);
       return adapterBroker;
     });
   }
diff --git a/chrome/browser/resources/bluetooth_internals/bluetooth_internals.js b/chrome/browser/resources/bluetooth_internals/bluetooth_internals.js
index f15709c2..950d79c 100644
--- a/chrome/browser/resources/bluetooth_internals/bluetooth_internals.js
+++ b/chrome/browser/resources/bluetooth_internals/bluetooth_internals.js
@@ -39,7 +39,7 @@
     },
   };
 
-  /** @type {!Map<string, !interfaces.BluetoothDevice.Device.proxyClass>} */
+  /** @type {!Map<string, !interfaces.BluetoothDevice.DevicePtr>} */
   var deviceAddressToProxy = new Map();
 
   /** @type {!device_collection.DeviceCollection} */
diff --git a/chrome/browser/resources/bluetooth_internals/interfaces.js b/chrome/browser/resources/bluetooth_internals/interfaces.js
index 0bbe9cb..20eb2b8b 100644
--- a/chrome/browser/resources/bluetooth_internals/interfaces.js
+++ b/chrome/browser/resources/bluetooth_internals/interfaces.js
@@ -26,13 +26,11 @@
         'device/bluetooth/public/interfaces/adapter.mojom',
         'device/bluetooth/public/interfaces/device.mojom',
         'mojo/public/js/bindings',
-        'mojo/public/js/connection',
       ]).then(function([frameInterfaces, bluetoothAdapter, bluetoothDevice,
-          bindings, connection]) {
+          bindings]) {
         interfaces.BluetoothAdapter = bluetoothAdapter;
         interfaces.BluetoothDevice = bluetoothDevice;
         interfaces.Bindings = bindings;
-        interfaces.Connection = connection;
         interfaces.FrameInterfaces = frameInterfaces;
       });
     });
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js
index 9f70869..3ae083c 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js
@@ -195,8 +195,11 @@
   }
 
   // Require a current range.
-  if (!ChromeVoxState.instance.currentRange_)
-    return true;
+  if (!ChromeVoxState.instance.currentRange_ ||
+      !ChromeVoxState.instance.currentRange_.isValid()) {
+    cvox.ChromeVox.tts.speak(Msgs.getMsg('no_focus'), cvox.QueueMode.FLUSH);
+    return false;
+  }
 
   // Next/classic compat commands hereafter.
   if (ChromeVoxState.instance.mode == ChromeVoxMode.CLASSIC ||
diff --git a/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd b/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd
index f78581d..64da50f7 100644
--- a/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd
+++ b/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd
@@ -2675,6 +2675,9 @@
       <message desc="Describes an audio clip that gets played for a specific event or control type. Use the default string as a guide to what the audio clip represents or conveys." name="IDS_CHROMEVOX_WRAP_EARCON_DESCRIPTION">
         Wrap from beginning to end or end to beginning inside of a page, dialog, or other container
       </message>
+      <message desc="Announced when ChromeVox has no item in focus." name="IDS_CHROMEVOX_NO_FOCUS">
+        No focus. Press Control N to open a new window.
+      </message>
     </messages>
   </release>
 </grit>
diff --git a/chrome/browser/resources/chromeos/sounds/spoken_feedback_toggle_countdown_high.wav b/chrome/browser/resources/chromeos/sounds/spoken_feedback_toggle_countdown_high.wav
new file mode 100644
index 0000000..12661f5
--- /dev/null
+++ b/chrome/browser/resources/chromeos/sounds/spoken_feedback_toggle_countdown_high.wav
Binary files differ
diff --git a/chrome/browser/resources/chromeos/sounds/spoken_feedback_toggle_countdown_low.wav b/chrome/browser/resources/chromeos/sounds/spoken_feedback_toggle_countdown_low.wav
new file mode 100644
index 0000000..e0f4f20
--- /dev/null
+++ b/chrome/browser/resources/chromeos/sounds/spoken_feedback_toggle_countdown_low.wav
Binary files differ
diff --git a/chrome/browser/resources/engagement/site_engagement.js b/chrome/browser/resources/engagement/site_engagement.js
index bd19f11..3557fd0 100644
--- a/chrome/browser/resources/engagement/site_engagement.js
+++ b/chrome/browser/resources/engagement/site_engagement.js
@@ -5,15 +5,13 @@
 'use strict';
 
 define('main', [
-    'mojo/public/js/connection',
     'chrome/browser/ui/webui/engagement/site_engagement.mojom',
     'content/public/renderer/frame_interfaces',
-], function(connection, siteEngagementMojom, frameInterfaces) {
+], function(siteEngagementMojom, frameInterfaces) {
   return function() {
-    var uiHandler = connection.bindHandleToProxy(
+    var uiHandler = new siteEngagementMojom.SiteEngagementUIHandlerPtr(
         frameInterfaces.getInterface(
-            siteEngagementMojom.SiteEngagementUIHandler.name),
-        siteEngagementMojom.SiteEngagementUIHandler);
+            siteEngagementMojom.SiteEngagementUIHandler.name));
 
     var engagementTableBody = $('engagement-table-body');
     var updateInterval = null;
diff --git a/chrome/browser/resources/omnibox/omnibox.js b/chrome/browser/resources/omnibox/omnibox.js
index 11c4a993..2570deb 100644
--- a/chrome/browser/resources/omnibox/omnibox.js
+++ b/chrome/browser/resources/omnibox/omnibox.js
@@ -416,18 +416,15 @@
   function initializeProxies() {
     return importModules([
       'mojo/public/js/bindings',
-      'mojo/public/js/connection',
       'chrome/browser/ui/webui/omnibox/omnibox.mojom',
       'content/public/renderer/frame_interfaces',
     ]).then(function(modules) {
       var bindings = modules[0];
-      var connection = modules[1];
-      var mojom = modules[2];
-      var frameInterfaces = modules[3];
+      var mojom = modules[1];
+      var frameInterfaces = modules[2];
 
-      browserProxy = connection.bindHandleToProxy(
-          frameInterfaces.getInterface(mojom.OmniboxPageHandler.name),
-          mojom.OmniboxPageHandler);
+      browserProxy = new mojom.OmniboxPageHandlerPtr(
+          frameInterfaces.getInterface(mojom.OmniboxPageHandler.name));
 
       /** @constructor */
       var OmniboxPageImpl = function() {
diff --git a/chrome/browser/resources/plugins.js b/chrome/browser/resources/plugins.js
index bffd6bb..f57f133 100644
--- a/chrome/browser/resources/plugins.js
+++ b/chrome/browser/resources/plugins.js
@@ -228,18 +228,15 @@
 function initializeProxies() {
   return importModules([
     'mojo/public/js/bindings',
-    'mojo/public/js/connection',
     'chrome/browser/ui/webui/plugins/plugins.mojom',
     'content/public/renderer/frame_interfaces',
   ]).then(function(modules) {
     var bindings = modules[0];
-    var connection = modules[1];
-    var pluginsMojom = modules[2];
-    var frameInterfaces = modules[3];
+    var pluginsMojom = modules[1];
+    var frameInterfaces = modules[2];
 
-    browserProxy = connection.bindHandleToProxy(
-        frameInterfaces.getInterface(pluginsMojom.PluginsPageHandler.name),
-        pluginsMojom.PluginsPageHandler);
+    browserProxy = new pluginsMojom.PluginsPageHandlerPtr(
+        frameInterfaces.getInterface(pluginsMojom.PluginsPageHandler.name));
 
     /** @constructor */
     var PluginsPageImpl = function() {
diff --git a/chrome/browser/resources/usb_internals/usb_internals.js b/chrome/browser/resources/usb_internals/usb_internals.js
index a1c1a28..bed9e59 100644
--- a/chrome/browser/resources/usb_internals/usb_internals.js
+++ b/chrome/browser/resources/usb_internals/usb_internals.js
@@ -61,17 +61,14 @@
 
   function initializeProxies() {
     return importModules([
-      'mojo/public/js/connection',
       'chrome/browser/ui/webui/usb_internals/usb_internals.mojom',
       'content/public/renderer/frame_interfaces',
     ]).then(function(modules) {
-      let connection = modules[0];
-      let mojom = modules[1];
-      let frameInterfaces = modules[2];
+      let mojom = modules[0];
+      let frameInterfaces = modules[1];
 
-      pageHandler = connection.bindHandleToProxy(
-          frameInterfaces.getInterface(mojom.UsbInternalsPageHandler.name),
-          mojom.UsbInternalsPageHandler);
+      pageHandler = new mojom.UsbInternalsPageHandlerPtr(
+          frameInterfaces.getInterface(mojom.UsbInternalsPageHandler.name));
     });
   }
 
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.cc b/chrome/browser/ui/ash/chrome_shell_delegate.cc
index 2f1d12e..a452d0a 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.cc
@@ -317,6 +317,16 @@
     return ash::A11Y_ALERT_NONE;
   }
 
+  bool ShouldToggleSpokenFeedbackViaTouch() override {
+    DCHECK(AccessibilityManager::Get());
+    return AccessibilityManager::Get()->ShouldToggleSpokenFeedbackViaTouch();
+  }
+
+  void PlaySpokenFeedbackToggleCountdown(int tick_count) override {
+    DCHECK(AccessibilityManager::Get());
+    AccessibilityManager::Get()->PlaySpokenFeedbackToggleCountdown(tick_count);
+  }
+
   void PlayEarcon(int sound_key) override {
     DCHECK(AccessibilityManager::Get());
     AccessibilityManager::Get()->PlayEarcon(
diff --git a/chrome/browser/ui/bluetooth/bluetooth_chooser_controller.h b/chrome/browser/ui/bluetooth/bluetooth_chooser_controller.h
index 6a6a0d65..a3daa026 100644
--- a/chrome/browser/ui/bluetooth/bluetooth_chooser_controller.h
+++ b/chrome/browser/ui/bluetooth/bluetooth_chooser_controller.h
@@ -22,7 +22,7 @@
 // access a Bluetooth device. It is owned by ChooserBubbleDelegate.
 class BluetoothChooserController : public ChooserController {
  public:
-  explicit BluetoothChooserController(
+  BluetoothChooserController(
       content::RenderFrameHost* owner,
       const content::BluetoothChooser::EventHandler& event_handler);
   ~BluetoothChooserController() override;
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h
index 4dd4adbb..a13ea94 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h
@@ -65,10 +65,10 @@
   // is hidden until its WebContents initially loads.
   bool DialogWasShown();
 
+ private:
   // Gets the dialog manager for |web_contents_|.
   web_modal::WebContentsModalDialogManager* GetDialogManager();
 
- private:
   ConstrainedWindowMacDelegate* delegate_;  // weak, owns us.
   SingleWebContentsDialogManagerCocoa* manager_;  // weak, owned by WCMDM.
   content::WebContents* web_contents_;  // weak, owned by dialog initiator.
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.mm
index c0aa06b..4df3304 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.mm
@@ -81,5 +81,12 @@
 
 WebContentsModalDialogManager* ConstrainedWindowMac::GetDialogManager() {
   DCHECK(web_contents_);
-  return WebContentsModalDialogManager::FromWebContents(web_contents_);
+  WebContentsModalDialogManager* dialog_manager =
+      WebContentsModalDialogManager::FromWebContents(web_contents_);
+  // If WebContentsModalDialogManager::CreateForWebContents(web_contents_) was
+  // never called, then the manager will be null. E.g., for browser tabs,
+  // TabHelpers::AttachTabHelpers() calls CreateForWebContents(). It is invalid
+  // to show a dialog on some kinds of WebContents. Crash cleanly in that case.
+  CHECK(dialog_manager);
+  return dialog_manager;
 }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 880c26a..67dc669 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3506,6 +3506,8 @@
   if (is_android) {
     sources += [
       # Offline pages are currently only on Android.
+      "../browser/android/offline_pages/background_loader_offliner_unittest.cc",
+      "../browser/android/offline_pages/downloads/resource_throttle_unittest.cc",
       "../browser/android/offline_pages/offline_page_mhtml_archiver_unittest.cc",
       "../browser/android/offline_pages/offline_page_request_job_unittest.cc",
       "../browser/android/offline_pages/offline_page_utils_unittest.cc",
@@ -3529,6 +3531,7 @@
       ":unit_tests_java",
       "//components/gcm_driver/instance_id/android:instance_id_driver_java",
       "//components/gcm_driver/instance_id/android:instance_id_driver_test_support_java",
+      "//components/offline_pages/content/background_loader:test_support",
       "//components/offline_pages/core:test_support",
       "//components/offline_pages/core/background:test_support",
       "//v8:v8_external_startup_data_assets",
diff --git a/chrome/test/data/webui/bluetooth_internals_browsertest.js b/chrome/test/data/webui/bluetooth_internals_browsertest.js
index 1def822..886f0fd7 100644
--- a/chrome/test/data/webui/bluetooth_internals_browsertest.js
+++ b/chrome/test/data/webui/bluetooth_internals_browsertest.js
@@ -51,9 +51,7 @@
         'device/bluetooth/public/interfaces/adapter.mojom',
         'device/bluetooth/public/interfaces/device.mojom',
         'mojo/public/js/bindings',
-        'mojo/public/js/connection',
-      ]).then(function([frameInterfaces, adapter, device, bindings,
-          connection]) {
+      ]).then(function([frameInterfaces, adapter, device, bindings]) {
         /**
           * A test adapter factory proxy for the chrome://bluetooth-internals
           * page.
@@ -66,6 +64,7 @@
             'getAdapter',
           ]);
 
+          this.binding = new bindings.Binding(adapter.AdapterFactory, this);
           this.adapter = new TestAdapter();
           this.adapterBinding_ = new bindings.Binding(adapter.Adapter,
                                                       this.adapter);
@@ -88,14 +87,12 @@
           * Must be used to create message pipe handle from test code.
           *
           * @constructor
-          * @extends {adapter.Adapter.stubClass}
           */
         var TestAdapter = function() {
           this.proxy = new TestAdapterProxy();
         };
 
         TestAdapter.prototype = {
-          __proto__: adapter.Adapter.stubClass.prototype,
           getInfo: function() { return this.proxy.getInfo(); },
           getDevices: function() { return this.proxy.getDevices(); },
           setClient: function(client) { return this.proxy.setClient(client); }
@@ -146,10 +143,8 @@
 
         frameInterfaces.addInterfaceOverrideForTesting(
             adapter.AdapterFactory.name, function(handle) {
-              var stub = connection.bindHandleToStub(
-                  handle, adapter.AdapterFactory);
-
               this.adapterFactory = new TestAdapterFactoryProxy();
+              this.adapterFactory.binding.bind(handle);
 
               this.adapterFactory.adapter.proxy.setTestDevices([
                 this.fakeDeviceInfo1(),
@@ -158,8 +153,6 @@
               this.adapterFactory.adapter.proxy.setTestAdapter(
                   this.fakeAdapterInfo());
 
-              bindings.StubBindings(stub).delegate = this.adapterFactory;
-
               this.setupResolver.resolve();
             }.bind(this));
 
diff --git a/chrome/test/data/webui/plugins_browsertest.js b/chrome/test/data/webui/plugins_browsertest.js
index 6f613ea..1fc8ac7 100644
--- a/chrome/test/data/webui/plugins_browsertest.js
+++ b/chrome/test/data/webui/plugins_browsertest.js
@@ -55,6 +55,8 @@
         'saveShowDetailsToPrefs',
       ]);
 
+      this.bindingSet = null;
+
       /**
        * The data to be returned by |getPluginsData_|.
        * @private
@@ -96,20 +98,19 @@
     window.setupFn = function() {
       return importModules([
         'mojo/public/js/bindings',
-        'mojo/public/js/connection',
         'chrome/browser/ui/webui/plugins/plugins.mojom',
         'content/public/renderer/frame_interfaces',
       ]).then(function(modules) {
         var bindings = modules[0];
-        var connection = modules[1];
-        var pluginsMojom = modules[2];
-        var frameInterfaces = modules[3];
+        var pluginsMojom = modules[1];
+        var frameInterfaces = modules[2];
 
+        this.browserProxy.bindingSet = new bindings.BindingSet(
+            pluginsMojom.PluginsPageHandler);
         frameInterfaces.addInterfaceOverrideForTesting(
             pluginsMojom.PluginsPageHandler.name, function(handle) {
-              var stub = connection.bindHandleToStub(
-                  handle, pluginsMojom.PluginsPageHandler);
-              bindings.StubBindings(stub).delegate = this.browserProxy;
+              this.browserProxy.bindingSet.addBinding(this.browserProxy,
+                                                      handle);
             }.bind(this));
         return this.setupFnResolver.promise;
       }.bind(this));
diff --git a/chromecast/browser/BUILD.gn b/chromecast/browser/BUILD.gn
index 2897c93..b410082 100644
--- a/chromecast/browser/BUILD.gn
+++ b/chromecast/browser/BUILD.gn
@@ -4,6 +4,7 @@
 
 import("//build/config/ui.gni")
 import("//chromecast/chromecast.gni")
+import("//services/service_manager/public/service_manifest.gni")
 import("//testing/test.gni")
 import("//tools/grit/grit_rule.gni")
 
@@ -143,6 +144,51 @@
   }
 }
 
+# HOW THIS WORKS
+# This target generates an "overlay" interface spec, allowing the Cast build to
+# declare specific behavior and requirements for the "content_browser" service.
+# This is accomplished by generating a JSON file, which is packed into
+# cast_shell.pak, and loaded at runtime. This can be used to:
+#
+# 1) Host Cast-specific embedded services in the browser process.
+#    To host an embedded service, add the service's name to the list of
+#    "packages" in this target, and add the target that generates that service's
+#    manifest to "deps", like so:
+#
+#      packages = [ "foo" ]
+#      deps = [ "//path/to/foo/service:foo_manifest" ]
+#
+#    You must also register the "foo" service with the content client. See
+#    CastContentBrowserClient::RegisterInProcessServices() for details.
+#
+#    **NOTE**
+#    If your service's manifest is in chromecast/internal, do not add it here!
+#    Instead, add the service to the internal counterpart, which is referenced
+#    below.
+#
+# 2) Host an addtional interface in "content_browser" via a ConnectionFilter.
+#    In this case, nothing need be added to this file. Add your interface to the
+#    "provides" field in cast_content_browser_manifest_overlay.json, and use
+#    CastContentBrowserClient::AddConnectionFilters() to register bindings to it
+#    for incoming connections. Remember to add the provided interfaces to the
+#    "requires" field in the manifest of the service that needs them.
+#
+service_manifest_overlay("cast_content_browser_manifest_overlay") {
+  source = "cast_content_browser_manifest_overlay.json"
+
+  packaged_services = [ "media" ]
+
+  deps = [
+    "//media/mojo/services:media_manifest",
+  ]
+
+  if (chromecast_branding != "public") {
+    overlays = [ "${root_gen_dir}/cast_content_browser_internal_manifest_overlay.json" ]
+
+    deps += [ "//chromecast/internal/shell/browser:cast_content_browser_internal_manifest_overlay" ]
+  }
+}
+
 grit("resources") {
   visibility = [
     ":browser",
@@ -155,6 +201,10 @@
     "grit/cast_browser_resources.h",
     "cast_browser_resources.pak",
   ]
+
+  deps = [
+    ":cast_content_browser_manifest_overlay",
+  ]
 }
 
 source_set("test_support") {
diff --git a/chromecast/browser/cast_browser_resources.grd b/chromecast/browser/cast_browser_resources.grd
index ebc64e5c..24d7de8e 100644
--- a/chromecast/browser/cast_browser_resources.grd
+++ b/chromecast/browser/cast_browser_resources.grd
@@ -8,7 +8,9 @@
   </outputs>
   <release seq="1">
     <includes>
-      <include name="IDR_CAST_CONTENT_BROWSER_MANIFEST_OVERLAY" file="cast_content_browser_manifest_overlay.json" type="BINDATA" />
+      <include name="IDR_CAST_CONTENT_BROWSER_MANIFEST_OVERLAY"
+               file="gen\cast_content_browser_manifest_overlay.json"
+               use_base_dir="false" type="BINDATA" />
     </includes>
   </release>
 </grit>
diff --git a/chromecast/browser/cast_content_browser_manifest_overlay.json b/chromecast/browser/cast_content_browser_manifest_overlay.json
index 1b00695..e3e749d 100644
--- a/chromecast/browser/cast_content_browser_manifest_overlay.json
+++ b/chromecast/browser/cast_content_browser_manifest_overlay.json
@@ -1,4 +1,6 @@
 {
+  "name": "content_browser",
+  "display_name": "Cast Shell (Browser)",
   "interface_provider_specs": {
     "service_manager:connector": {
       "provides": {
diff --git a/chromeos/audio/chromeos_sounds.h b/chromeos/audio/chromeos_sounds.h
index 81788e6..c289b6e 100644
--- a/chromeos/audio/chromeos_sounds.h
+++ b/chromeos/audio/chromeos_sounds.h
@@ -22,6 +22,8 @@
   SOUND_PASSTHROUGH,
   SOUND_EXIT_SCREEN,
   SOUND_ENTER_SCREEN,
+  SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_HIGH,
+  SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_LOW,
   SOUND_COUNT,
 };
 
diff --git a/chromeos/chromeos_switches.cc b/chromeos/chromeos_switches.cc
index 16d04b7..45bde70 100644
--- a/chromeos/chromeos_switches.cc
+++ b/chromeos/chromeos_switches.cc
@@ -211,6 +211,9 @@
 // Enables AD functionality.
 const char kEnableAd[] = "enable-ad";
 
+// Enables the Android Wallpapers App as the default app on Chrome OS.
+const char kEnableAndroidWallpapersApp[] = "enable-android-wallpapers-app";
+
 // Enables starting the ARC instance upon session start.
 const char kEnableArc[] = "enable-arc";
 
diff --git a/chromeos/chromeos_switches.h b/chromeos/chromeos_switches.h
index 28d4b20..ee8420b 100644
--- a/chromeos/chromeos_switches.h
+++ b/chromeos/chromeos_switches.h
@@ -75,6 +75,7 @@
 CHROMEOS_EXPORT extern const char kEafePath[];
 CHROMEOS_EXPORT extern const char kEafeUrl[];
 CHROMEOS_EXPORT extern const char kEnableAd[];
+CHROMEOS_EXPORT extern const char kEnableAndroidWallpapersApp[];
 CHROMEOS_EXPORT extern const char kEnableArc[];
 CHROMEOS_EXPORT extern const char kEnableArcOOBEOptIn[];
 CHROMEOS_EXPORT extern const char kEnableConsumerKiosk[];
diff --git a/chromeos/components/tether/host_scan_scheduler.cc b/chromeos/components/tether/host_scan_scheduler.cc
index 1dc0ef13..0605974 100644
--- a/chromeos/components/tether/host_scan_scheduler.cc
+++ b/chromeos/components/tether/host_scan_scheduler.cc
@@ -18,12 +18,12 @@
 
 namespace tether {
 
-HostScanScheduler::ContextImpl::ContextImpl(
+HostScanScheduler::DelegateImpl::DelegateImpl(
     const content::BrowserContext* browser_context) {
   // TODO(khorimoto): Use browser_context to get a CryptAuthDeviceManager.
 }
 
-void HostScanScheduler::ContextImpl::AddObserver(
+void HostScanScheduler::DelegateImpl::AddObserver(
     HostScanScheduler* host_scan_scheduler) {
   LoginState::Get()->AddObserver(host_scan_scheduler);
   DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(
@@ -33,7 +33,7 @@
   // TODO(khorimoto): Add listener for CryptAuthDeviceManager.
 }
 
-void HostScanScheduler::ContextImpl::RemoveObserver(
+void HostScanScheduler::DelegateImpl::RemoveObserver(
     HostScanScheduler* host_scan_scheduler) {
   LoginState::Get()->RemoveObserver(host_scan_scheduler);
   DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(
@@ -43,20 +43,20 @@
   // TODO(khorimoto): Add observer of CryptAuthDeviceManager.
 }
 
-bool HostScanScheduler::ContextImpl::IsAuthenticatedUserLoggedIn() const {
+bool HostScanScheduler::DelegateImpl::IsAuthenticatedUserLoggedIn() const {
   LoginState* login_state = LoginState::Get();
   return login_state && login_state->IsUserLoggedIn() &&
          login_state->IsUserAuthenticated();
 }
 
-bool HostScanScheduler::ContextImpl::IsNetworkConnectedOrConnecting() const {
+bool HostScanScheduler::DelegateImpl::IsNetworkConnectedOrConnecting() const {
   const NetworkState* network_state =
       NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
   return network_state && (network_state->IsConnectedState() ||
                            network_state->IsConnectingState());
 }
 
-bool HostScanScheduler::ContextImpl::AreTetherHostsSynced() const {
+bool HostScanScheduler::DelegateImpl::AreTetherHostsSynced() const {
   // TODO(khorimoto): Return CryptAuthDeviceManager->GetTetherHosts().empty().
   return true;
 }
@@ -64,18 +64,18 @@
 HostScanScheduler::HostScanScheduler(
     const content::BrowserContext* browser_context,
     std::unique_ptr<HostScanner> host_scanner)
-    : HostScanScheduler(base::MakeUnique<ContextImpl>(browser_context),
+    : HostScanScheduler(base::MakeUnique<DelegateImpl>(browser_context),
                         std::move(host_scanner)) {}
 
 HostScanScheduler::~HostScanScheduler() {
   if (initialized_) {
-    context_->RemoveObserver(this);
+    delegate_->RemoveObserver(this);
   }
 }
 
-HostScanScheduler::HostScanScheduler(std::unique_ptr<Context> context,
+HostScanScheduler::HostScanScheduler(std::unique_ptr<Delegate> delegate,
                                      std::unique_ptr<HostScanner> host_scanner)
-    : context_(std::move(context)),
+    : delegate_(std::move(delegate)),
       host_scanner_(std::move(host_scanner)),
       initialized_(false) {}
 
@@ -85,22 +85,22 @@
   }
 
   initialized_ = true;
-  context_->AddObserver(this);
+  delegate_->AddObserver(this);
 }
 
 bool HostScanScheduler::ScheduleScanNowIfPossible() {
-  if (!context_->IsAuthenticatedUserLoggedIn()) {
+  if (!delegate_->IsAuthenticatedUserLoggedIn()) {
     PA_LOG(INFO) << "Authenticated user not logged in; not starting scan.";
     return false;
   }
 
-  if (context_->IsNetworkConnectedOrConnecting()) {
+  if (delegate_->IsNetworkConnectedOrConnecting()) {
     PA_LOG(INFO)
         << "Network is already connected/connecting; not starting scan.";
     return false;
   }
 
-  if (!context_->AreTetherHostsSynced()) {
+  if (!delegate_->AreTetherHostsSynced()) {
     PA_LOG(INFO) << "No tether hosts available on account; not starting scan.";
     return false;
   }
diff --git a/chromeos/components/tether/host_scan_scheduler.h b/chromeos/components/tether/host_scan_scheduler.h
index c68d8b7..80d1aa2 100644
--- a/chromeos/components/tether/host_scan_scheduler.h
+++ b/chromeos/components/tether/host_scan_scheduler.h
@@ -30,9 +30,8 @@
 // Schedules scans for tether hosts. To start a scan attempt, three conditions
 // must be true:
 //
-//   (1) The user has just started using the device; specifically, the user has
-//       just logged in or has just resumed using the device after it had been
-//       sleeping/suspended.
+//   (1) The user has just logged in or has just resumed using the device after
+//       it had been sleeping/suspended.
 //   (2) The device does not have an Internet connection.
 //   (3) The device has synced data about other devices belonging to the user's
 //       account, and at least one of those devices is capable of being a tether
@@ -75,7 +74,7 @@
  private:
   friend class HostScanSchedulerTest;
 
-  class Context {
+  class Delegate {
    public:
     virtual void AddObserver(HostScanScheduler* host_scan_scheduler) = 0;
     virtual void RemoveObserver(HostScanScheduler* host_scan_scheduler) = 0;
@@ -84,9 +83,9 @@
     virtual bool AreTetherHostsSynced() const = 0;
   };
 
-  class ContextImpl : public Context {
+  class DelegateImpl : public Delegate {
    public:
-    ContextImpl(const content::BrowserContext* browser_context);
+    DelegateImpl(const content::BrowserContext* browser_context);
 
     void AddObserver(HostScanScheduler* host_scan_scheduler) override;
     void RemoveObserver(HostScanScheduler* host_scan_scheduler) override;
@@ -95,10 +94,10 @@
     bool AreTetherHostsSynced() const override;
   };
 
-  HostScanScheduler(std::unique_ptr<Context> context_,
+  HostScanScheduler(std::unique_ptr<Delegate> delegate,
                     std::unique_ptr<HostScanner> host_scanner);
 
-  std::unique_ptr<Context> context_;
+  std::unique_ptr<Delegate> delegate_;
   std::unique_ptr<HostScanner> host_scanner_;
   bool initialized_;
 
diff --git a/chromeos/components/tether/host_scan_scheduler_unittest.cc b/chromeos/components/tether/host_scan_scheduler_unittest.cc
index ebf7a61b..7a39a27 100644
--- a/chromeos/components/tether/host_scan_scheduler_unittest.cc
+++ b/chromeos/components/tether/host_scan_scheduler_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// 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.
 
@@ -19,13 +19,11 @@
 
 namespace tether {
 
-namespace {}  // namespace
-
 class HostScanSchedulerTest : public testing::Test {
  protected:
-  class TestContext : public HostScanScheduler::Context {
+  class TestDelegate : public HostScanScheduler::Delegate {
    public:
-    TestContext(HostScanSchedulerTest* test)
+    TestDelegate(HostScanSchedulerTest* test)
         : test_(test),
           observer_(nullptr),
           is_authenticated_user_logged_in(true),
@@ -60,15 +58,17 @@
              observer_ == test_->host_scan_scheduler_.get();
     }
 
-    void SetIsAuthenticatedUserLoggedIn(bool value) {
+    void set_is_authenticated_user_logged_in(bool value) {
       is_authenticated_user_logged_in = value;
     }
 
-    void SetIsNetworkConnectedOrConnecting(bool value) {
+    void set_is_network_connected_or_connecting(bool value) {
       is_network_connected_or_connecting = value;
     }
 
-    void AreTetherHostsSynced(bool value) { are_tether_hosts_synced = value; }
+    void set_are_tether_hosts_synced(bool value) {
+      are_tether_hosts_synced = value;
+    }
 
    private:
     const HostScanSchedulerTest* test_;
@@ -79,10 +79,10 @@
     bool are_tether_hosts_synced;
   };
 
-  class MockHostScanner : public HostScanner {
+  class FakeHostScanner : public HostScanner {
    public:
-    MockHostScanner() : num_scans_started_(0) {}
-    ~MockHostScanner() override {}
+    FakeHostScanner() : num_scans_started_(0) {}
+    ~FakeHostScanner() override {}
 
     void StartScan() override { num_scans_started_++; }
 
@@ -95,19 +95,20 @@
   HostScanSchedulerTest() {}
 
   void SetUp() override {
-    test_context_ = new TestContext(this);
-    mock_host_scanner_ = new MockHostScanner();
+    test_delegate_ = new TestDelegate(this);
+    fake_host_scanner_ = new FakeHostScanner();
 
-    host_scan_scheduler_.reset(new HostScanScheduler(
-        base::WrapUnique(test_context_), base::WrapUnique(mock_host_scanner_)));
+    host_scan_scheduler_.reset(
+        new HostScanScheduler(base::WrapUnique(test_delegate_),
+                              base::WrapUnique(fake_host_scanner_)));
 
-    EXPECT_FALSE(test_context_->IsObserverSet());
+    EXPECT_FALSE(test_delegate_->IsObserverSet());
     host_scan_scheduler_->InitializeAutomaticScans();
-    EXPECT_TRUE(test_context_->IsObserverSet());
+    EXPECT_TRUE(test_delegate_->IsObserverSet());
   }
 
   void TearDown() override {
-    EXPECT_TRUE(test_context_->IsObserverSet());
+    EXPECT_TRUE(test_delegate_->IsObserverSet());
     host_scan_scheduler_.reset();
   }
 
@@ -115,19 +116,19 @@
                                      bool is_network_connected_or_connecting,
                                      bool are_tether_hosts_synced,
                                      int num_expected_scans) {
-    test_context_->SetIsAuthenticatedUserLoggedIn(
+    test_delegate_->set_is_authenticated_user_logged_in(
         is_authenticated_user_logged_in);
-    test_context_->SetIsNetworkConnectedOrConnecting(
+    test_delegate_->set_is_network_connected_or_connecting(
         is_network_connected_or_connecting);
-    test_context_->AreTetherHostsSynced(are_tether_hosts_synced);
+    test_delegate_->set_are_tether_hosts_synced(are_tether_hosts_synced);
     host_scan_scheduler_->ScheduleScanNowIfPossible();
-    EXPECT_EQ(num_expected_scans, mock_host_scanner_->num_scans_started());
+    EXPECT_EQ(num_expected_scans, fake_host_scanner_->num_scans_started());
   }
 
   std::unique_ptr<HostScanScheduler> host_scan_scheduler_;
 
-  TestContext* test_context_;
-  MockHostScanner* mock_host_scanner_;
+  TestDelegate* test_delegate_;
+  FakeHostScanner* fake_host_scanner_;
 };
 
 TEST_F(HostScanSchedulerTest, TestObserverAddedAndRemoved) {
@@ -136,7 +137,7 @@
 }
 
 TEST_F(HostScanSchedulerTest, TestScheduleScanNowIfPossible) {
-  EXPECT_EQ(0, mock_host_scanner_->num_scans_started());
+  EXPECT_EQ(0, fake_host_scanner_->num_scans_started());
 
   // A scan should only be started when an authenticated user is logged in,
   // the network is not connected/connecting, and tether hosts are synced.
@@ -151,75 +152,75 @@
 }
 
 TEST_F(HostScanSchedulerTest, TestLoggedInStateChange) {
-  EXPECT_EQ(0, mock_host_scanner_->num_scans_started());
+  EXPECT_EQ(0, fake_host_scanner_->num_scans_started());
 
-  test_context_->SetIsAuthenticatedUserLoggedIn(true);
-  test_context_->SetIsNetworkConnectedOrConnecting(false);
-  test_context_->AreTetherHostsSynced(true);
+  test_delegate_->set_is_authenticated_user_logged_in(true);
+  test_delegate_->set_is_network_connected_or_connecting(false);
+  test_delegate_->set_are_tether_hosts_synced(true);
 
   host_scan_scheduler_->LoggedInStateChanged();
-  EXPECT_EQ(1, mock_host_scanner_->num_scans_started());
+  EXPECT_EQ(1, fake_host_scanner_->num_scans_started());
 
   // Change a condition so that it should not scan, and re-trigger; there should
   // still be only 1 started scan.
-  test_context_->SetIsAuthenticatedUserLoggedIn(false);
+  test_delegate_->set_is_authenticated_user_logged_in(false);
   host_scan_scheduler_->LoggedInStateChanged();
-  EXPECT_EQ(1, mock_host_scanner_->num_scans_started());
+  EXPECT_EQ(1, fake_host_scanner_->num_scans_started());
 }
 
 TEST_F(HostScanSchedulerTest, TestSuspendDone) {
-  EXPECT_EQ(0, mock_host_scanner_->num_scans_started());
+  EXPECT_EQ(0, fake_host_scanner_->num_scans_started());
 
-  test_context_->SetIsAuthenticatedUserLoggedIn(true);
-  test_context_->SetIsNetworkConnectedOrConnecting(false);
-  test_context_->AreTetherHostsSynced(true);
+  test_delegate_->set_is_authenticated_user_logged_in(true);
+  test_delegate_->set_is_network_connected_or_connecting(false);
+  test_delegate_->set_are_tether_hosts_synced(true);
 
   host_scan_scheduler_->SuspendDone(base::TimeDelta::FromSeconds(1));
-  EXPECT_EQ(1, mock_host_scanner_->num_scans_started());
+  EXPECT_EQ(1, fake_host_scanner_->num_scans_started());
 
   // Change a condition so that it should not scan, and re-trigger; there should
   // still be only 1 started scan.
-  test_context_->SetIsAuthenticatedUserLoggedIn(false);
+  test_delegate_->set_is_authenticated_user_logged_in(false);
   host_scan_scheduler_->SuspendDone(base::TimeDelta::FromSeconds(1));
-  EXPECT_EQ(1, mock_host_scanner_->num_scans_started());
+  EXPECT_EQ(1, fake_host_scanner_->num_scans_started());
 }
 
 TEST_F(HostScanSchedulerTest, TestNetworkConnectionStateChanged) {
-  EXPECT_EQ(0, mock_host_scanner_->num_scans_started());
+  EXPECT_EQ(0, fake_host_scanner_->num_scans_started());
 
-  test_context_->SetIsAuthenticatedUserLoggedIn(true);
-  test_context_->SetIsNetworkConnectedOrConnecting(false);
-  test_context_->AreTetherHostsSynced(true);
+  test_delegate_->set_is_authenticated_user_logged_in(true);
+  test_delegate_->set_is_network_connected_or_connecting(false);
+  test_delegate_->set_are_tether_hosts_synced(true);
 
   host_scan_scheduler_->NetworkConnectionStateChanged(nullptr);
-  EXPECT_EQ(1, mock_host_scanner_->num_scans_started());
+  EXPECT_EQ(1, fake_host_scanner_->num_scans_started());
 
   // Change a condition so that it should not scan, and re-trigger; there should
   // still be only 1 started scan.
-  test_context_->SetIsNetworkConnectedOrConnecting(true);
+  test_delegate_->set_is_network_connected_or_connecting(true);
   host_scan_scheduler_->NetworkConnectionStateChanged(nullptr);
-  EXPECT_EQ(1, mock_host_scanner_->num_scans_started());
+  EXPECT_EQ(1, fake_host_scanner_->num_scans_started());
 }
 
 TEST_F(HostScanSchedulerTest, TestOnSyncFinished) {
-  EXPECT_EQ(0, mock_host_scanner_->num_scans_started());
+  EXPECT_EQ(0, fake_host_scanner_->num_scans_started());
 
-  test_context_->SetIsAuthenticatedUserLoggedIn(true);
-  test_context_->SetIsNetworkConnectedOrConnecting(false);
-  test_context_->AreTetherHostsSynced(true);
+  test_delegate_->set_is_authenticated_user_logged_in(true);
+  test_delegate_->set_is_network_connected_or_connecting(false);
+  test_delegate_->set_are_tether_hosts_synced(true);
 
   host_scan_scheduler_->OnSyncFinished(
       cryptauth::CryptAuthDeviceManager::SyncResult::SUCCESS,
       cryptauth::CryptAuthDeviceManager::DeviceChangeResult::CHANGED);
-  EXPECT_EQ(1, mock_host_scanner_->num_scans_started());
+  EXPECT_EQ(1, fake_host_scanner_->num_scans_started());
 
   // Change a condition so that it should not scan, and re-trigger; there should
   // still be only 1 started scan.
-  test_context_->AreTetherHostsSynced(false);
+  test_delegate_->set_are_tether_hosts_synced(false);
   host_scan_scheduler_->OnSyncFinished(
       cryptauth::CryptAuthDeviceManager::SyncResult::SUCCESS,
       cryptauth::CryptAuthDeviceManager::DeviceChangeResult::UNCHANGED);
-  EXPECT_EQ(1, mock_host_scanner_->num_scans_started());
+  EXPECT_EQ(1, fake_host_scanner_->num_scans_started());
 }
 
 }  // namespace tether
diff --git a/components/cronet/android/cronet_url_request_adapter.cc b/components/cronet/android/cronet_url_request_adapter.cc
index 253b0a5..19437d5 100644
--- a/components/cronet/android/cronet_url_request_adapter.cc
+++ b/components/cronet/android/cronet_url_request_adapter.cc
@@ -402,7 +402,11 @@
 }
 
 void CronetURLRequestAdapter::MaybeReportMetrics(JNIEnv* env) const {
-  if (!enable_metrics_) {
+  // If there was an exception while starting the CronetUrlRequest, there won't
+  // be a native URLRequest. In this case, the caller gets the exception
+  // immediately, and the onFailed callback isn't called, so don't report
+  // metrics either.
+  if (!enable_metrics_ || !url_request_) {
     return;
   }
   net::LoadTimingInfo metrics;
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/RequestFinishedInfoTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/RequestFinishedInfoTest.java
index 1f671a8..c88ff84 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/RequestFinishedInfoTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/RequestFinishedInfoTest.java
@@ -20,6 +20,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
 
 /**
  * Test RequestFinishedInfo.Listener and the metrics information it provides.
@@ -292,6 +293,41 @@
         mTestFramework.mCronetEngine.shutdown();
     }
 
+    private static class RejectAllTasksExecutor implements Executor {
+        @Override
+        public void execute(Runnable task) {
+            throw new RejectedExecutionException();
+        }
+    }
+
+    // Checks that CronetURLRequestAdapter::DestroyOnNetworkThread() doesn't crash when metrics
+    // collection is enabled and the URLRequest hasn't been created. See http://crbug.com/675629.
+    @SmallTest
+    @OnlyRunNativeCronet
+    @Feature({"Cronet"})
+    public void testExceptionInRequestStart() throws Exception {
+        mTestFramework = startCronetTestFramework();
+        // The listener in this test shouldn't get any tasks.
+        Executor executor = new RejectAllTasksExecutor();
+        TestRequestFinishedListener requestFinishedListener =
+                new TestRequestFinishedListener(executor);
+        mTestFramework.mCronetEngine.addRequestFinishedListener(requestFinishedListener);
+        TestUrlRequestCallback callback = new TestUrlRequestCallback();
+        ExperimentalUrlRequest.Builder urlRequestBuilder =
+                mTestFramework.mCronetEngine.newUrlRequestBuilder(
+                        mUrl, callback, callback.getExecutor());
+        // Empty headers are invalid and will cause start() to throw an exception.
+        UrlRequest request = urlRequestBuilder.addHeader("", "").build();
+        try {
+            request.start();
+            fail("UrlRequest.start() should throw IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            assertEquals("Invalid header =", e.getMessage());
+        }
+
+        mTestFramework.mCronetEngine.shutdown();
+    }
+
     @SmallTest
     @Feature({"Cronet"})
     public void testMetricsGetters() throws Exception {
diff --git a/components/cryptauth/BUILD.gn b/components/cryptauth/BUILD.gn
index a1cec1d..ac78303 100644
--- a/components/cryptauth/BUILD.gn
+++ b/components/cryptauth/BUILD.gn
@@ -8,6 +8,11 @@
 
 static_library("cryptauth") {
   sources = [
+    "bluetooth_throttler.h",
+    "bluetooth_throttler_impl.cc",
+    "bluetooth_throttler_impl.h",
+    "connection.cc",
+    "connection.h",
     "cryptauth_access_token_fetcher.h",
     "cryptauth_access_token_fetcher_impl.cc",
     "cryptauth_access_token_fetcher_impl.h",
@@ -43,10 +48,13 @@
     "sync_scheduler.h",
     "sync_scheduler_impl.cc",
     "sync_scheduler_impl.h",
+    "wire_message.cc",
+    "wire_message.h",
   ]
 
   deps = [
     "//base",
+    "//components/cryptauth/ble",
     "//components/gcm_driver",
     "//components/gcm_driver/common",
     "//components/prefs",
@@ -59,12 +67,19 @@
   public_deps = [
     "//components/cryptauth/proto",
   ]
+
+  # TODO (hansberry): Resolve this.
+  allow_circular_includes_from = [ "//components/cryptauth/ble" ]
 }
 
 static_library("test_support") {
   testonly = true
 
   sources = [
+    "cryptauth_test_util.cc",
+    "cryptauth_test_util.h",
+    "fake_connection.cc",
+    "fake_connection.h",
     "fake_cryptauth_gcm_manager.cc",
     "fake_cryptauth_gcm_manager.h",
     "fake_secure_message_delegate.cc",
@@ -91,6 +106,8 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
+    "bluetooth_throttler_impl_unittest.cc",
+    "connection_unittest.cc",
     "cryptauth_access_token_fetcher_impl_unittest.cc",
     "cryptauth_api_call_flow_unittest.cc",
     "cryptauth_client_impl_unittest.cc",
@@ -101,6 +118,7 @@
     "eid_generator_unittest.cc",
     "fake_secure_message_delegate_unittest.cc",
     "sync_scheduler_impl_unittest.cc",
+    "wire_message_unittest.cc",
   ]
 
   deps = [
@@ -109,7 +127,6 @@
     "//base/test:test_support",
     "//components/gcm_driver:test_support",
     "//components/prefs:test_support",
-    "//components/proximity_auth",
     "//google_apis:test_support",
     "//net:test_support",
     "//testing/gtest",
diff --git a/components/cryptauth/DEPS b/components/cryptauth/DEPS
index 531dbff44..af0b1cb 100644
--- a/components/cryptauth/DEPS
+++ b/components/cryptauth/DEPS
@@ -3,6 +3,7 @@
   "+components/prefs",
   "+components/proximity_auth/logging",
   "+crypto",
+  "+device/bluetooth",
   "+google_apis",
   "+net",
 ]
diff --git a/components/cryptauth/README b/components/cryptauth/README
new file mode 100644
index 0000000..5a0fdf7
--- /dev/null
+++ b/components/cryptauth/README
@@ -0,0 +1,3 @@
+Cryptauth provides cryptographic protocols involving user devices. In
+particular, it uses known device public keys to verify cryptographic
+assertions made by corresponding private keys.
\ No newline at end of file
diff --git a/components/cryptauth/ble/BUILD.gn b/components/cryptauth/ble/BUILD.gn
new file mode 100644
index 0000000..a1de6a07
--- /dev/null
+++ b/components/cryptauth/ble/BUILD.gn
@@ -0,0 +1,65 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//testing/test.gni")
+
+static_library("ble") {
+  sources = [
+    "bluetooth_low_energy_characteristics_finder.cc",
+    "bluetooth_low_energy_characteristics_finder.h",
+    "bluetooth_low_energy_weave_client_connection.cc",
+    "bluetooth_low_energy_weave_client_connection.h",
+    "bluetooth_low_energy_weave_defines.h",
+    "bluetooth_low_energy_weave_packet_generator.cc",
+    "bluetooth_low_energy_weave_packet_generator.h",
+    "bluetooth_low_energy_weave_packet_receiver.cc",
+    "bluetooth_low_energy_weave_packet_receiver.h",
+    "fake_wire_message.cc",
+    "fake_wire_message.h",
+    "remote_attribute.h",
+  ]
+
+  deps = [
+    "//base",
+
+    # TODO (hansberry): This component has a circular dependency
+    # with the root cryptauth target. It is whitelisted in that target for
+    # includes.
+    "//components/prefs",
+    "//components/proximity_auth/logging",
+    "//device/bluetooth",
+    "//net",
+  ]
+
+  public_deps = [
+    "//components/cryptauth/proto",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "bluetooth_low_energy_characteristics_finder_unittest.cc",
+    "bluetooth_low_energy_weave_client_connection_unittest.cc",
+    "bluetooth_low_energy_weave_packet_generator_unittest.cc",
+    "bluetooth_low_energy_weave_packet_receiver_unittest.cc",
+  ]
+
+  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
+  deps = [
+    ":ble",
+    "//base/test:test_support",
+    "//components/cryptauth",
+    "//components/cryptauth:test_support",
+    "//components/prefs:test_support",
+    "//device/bluetooth:mocks",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+
+  public_deps = [
+    "//components/cryptauth/proto",
+  ]
+}
diff --git a/components/cryptauth/ble/OWNERS b/components/cryptauth/ble/OWNERS
new file mode 100644
index 0000000..067b451
--- /dev/null
+++ b/components/cryptauth/ble/OWNERS
@@ -0,0 +1,5 @@
+msarda@chromium.org
+sacomoto@chromium.org
+tengs@chromium.org
+khorimoto@chromium.org
+hansberry@chromium.org
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_characteristics_finder.cc b/components/cryptauth/ble/bluetooth_low_energy_characteristics_finder.cc
similarity index 95%
rename from components/proximity_auth/ble/bluetooth_low_energy_characteristics_finder.cc
rename to components/cryptauth/ble/bluetooth_low_energy_characteristics_finder.cc
index fdfd2862..be036e4 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_characteristics_finder.cc
+++ b/components/cryptauth/ble/bluetooth_low_energy_characteristics_finder.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/proximity_auth/ble/bluetooth_low_energy_characteristics_finder.h"
+#include "components/cryptauth/ble/bluetooth_low_energy_characteristics_finder.h"
 
 #include "components/proximity_auth/logging/logging.h"
 #include "device/bluetooth/bluetooth_adapter.h"
@@ -16,7 +16,7 @@
 using device::BluetoothRemoteGattService;
 using device::BluetoothUUID;
 
-namespace proximity_auth {
+namespace cryptauth {
 
 BluetoothLowEnergyCharacteristicsFinder::
     BluetoothLowEnergyCharacteristicsFinder(
@@ -46,8 +46,7 @@
 }
 
 BluetoothLowEnergyCharacteristicsFinder::
-    BluetoothLowEnergyCharacteristicsFinder() {
-}
+    BluetoothLowEnergyCharacteristicsFinder() {}
 
 BluetoothLowEnergyCharacteristicsFinder::
     ~BluetoothLowEnergyCharacteristicsFinder() {
@@ -140,4 +139,4 @@
   error_callback_.Reset();
 }
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_characteristics_finder.h b/components/cryptauth/ble/bluetooth_low_energy_characteristics_finder.h
similarity index 91%
rename from components/proximity_auth/ble/bluetooth_low_energy_characteristics_finder.h
rename to components/cryptauth/ble/bluetooth_low_energy_characteristics_finder.h
index 1c95c4c..8741765a 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_characteristics_finder.h
+++ b/components/cryptauth/ble/bluetooth_low_energy_characteristics_finder.h
@@ -2,20 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_PROXIMITY_AUTH_BLE_BLUETOOTH_LOW_ENERGY_CHARACTERISTICS_FINDER_H_
-#define COMPONENTS_PROXIMITY_AUTH_BLE_BLUETOOTH_LOW_ENERGY_CHARACTERISTICS_FINDER_H_
+#ifndef COMPONENTS_CRYPTAUTH_BLE_BLUETOOTH_LOW_ENERGY_CHARACTERISTICS_FINDER_H_
+#define COMPONENTS_CRYPTAUTH_BLE_BLUETOOTH_LOW_ENERGY_CHARACTERISTICS_FINDER_H_
 
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "components/proximity_auth/ble/remote_attribute.h"
+#include "components/cryptauth/ble/remote_attribute.h"
 #include "device/bluetooth/bluetooth_adapter.h"
 #include "device/bluetooth/bluetooth_device.h"
 #include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"
 #include "device/bluetooth/bluetooth_remote_gatt_service.h"
 #include "device/bluetooth/bluetooth_uuid.h"
 
-namespace proximity_auth {
+namespace cryptauth {
 
 // Looks for given characteristics in a remote device, for which a GATT
 // connection was already established. In the current BLE connection protocol
@@ -32,7 +32,8 @@
   // to_peripheral_char_.id) will be non-blank.
   typedef base::Callback<void(const RemoteAttribute&,
                               const RemoteAttribute&,
-                              const RemoteAttribute&)> SuccessCallback;
+                              const RemoteAttribute&)>
+      SuccessCallback;
 
   // This callback takes as arguments (in this order): |to_peripheral_char_| and
   // |from_peripheral_char_|. A blank id field in the characteristics indicate
@@ -113,6 +114,6 @@
   DISALLOW_COPY_AND_ASSIGN(BluetoothLowEnergyCharacteristicsFinder);
 };
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
 
-#endif  // COMPONENTS_PROXIMITY_AUTH_BLE_BLUETOOTH_CHARACTERISTICS_FINDER_H_
+#endif  // COMPONENTS_CRYPTAUTH_BLE_BLUETOOTH_CHARACTERISTICS_FINDER_H_
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_characteristics_finder_unittest.cc b/components/cryptauth/ble/bluetooth_low_energy_characteristics_finder_unittest.cc
similarity index 98%
rename from components/proximity_auth/ble/bluetooth_low_energy_characteristics_finder_unittest.cc
rename to components/cryptauth/ble/bluetooth_low_energy_characteristics_finder_unittest.cc
index 5eda18c0..ec354ad 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_characteristics_finder_unittest.cc
+++ b/components/cryptauth/ble/bluetooth_low_energy_characteristics_finder_unittest.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/proximity_auth/ble/bluetooth_low_energy_characteristics_finder.h"
+#include "components/cryptauth/ble/bluetooth_low_energy_characteristics_finder.h"
 
 #include <memory>
 
 #include "base/bind.h"
 #include "base/memory/ref_counted.h"
-#include "components/proximity_auth/ble/remote_attribute.h"
+#include "components/cryptauth/ble/remote_attribute.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "device/bluetooth/bluetooth_uuid.h"
 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
@@ -25,7 +25,7 @@
 using testing::StrictMock;
 using testing::SaveArg;
 
-namespace proximity_auth {
+namespace cryptauth {
 namespace {
 
 const char kDeviceName[] = "Device name";
@@ -292,4 +292,4 @@
   observer->GattDiscoveryCompleteForService(adapter_.get(), service_.get());
 }
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_weave_client_connection.cc b/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.cc
similarity index 97%
rename from components/proximity_auth/ble/bluetooth_low_energy_weave_client_connection.cc
rename to components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.cc
index 6f96df20b..529a1b25 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_weave_client_connection.cc
+++ b/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.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/proximity_auth/ble/bluetooth_low_energy_weave_client_connection.h"
+#include "components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.h"
 
 #include <utility>
 
@@ -10,10 +10,10 @@
 #include "base/location.h"
 #include "base/task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "components/proximity_auth/bluetooth_throttler.h"
-#include "components/proximity_auth/connection_finder.h"
+#include "components/cryptauth/bluetooth_throttler.h"
+#include "components/cryptauth/connection_finder.h"
+#include "components/cryptauth/wire_message.h"
 #include "components/proximity_auth/logging/logging.h"
-#include "components/proximity_auth/wire_message.h"
 #include "device/bluetooth/bluetooth_gatt_connection.h"
 
 using device::BluetoothAdapter;
@@ -24,7 +24,7 @@
 using device::BluetoothGattNotifySession;
 using device::BluetoothUUID;
 
-namespace proximity_auth {
+namespace cryptauth {
 namespace weave {
 namespace {
 
@@ -43,7 +43,7 @@
         const cryptauth::RemoteDevice& device,
         scoped_refptr<device::BluetoothAdapter> adapter,
         const BluetoothUUID remote_service_uuid,
-        BluetoothThrottler* bluetooth_throttler,
+        cryptauth::BluetoothThrottler* bluetooth_throttler,
         int max_number_of_write_attempts)
     : Connection(device),
       adapter_(adapter),
@@ -162,7 +162,7 @@
     SubStatus new_sub_status) {
   sub_status_ = new_sub_status;
 
-  // Sets the status of parent class proximity_auth::Connection accordingly.
+  // Sets the status of parent class cryptauth::Connection accordingly.
   if (new_sub_status == SubStatus::CONNECTED) {
     SetStatus(Status::CONNECTED);
   } else if (new_sub_status == SubStatus::DISCONNECTED) {
@@ -636,4 +636,4 @@
 
 }  // namespace weave
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_weave_client_connection.h b/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.h
similarity index 91%
rename from components/proximity_auth/ble/bluetooth_low_energy_weave_client_connection.h
rename to components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.h
index 681fe3b..1a66bf2 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_weave_client_connection.h
+++ b/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.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_PROXIMITY_AUTH_BLE_BLUETOOTH_LOW_ENERGY_WEAVE_CLIENT_CONNECTION_H_
-#define COMPONENTS_PROXIMITY_AUTH_BLE_BLUETOOTH_LOW_ENERGY_WEAVE_CLIENT_CONNECTION_H_
+#ifndef COMPONENTS_CRYPTAUTH_BLE_BLUETOOTH_LOW_ENERGY_WEAVE_CLIENT_CONNECTION_H_
+#define COMPONENTS_CRYPTAUTH_BLE_BLUETOOTH_LOW_ENERGY_WEAVE_CLIENT_CONNECTION_H_
 
 #include <stddef.h>
 #include <stdint.h>
@@ -17,12 +17,13 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
-#include "components/proximity_auth/ble/bluetooth_low_energy_characteristics_finder.h"
-#include "components/proximity_auth/ble/bluetooth_low_energy_weave_packet_generator.h"
-#include "components/proximity_auth/ble/bluetooth_low_energy_weave_packet_receiver.h"
-#include "components/proximity_auth/ble/fake_wire_message.h"
-#include "components/proximity_auth/ble/remote_attribute.h"
-#include "components/proximity_auth/connection.h"
+#include "components/cryptauth/ble/bluetooth_low_energy_characteristics_finder.h"
+#include "components/cryptauth/ble/bluetooth_low_energy_weave_packet_generator.h"
+#include "components/cryptauth/ble/bluetooth_low_energy_weave_packet_receiver.h"
+#include "components/cryptauth/ble/fake_wire_message.h"
+#include "components/cryptauth/ble/remote_attribute.h"
+#include "components/cryptauth/bluetooth_throttler.h"
+#include "components/cryptauth/connection.h"
 #include "device/bluetooth/bluetooth_adapter.h"
 #include "device/bluetooth/bluetooth_device.h"
 #include "device/bluetooth/bluetooth_gatt_notify_session.h"
@@ -33,8 +34,7 @@
 class TaskRunner;
 }
 
-namespace proximity_auth {
-class BluetoothThrottler;
+namespace cryptauth {
 
 namespace weave {
 // Creates GATT connection on top of the BLE connection and act as a Client.
@@ -69,8 +69,8 @@
     static Factory* factory_instance_;
   };
 
-  // The sub-state of a proximity_auth::BluetoothLowEnergyWeaveClientConnection
-  // extends the IN_PROGRESS state of proximity_auth::Connection::Status.
+  // The sub-state of a cryptauth::BluetoothLowEnergyWeaveClientConnection
+  // extends the IN_PROGRESS state of cryptauth::Connection::Status.
   enum SubStatus {
     DISCONNECTED,
     WAITING_GATT_CONNECTION,
@@ -96,7 +96,7 @@
 
   ~BluetoothLowEnergyWeaveClientConnection() override;
 
-  // proximity_auth::Connection:
+  // namespace cryptauth::Connection:
   void Connect() override;
   void Disconnect() override;
   std::string GetDeviceAddress() override;
@@ -118,7 +118,7 @@
       const BluetoothLowEnergyCharacteristicsFinder::ErrorCallback&
           error_callback);
 
-  // proximity_auth::Connection:
+  // namespace cryptauth::Connection:
   void SendMessageImpl(std::unique_ptr<WireMessage> message) override;
 
   // device::BluetoothAdapter::Observer:
@@ -311,6 +311,6 @@
 
 }  // namespace weave
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
 
-#endif  // COMPONENTS_PROXIMITY_AUTH_BLE_BLUETOOTH_LOW_ENERGY_WEAVE_CLIENT_CONNECTION_H_
+#endif  // COMPONENTS_CRYPTAUTH_BLE_BLUETOOTH_LOW_ENERGY_WEAVE_CLIENT_CONNECTION_H_
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_weave_client_connection_unittest.cc b/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection_unittest.cc
similarity index 98%
rename from components/proximity_auth/ble/bluetooth_low_energy_weave_client_connection_unittest.cc
rename to components/cryptauth/ble/bluetooth_low_energy_weave_client_connection_unittest.cc
index c376a79..c8b69df 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_weave_client_connection_unittest.cc
+++ b/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection_unittest.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/proximity_auth/ble/bluetooth_low_energy_weave_client_connection.h"
+#include "components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.h"
 
 #include <stdint.h>
 
@@ -14,12 +14,12 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/test/test_simple_task_runner.h"
+#include "components/cryptauth/bluetooth_throttler.h"
+#include "components/cryptauth/connection_finder.h"
+#include "components/cryptauth/connection_observer.h"
+#include "components/cryptauth/cryptauth_test_util.h"
 #include "components/cryptauth/remote_device.h"
-#include "components/proximity_auth/bluetooth_throttler.h"
-#include "components/proximity_auth/connection_finder.h"
-#include "components/proximity_auth/connection_observer.h"
-#include "components/proximity_auth/proximity_auth_test_util.h"
-#include "components/proximity_auth/wire_message.h"
+#include "components/cryptauth/wire_message.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
 #include "device/bluetooth/test/mock_bluetooth_device.h"
@@ -37,7 +37,7 @@
 using testing::StrictMock;
 using testing::SaveArg;
 
-namespace proximity_auth {
+namespace cryptauth {
 namespace {
 
 class MockBluetoothThrottler : public BluetoothThrottler {
@@ -1053,4 +1053,4 @@
 
 }  // namespace weave
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_weave_defines.h b/components/cryptauth/ble/bluetooth_low_energy_weave_defines.h
similarity index 82%
rename from components/proximity_auth/ble/bluetooth_low_energy_weave_defines.h
rename to components/cryptauth/ble/bluetooth_low_energy_weave_defines.h
index 15bbac92..e1d561d 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_weave_defines.h
+++ b/components/cryptauth/ble/bluetooth_low_energy_weave_defines.h
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_PROXIMITY_AUTH_BLE_BLUETOOTH_LOW_ENERGY_WEAVE_DEFINES_H_
-#define COMPONENTS_PROXIMITY_AUTH_BLE_BLUETOOTH_LOW_ENERGY_WEAVE_DEFINES_H_
+#ifndef COMPONENTS_CRYPTAUTH_BLE_BLUETOOTH_LOW_ENERGY_WEAVE_DEFINES_H_
+#define COMPONENTS_CRYPTAUTH_BLE_BLUETOOTH_LOW_ENERGY_WEAVE_DEFINES_H_
 
 #include <stddef.h>
 #include <stdint.h>
 
 #include <vector>
 
-namespace proximity_auth {
+namespace cryptauth {
 namespace weave {
 
 enum PacketType { DATA = 0x00, CONTROL = 0x01 };
@@ -50,6 +50,6 @@
 const uint8_t kEmptyUpperByte = 0;
 
 }  // namespace weave
-}  // namespace proximity_auth
+}  // namespace cryptauth
 
-#endif  // COMPONENTS_PROXIMITY_AUTH_BLE_BLUETOOTH_LOW_ENERGY_WEAVE_DEFINES_H_
+#endif  // COMPONENTS_CRYPTAUTH_BLE_BLUETOOTH_LOW_ENERGY_WEAVE_DEFINES_H_
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_weave_packet_generator.cc b/components/cryptauth/ble/bluetooth_low_energy_weave_packet_generator.cc
similarity index 97%
rename from components/proximity_auth/ble/bluetooth_low_energy_weave_packet_generator.cc
rename to components/cryptauth/ble/bluetooth_low_energy_weave_packet_generator.cc
index c2f55e9..164a47b 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_weave_packet_generator.cc
+++ b/components/cryptauth/ble/bluetooth_low_energy_weave_packet_generator.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/proximity_auth/ble/bluetooth_low_energy_weave_packet_generator.h"
+#include "components/cryptauth/ble/bluetooth_low_energy_weave_packet_generator.h"
 
 #ifdef OS_WIN
 #include <winsock2.h>
@@ -16,7 +16,7 @@
 
 #include "base/logging.h"
 
-namespace proximity_auth {
+namespace cryptauth {
 namespace weave {
 
 // static.
@@ -198,4 +198,4 @@
 
 }  // namespace weave
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_weave_packet_generator.h b/components/cryptauth/ble/bluetooth_low_energy_weave_packet_generator.h
similarity index 82%
rename from components/proximity_auth/ble/bluetooth_low_energy_weave_packet_generator.h
rename to components/cryptauth/ble/bluetooth_low_energy_weave_packet_generator.h
index 281badff0..b59cfa43 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_weave_packet_generator.h
+++ b/components/cryptauth/ble/bluetooth_low_energy_weave_packet_generator.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_PROXIMITY_AUTH_BLE_BLUETOOTH_LOW_ENERGY_WEAVE_PACKET_GENERATOR_H_
-#define COMPONENTS_PROXIMITY_AUTH_BLE_BLUETOOTH_LOW_ENERGY_WEAVE_PACKET_GENERATOR_H_
+#ifndef COMPONENTS_CRYPTAUTH_BLE_BLUETOOTH_LOW_ENERGY_WEAVE_PACKET_GENERATOR_H_
+#define COMPONENTS_CRYPTAUTH_BLE_BLUETOOTH_LOW_ENERGY_WEAVE_PACKET_GENERATOR_H_
 
 #include <stddef.h>
 #include <stdint.h>
@@ -12,10 +12,10 @@
 #include <string>
 #include <vector>
 
-#include "components/proximity_auth/ble/bluetooth_low_energy_weave_defines.h"
+#include "components/cryptauth/ble/bluetooth_low_energy_weave_defines.h"
 #include "build/build_config.h"
 
-namespace proximity_auth {
+namespace cryptauth {
 namespace weave {
 
 // Generates the messages sent using the uWeave protocol.
@@ -69,6 +69,6 @@
 
 }  // namespace weave
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
 
-#endif  // COMPONENTS_PROXIMITY_AUTH_BLE_BLUETOOTH_LOW_ENERGY_WEAVE_PACKET_GENERATOR_H_
+#endif  // COMPONENTS_CRYPTAUTH_BLE_BLUETOOTH_LOW_ENERGY_WEAVE_PACKET_GENERATOR_H_
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_weave_packet_generator_unittest.cc b/components/cryptauth/ble/bluetooth_low_energy_weave_packet_generator_unittest.cc
similarity index 98%
rename from components/proximity_auth/ble/bluetooth_low_energy_weave_packet_generator_unittest.cc
rename to components/cryptauth/ble/bluetooth_low_energy_weave_packet_generator_unittest.cc
index f1a3177..44ef03b6 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_weave_packet_generator_unittest.cc
+++ b/components/cryptauth/ble/bluetooth_low_energy_weave_packet_generator_unittest.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/proximity_auth/ble/bluetooth_low_energy_weave_packet_generator.h"
+#include "components/cryptauth/ble/bluetooth_low_energy_weave_packet_generator.h"
 
 #include <algorithm>
 #include <string>
@@ -12,7 +12,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace proximity_auth {
+namespace cryptauth {
 namespace weave {
 
 class ProximityAuthBluetoothLowEnergyWeavePacketGeneratorTest
@@ -261,4 +261,4 @@
 
 }  // namespace weave
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_weave_packet_receiver.cc b/components/cryptauth/ble/bluetooth_low_energy_weave_packet_receiver.cc
similarity index 98%
rename from components/proximity_auth/ble/bluetooth_low_energy_weave_packet_receiver.cc
rename to components/cryptauth/ble/bluetooth_low_energy_weave_packet_receiver.cc
index ce52572..c29bb1a3 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_weave_packet_receiver.cc
+++ b/components/cryptauth/ble/bluetooth_low_energy_weave_packet_receiver.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/proximity_auth/ble/bluetooth_low_energy_weave_packet_receiver.h"
+#include "components/cryptauth/ble/bluetooth_low_energy_weave_packet_receiver.h"
 
 #ifdef OS_WIN
 #include <winsock2.h>
@@ -12,7 +12,7 @@
 
 #include "components/proximity_auth/logging/logging.h"
 
-namespace proximity_auth {
+namespace cryptauth {
 namespace weave {
 namespace {
 
@@ -448,4 +448,4 @@
 
 }  // namespace weave
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_weave_packet_receiver.h b/components/cryptauth/ble/bluetooth_low_energy_weave_packet_receiver.h
similarity index 94%
rename from components/proximity_auth/ble/bluetooth_low_energy_weave_packet_receiver.h
rename to components/cryptauth/ble/bluetooth_low_energy_weave_packet_receiver.h
index ece324c1..147963f1 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_weave_packet_receiver.h
+++ b/components/cryptauth/ble/bluetooth_low_energy_weave_packet_receiver.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_PROXIMITY_AUTH_BLE_BLUETOOTH_LOW_ENERGY_WEAVE_PACKET_RECEIVER_H_
-#define COMPONENTS_PROXIMITY_AUTH_BLE_BLUETOOTH_LOW_ENERGY_WEAVE_PACKET_RECEIVER_H_
+#ifndef COMPONENTS_CRYPTAUTH_BLE_BLUETOOTH_LOW_ENERGY_WEAVE_PACKET_RECEIVER_H_
+#define COMPONENTS_CRYPTAUTH_BLE_BLUETOOTH_LOW_ENERGY_WEAVE_PACKET_RECEIVER_H_
 
 #include <stdint.h>
 
@@ -12,9 +12,9 @@
 #include <vector>
 
 #include "build/build_config.h"
-#include "components/proximity_auth/ble/bluetooth_low_energy_weave_defines.h"
+#include "components/cryptauth/ble/bluetooth_low_energy_weave_defines.h"
 
-namespace proximity_auth {
+namespace cryptauth {
 namespace weave {
 
 // Receive the messages sent with uWeave protocol.
@@ -217,6 +217,6 @@
 
 }  // namespace weave
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
 
-#endif  // COMPONENTS_PROXIMITY_AUTH_BLE_BLUETOOTH_LOW_ENERGY_WEAVE_PACKET_RECEIVER_H_
+#endif  // COMPONENTS_CRYPTAUTH_BLE_BLUETOOTH_LOW_ENERGY_WEAVE_PACKET_RECEIVER_H_
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_weave_packet_receiver_unittest.cc b/components/cryptauth/ble/bluetooth_low_energy_weave_packet_receiver_unittest.cc
similarity index 99%
rename from components/proximity_auth/ble/bluetooth_low_energy_weave_packet_receiver_unittest.cc
rename to components/cryptauth/ble/bluetooth_low_energy_weave_packet_receiver_unittest.cc
index de009c8..d631c160 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_weave_packet_receiver_unittest.cc
+++ b/components/cryptauth/ble/bluetooth_low_energy_weave_packet_receiver_unittest.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/proximity_auth/ble/bluetooth_low_energy_weave_packet_receiver.h"
+#include "components/cryptauth/ble/bluetooth_low_energy_weave_packet_receiver.h"
 
 #include <algorithm>
 #include <string>
@@ -11,7 +11,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace proximity_auth {
+namespace cryptauth {
 namespace weave {
 namespace {
 
@@ -1023,4 +1023,4 @@
 
 }  // namespace weave
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
diff --git a/components/proximity_auth/ble/fake_wire_message.cc b/components/cryptauth/ble/fake_wire_message.cc
similarity index 82%
rename from components/proximity_auth/ble/fake_wire_message.cc
rename to components/cryptauth/ble/fake_wire_message.cc
index 531f4d9..31ea442 100644
--- a/components/proximity_auth/ble/fake_wire_message.cc
+++ b/components/cryptauth/ble/fake_wire_message.cc
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/proximity_auth/ble/fake_wire_message.h"
+#include "components/cryptauth/ble/fake_wire_message.h"
 
 #include <memory>
 #include <string>
 
 #include "base/macros.h"
-#include "components/proximity_auth/wire_message.h"
+#include "components/cryptauth/wire_message.h"
 
-namespace proximity_auth {
+namespace cryptauth {
 
 FakeWireMessage::FakeWireMessage(const std::string& payload)
     : WireMessage(payload) {}
diff --git a/components/proximity_auth/ble/fake_wire_message.h b/components/cryptauth/ble/fake_wire_message.h
similarity index 70%
rename from components/proximity_auth/ble/fake_wire_message.h
rename to components/cryptauth/ble/fake_wire_message.h
index e18185b..85cb82b 100644
--- a/components/proximity_auth/ble/fake_wire_message.h
+++ b/components/cryptauth/ble/fake_wire_message.h
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_PROXIMITY_AUTH_FAKE_WIRE_MESSAGE_H
-#define COMPONENTS_PROXIMITY_AUTH_FAKE_WIRE_MESSAGE_H
+#ifndef COMPONENTS_CRYPTAUTH_FAKE_WIRE_MESSAGE_H
+#define COMPONENTS_CRYPTAUTH_FAKE_WIRE_MESSAGE_H
 
 #include <memory>
 #include <string>
 
 #include "base/macros.h"
-#include "components/proximity_auth/wire_message.h"
+#include "components/cryptauth/wire_message.h"
 
-namespace proximity_auth {
+namespace cryptauth {
 
 class FakeWireMessage : public WireMessage {
  public:
@@ -28,4 +28,4 @@
 };
 }
 
-#endif  // COMPONENTS_PROXIMITY_AUTH_WIRE_MESSAGE_H
+#endif  // COMPONENTS_CRYPTAUTH_WIRE_MESSAGE_H
diff --git a/components/proximity_auth/ble/remote_attribute.h b/components/cryptauth/ble/remote_attribute.h
similarity index 62%
rename from components/proximity_auth/ble/remote_attribute.h
rename to components/cryptauth/ble/remote_attribute.h
index 2ac2f8c..190e332 100644
--- a/components/proximity_auth/ble/remote_attribute.h
+++ b/components/cryptauth/ble/remote_attribute.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_PROXIMITY_AUTH_BLE_REMOTE_ATTRIBUTE_H
-#define COMPONENTS_PROXIMITY_AUTH_BLE_REMOTE_ATTRIBUTE_H
+#ifndef COMPONENTS_CRYPTAUTH_BLE_REMOTE_ATTRIBUTE_H
+#define COMPONENTS_CRYPTAUTH_BLE_REMOTE_ATTRIBUTE_H
 
 #include <string>
 
 #include "device/bluetooth/bluetooth_uuid.h"
 
-namespace proximity_auth {
+namespace cryptauth {
 
 // Represents an attribute in the peripheral (service or characteristic).
 struct RemoteAttribute {
@@ -17,6 +17,6 @@
   std::string id;
 };
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
 
-#endif  // COMPONENTS_PROXIMITY_AUTH_REMOTE_ATTRIBUTE_H
+#endif  // COMPONENTS_CRYPTAUTH_REMOTE_ATTRIBUTE_H
diff --git a/components/proximity_auth/bluetooth_throttler.h b/components/cryptauth/bluetooth_throttler.h
similarity index 83%
rename from components/proximity_auth/bluetooth_throttler.h
rename to components/cryptauth/bluetooth_throttler.h
index 1e428fe..ee77718e 100644
--- a/components/proximity_auth/bluetooth_throttler.h
+++ b/components/cryptauth/bluetooth_throttler.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_PROXIMITY_AUTH_BLUETOOTH_THROTTLER_H
-#define COMPONENTS_PROXIMITY_AUTH_BLUETOOTH_THROTTLER_H
+#ifndef COMPONENTS_CRYPTAUTH_BLUETOOTH_THROTTLER_H
+#define COMPONENTS_CRYPTAUTH_BLUETOOTH_THROTTLER_H
 
 namespace base {
 class TimeDelta;
 }
 
-namespace proximity_auth {
+namespace cryptauth {
 
 class Connection;
 
@@ -33,6 +33,6 @@
   virtual void OnConnection(Connection* connection) = 0;
 };
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
 
-#endif  // COMPONENTS_PROXIMITY_AUTH_BLUETOOTH_THROTTLER_H
+#endif  // COMPONENTS_CRYPTAUTH_BLUETOOTH_THROTTLER_H
diff --git a/components/proximity_auth/bluetooth_throttler_impl.cc b/components/cryptauth/bluetooth_throttler_impl.cc
similarity index 90%
rename from components/proximity_auth/bluetooth_throttler_impl.cc
rename to components/cryptauth/bluetooth_throttler_impl.cc
index da4816d..d72337e 100644
--- a/components/proximity_auth/bluetooth_throttler_impl.cc
+++ b/components/cryptauth/bluetooth_throttler_impl.cc
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/proximity_auth/bluetooth_throttler_impl.h"
+#include "components/cryptauth/bluetooth_throttler_impl.h"
 
 #include <utility>
 
 #include "base/stl_util.h"
 #include "base/time/tick_clock.h"
-#include "components/proximity_auth/connection.h"
+#include "components/cryptauth/connection.h"
 
-namespace proximity_auth {
+namespace cryptauth {
 namespace {
 
 // Time to wait after disconnect before reconnecting.
@@ -63,4 +63,4 @@
   }
 }
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
diff --git a/components/proximity_auth/bluetooth_throttler_impl.h b/components/cryptauth/bluetooth_throttler_impl.h
similarity index 84%
rename from components/proximity_auth/bluetooth_throttler_impl.h
rename to components/cryptauth/bluetooth_throttler_impl.h
index 07b0a00..6c3fac8 100644
--- a/components/proximity_auth/bluetooth_throttler_impl.h
+++ b/components/cryptauth/bluetooth_throttler_impl.h
@@ -2,22 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_PROXIMITY_AUTH_BLUETOOTH_THROTTLER_IMPL_H
-#define COMPONENTS_PROXIMITY_AUTH_BLUETOOTH_THROTTLER_IMPL_H
+#ifndef COMPONENTS_CRYPTAUTH_BLUETOOTH_THROTTLER_IMPL_H
+#define COMPONENTS_CRYPTAUTH_BLUETOOTH_THROTTLER_IMPL_H
 
 #include <memory>
 #include <set>
 
 #include "base/macros.h"
 #include "base/time/time.h"
-#include "components/proximity_auth/bluetooth_throttler.h"
-#include "components/proximity_auth/connection_observer.h"
+#include "components/cryptauth/bluetooth_throttler.h"
+#include "components/cryptauth/connection_observer.h"
 
 namespace base {
 class TickClock;
 }
 
-namespace proximity_auth {
+namespace cryptauth {
 
 class Connection;
 
@@ -64,6 +64,6 @@
   DISALLOW_COPY_AND_ASSIGN(BluetoothThrottlerImpl);
 };
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
 
-#endif  // COMPONENTS_PROXIMITY_AUTH_BLUETOOTH_THROTTLER_IMPL_H
+#endif  // COMPONENTS_CRYPTAUTH_BLUETOOTH_THROTTLER_IMPL_H
diff --git a/components/proximity_auth/bluetooth_throttler_impl_unittest.cc b/components/cryptauth/bluetooth_throttler_impl_unittest.cc
similarity index 93%
rename from components/proximity_auth/bluetooth_throttler_impl_unittest.cc
rename to components/cryptauth/bluetooth_throttler_impl_unittest.cc
index cbf65a1..77f6280 100644
--- a/components/proximity_auth/bluetooth_throttler_impl_unittest.cc
+++ b/components/cryptauth/bluetooth_throttler_impl_unittest.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/proximity_auth/bluetooth_throttler_impl.h"
+#include "components/cryptauth/bluetooth_throttler_impl.h"
 
 #include <utility>
 
@@ -10,11 +10,11 @@
 #include "base/memory/ptr_util.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "base/time/time.h"
-#include "components/proximity_auth/fake_connection.h"
-#include "components/proximity_auth/wire_message.h"
+#include "components/cryptauth/fake_connection.h"
+#include "components/cryptauth/wire_message.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace proximity_auth {
+namespace cryptauth {
 namespace {
 
 class TestBluetoothThrottler : public BluetoothThrottlerImpl {
@@ -98,4 +98,4 @@
   EXPECT_EQ(base::TimeDelta(), throttler_.GetDelay());
 }
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
diff --git a/components/proximity_auth/connection.cc b/components/cryptauth/connection.cc
similarity index 90%
rename from components/proximity_auth/connection.cc
rename to components/cryptauth/connection.cc
index b191d5f..21ee01f 100644
--- a/components/proximity_auth/connection.cc
+++ b/components/cryptauth/connection.cc
@@ -2,23 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/proximity_auth/connection.h"
+#include "components/cryptauth/connection.h"
 
 #include <utility>
 
 #include "base/logging.h"
-#include "components/proximity_auth/connection_observer.h"
-#include "components/proximity_auth/wire_message.h"
+#include "components/cryptauth/connection_observer.h"
+#include "components/cryptauth/wire_message.h"
 
-namespace proximity_auth {
+namespace cryptauth {
 
 Connection::Connection(const cryptauth::RemoteDevice& remote_device)
     : remote_device_(remote_device),
       status_(DISCONNECTED),
       is_sending_message_(false) {}
 
-Connection::~Connection() {
-}
+Connection::~Connection() {}
 
 bool Connection::IsConnected() const {
   return status_ == CONNECTED;
@@ -103,4 +102,4 @@
   return WireMessage::Deserialize(received_bytes_, is_incomplete_message);
 }
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
diff --git a/components/proximity_auth/connection.h b/components/cryptauth/connection.h
similarity index 94%
rename from components/proximity_auth/connection.h
rename to components/cryptauth/connection.h
index f66e831..5daba54 100644
--- a/components/proximity_auth/connection.h
+++ b/components/cryptauth/connection.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_PROXIMITY_AUTH_CONNECTION_H
-#define COMPONENTS_PROXIMITY_AUTH_CONNECTION_H
+#ifndef COMPONENTS_CRYPTAUTH_CONNECTION_H
+#define COMPONENTS_CRYPTAUTH_CONNECTION_H
 
 #include <memory>
 
@@ -12,7 +12,7 @@
 #include "base/observer_list.h"
 #include "components/cryptauth/remote_device.h"
 
-namespace proximity_auth {
+namespace cryptauth {
 
 class ConnectionObserver;
 class WireMessage;
@@ -112,6 +112,6 @@
   DISALLOW_COPY_AND_ASSIGN(Connection);
 };
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
 
-#endif  // COMPONENTS_PROXIMITY_AUTH_CONNECTION_H
+#endif  // COMPONENTS_CRYPTAUTH_CONNECTION_H
diff --git a/components/proximity_auth/connection_finder.h b/components/cryptauth/connection_finder.h
similarity index 77%
rename from components/proximity_auth/connection_finder.h
rename to components/cryptauth/connection_finder.h
index 08230be..efc483b 100644
--- a/components/proximity_auth/connection_finder.h
+++ b/components/cryptauth/connection_finder.h
@@ -2,17 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_PROXIMITY_AUTH_CONNECTION_FINDER_H
-#define COMPONENTS_PROXIMITY_AUTH_CONNECTION_FINDER_H
+#ifndef COMPONENTS_CRYPTAUTH_CONNECTION_FINDER_H
+#define COMPONENTS_CRYPTAUTH_CONNECTION_FINDER_H
 
 #include <memory>
 
 #include "base/callback_forward.h"
 #include "base/macros.h"
+#include "components/cryptauth/connection.h"
 
-namespace proximity_auth {
-
-class Connection;
+namespace cryptauth {
 
 // Interface for finding a connection to a remote device.
 class ConnectionFinder {
@@ -29,6 +28,6 @@
   virtual void Find(const ConnectionCallback& connection_callback) = 0;
 };
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
 
-#endif  // COMPONENTS_PROXIMITY_AUTH_CONNECTION_FINDER_H
+#endif  // COMPONENTS_CRYPTAUTH_CONNECTION_FINDER_H
diff --git a/components/proximity_auth/connection_observer.h b/components/cryptauth/connection_observer.h
similarity index 81%
rename from components/proximity_auth/connection_observer.h
rename to components/cryptauth/connection_observer.h
index 7611ee3..9292e48 100644
--- a/components/proximity_auth/connection_observer.h
+++ b/components/cryptauth/connection_observer.h
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_PROXIMITY_AUTH_CONNECTION_OBSERVER_H
-#define COMPONENTS_PROXIMITY_AUTH_CONNECTION_OBSERVER_H
+#ifndef COMPONENTS_CRYPTAUTH_CONNECTION_OBSERVER_H
+#define COMPONENTS_CRYPTAUTH_CONNECTION_OBSERVER_H
 
-#include "components/proximity_auth/connection.h"
+#include "components/cryptauth/connection.h"
 
-namespace proximity_auth {
+namespace cryptauth {
 
 class WireMessage;
 
@@ -34,6 +34,6 @@
                                bool success) {}
 };
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
 
-#endif  // COMPONENTS_PROXIMITY_AUTH_CONNECTION_OBSERVER_H
+#endif  // COMPONENTS_CRYPTAUTH_CONNECTION_OBSERVER_H
diff --git a/components/proximity_auth/connection_unittest.cc b/components/cryptauth/connection_unittest.cc
similarity index 96%
rename from components/proximity_auth/connection_unittest.cc
rename to components/cryptauth/connection_unittest.cc
index c39857cb..82e09c2 100644
--- a/components/proximity_auth/connection_unittest.cc
+++ b/components/cryptauth/connection_unittest.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/proximity_auth/connection.h"
+#include "components/cryptauth/connection.h"
 
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "components/cryptauth/connection_observer.h"
 #include "components/cryptauth/remote_device.h"
-#include "components/proximity_auth/connection_observer.h"
-#include "components/proximity_auth/wire_message.h"
+#include "components/cryptauth/wire_message.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -19,7 +19,7 @@
 using testing::SetArgPointee;
 using testing::StrictMock;
 
-namespace proximity_auth {
+namespace cryptauth {
 namespace {
 
 class MockConnection : public Connection {
@@ -243,4 +243,4 @@
   connection.OnBytesReceived(std::string());
 }
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
diff --git a/components/cryptauth/cryptauth_api_call_flow.cc b/components/cryptauth/cryptauth_api_call_flow.cc
index 9af3b2c..cfacd899 100644
--- a/components/cryptauth/cryptauth_api_call_flow.cc
+++ b/components/cryptauth/cryptauth_api_call_flow.cc
@@ -80,4 +80,4 @@
   error_callback_.Run(error_message);
 }
 
-}  // proximity_auth
+}  // namespace cryptauth
diff --git a/components/cryptauth/cryptauth_client_impl.cc b/components/cryptauth/cryptauth_client_impl.cc
index c7bc8a7..69eebaf5 100644
--- a/components/cryptauth/cryptauth_client_impl.cc
+++ b/components/cryptauth/cryptauth_client_impl.cc
@@ -200,4 +200,4 @@
       url_request_context_, device_classifier_);
 }
 
-}  // proximity_auth
+}  // namespace cryptauth
diff --git a/components/proximity_auth/proximity_auth_test_util.cc b/components/cryptauth/cryptauth_test_util.cc
similarity index 82%
rename from components/proximity_auth/proximity_auth_test_util.cc
rename to components/cryptauth/cryptauth_test_util.cc
index 820b23cc..60b31f8 100644
--- a/components/proximity_auth/proximity_auth_test_util.cc
+++ b/components/cryptauth/cryptauth_test_util.cc
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/proximity_auth/proximity_auth_test_util.h"
+#include "components/cryptauth/cryptauth_test_util.h"
 
-namespace proximity_auth {
+namespace cryptauth {
 
 // Attributes of the default test remote device.
 const char kTestRemoteDeviceUserId[] = "example@gmail.com";
@@ -14,4 +14,4 @@
 const char kTestRemoteDevicePSK[] = "remote device psk";
 const char kTestRemoteDeviceSignInChallenge[] = "sign-in challenge";
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
diff --git a/components/cryptauth/cryptauth_test_util.h b/components/cryptauth/cryptauth_test_util.h
new file mode 100644
index 0000000..32a0d038
--- /dev/null
+++ b/components/cryptauth/cryptauth_test_util.h
@@ -0,0 +1,39 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_CRYPTAUTH_CRYPTAUTH_TEST_UTIL_H
+#define COMPONENTS_CRYPTAUTH_CRYPTAUTH_TEST_UTIL_H
+
+#include "components/cryptauth/remote_device.h"
+
+namespace cryptauth {
+
+// Attributes of the default test remote device.
+extern const char kTestRemoteDeviceUserId[];
+extern const char kTestRemoteDeviceName[];
+extern const char kTestRemoteDevicePublicKey[];
+extern const char kTestRemoteDeviceBluetoothAddress[];
+extern const char kTestRemoteDevicePSK[];
+extern const char kTestRemoteDeviceSignInChallenge[];
+
+// Returns a BLE RemoteDevice used for tests.
+inline RemoteDevice CreateLERemoteDeviceForTest() {
+  return RemoteDevice(kTestRemoteDeviceUserId, kTestRemoteDeviceName,
+                      kTestRemoteDevicePublicKey, RemoteDevice::BLUETOOTH_LE,
+                      kTestRemoteDeviceBluetoothAddress, kTestRemoteDevicePSK,
+                      kTestRemoteDeviceSignInChallenge);
+}
+
+// Returns a classic Bluetooth RemoteDevice used for tests.
+inline RemoteDevice CreateClassicRemoteDeviceForTest() {
+  return RemoteDevice(kTestRemoteDeviceUserId, kTestRemoteDeviceName,
+                      kTestRemoteDevicePublicKey,
+                      RemoteDevice::BLUETOOTH_CLASSIC,
+                      kTestRemoteDeviceBluetoothAddress, kTestRemoteDevicePSK,
+                      kTestRemoteDeviceSignInChallenge);
+}
+
+}  // namespace cryptauth
+
+#endif  // COMPONENTS_CRYPTAUTH_CRYPTAUTH_TEST_UTIL_H
diff --git a/components/proximity_auth/fake_connection.cc b/components/cryptauth/fake_connection.cc
similarity index 89%
rename from components/proximity_auth/fake_connection.cc
rename to components/cryptauth/fake_connection.cc
index c8e22fec..650f62e 100644
--- a/components/proximity_auth/fake_connection.cc
+++ b/components/cryptauth/fake_connection.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/proximity_auth/fake_connection.h"
+#include "components/cryptauth/fake_connection.h"
 
 #include <utility>
 
 #include "base/memory/ptr_util.h"
-#include "components/proximity_auth/wire_message.h"
+#include "components/cryptauth/wire_message.h"
 
-namespace proximity_auth {
+namespace cryptauth {
 
 FakeConnection::FakeConnection(const cryptauth::RemoteDevice& remote_device)
     : Connection(remote_device) {
@@ -53,4 +53,4 @@
   return base::MakeUnique<WireMessage>(pending_payload_);
 }
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
diff --git a/components/proximity_auth/fake_connection.h b/components/cryptauth/fake_connection.h
similarity index 84%
rename from components/proximity_auth/fake_connection.h
rename to components/cryptauth/fake_connection.h
index 5bfe3fb..0f8867e5 100644
--- a/components/proximity_auth/fake_connection.h
+++ b/components/cryptauth/fake_connection.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_PROXIMITY_AUTH_FAKE_CONNECTION_H
-#define COMPONENTS_PROXIMITY_AUTH_FAKE_CONNECTION_H
+#ifndef COMPONENTS_CRYPTAUTH_FAKE_CONNECTION_H
+#define COMPONENTS_CRYPTAUTH_FAKE_CONNECTION_H
 
 #include "base/macros.h"
-#include "components/proximity_auth/connection.h"
+#include "components/cryptauth/connection.h"
 
-namespace proximity_auth {
+namespace cryptauth {
 
 // A fake implementation of Connection to use in tests.
 class FakeConnection : public Connection {
@@ -49,6 +49,6 @@
   DISALLOW_COPY_AND_ASSIGN(FakeConnection);
 };
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
 
-#endif  // COMPONENTS_PROXIMITY_AUTH_FAKE_CONNECTION_H
+#endif  // COMPONENTS_CRYPTAUTH_FAKE_CONNECTION_H
diff --git a/components/cryptauth/fake_secure_message_delegate_unittest.cc b/components/cryptauth/fake_secure_message_delegate_unittest.cc
index ba46991b..712a571 100644
--- a/components/cryptauth/fake_secure_message_delegate_unittest.cc
+++ b/components/cryptauth/fake_secure_message_delegate_unittest.cc
@@ -203,4 +203,4 @@
   EXPECT_EQ(private_key, delegate_.GetPrivateKeyForPublicKey(kTestPublicKey));
 }
 
-}  // proximity_auth
+}  // namespace cryptauth
diff --git a/components/cryptauth/pref_names.h b/components/cryptauth/pref_names.h
index 54bd76b..d4c3230 100644
--- a/components/cryptauth/pref_names.h
+++ b/components/cryptauth/pref_names.h
@@ -20,6 +20,6 @@
 extern const char kCryptAuthGCMRegistrationId[];
 
 }  // namespace prefs
-}  // proximity_auth
+}  // namespace cryptauth
 
 #endif  // COMPONENTS_PROXIMITY_CRYPTAUTH_PREF_NAMES_H
diff --git a/components/cryptauth/secure_message_delegate.cc b/components/cryptauth/secure_message_delegate.cc
index 75f036f..4dd039d 100644
--- a/components/cryptauth/secure_message_delegate.cc
+++ b/components/cryptauth/secure_message_delegate.cc
@@ -27,4 +27,4 @@
 SecureMessageDelegate::UnwrapOptions::~UnwrapOptions() {
 }
 
-}  // proximity_auth
+}  // namespace cryptauth
diff --git a/components/cryptauth/sync_scheduler.cc b/components/cryptauth/sync_scheduler.cc
index 3c807af..52892e2 100644
--- a/components/cryptauth/sync_scheduler.cc
+++ b/components/cryptauth/sync_scheduler.cc
@@ -28,4 +28,4 @@
   }
 }
 
-}  // proximity_auth
+}  // namespace cryptauth
diff --git a/components/proximity_auth/wire_message.cc b/components/cryptauth/wire_message.cc
similarity index 97%
rename from components/proximity_auth/wire_message.cc
rename to components/cryptauth/wire_message.cc
index 6da69d1a..7b26d7d 100644
--- a/components/proximity_auth/wire_message.cc
+++ b/components/cryptauth/wire_message.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/proximity_auth/wire_message.h"
+#include "components/cryptauth/wire_message.h"
 
 #include <stddef.h>
 #include <stdint.h>
@@ -23,7 +23,7 @@
 // The JSON body contains two fields: an optional permit_id field and a required
 // data field.
 
-namespace proximity_auth {
+namespace cryptauth {
 namespace {
 
 // The length of the message header, in bytes.
@@ -76,8 +76,7 @@
 
 }  // namespace
 
-WireMessage::~WireMessage() {
-}
+WireMessage::~WireMessage() {}
 
 // static
 std::unique_ptr<WireMessage> WireMessage::Deserialize(
@@ -169,4 +168,4 @@
                          const std::string& permit_id)
     : payload_(payload), permit_id_(permit_id) {}
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
diff --git a/components/proximity_auth/wire_message.h b/components/cryptauth/wire_message.h
similarity index 88%
rename from components/proximity_auth/wire_message.h
rename to components/cryptauth/wire_message.h
index 4f03996c..b691462 100644
--- a/components/proximity_auth/wire_message.h
+++ b/components/cryptauth/wire_message.h
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_PROXIMITY_AUTH_WIRE_MESSAGE_H
-#define COMPONENTS_PROXIMITY_AUTH_WIRE_MESSAGE_H
+#ifndef COMPONENTS_CRYPTAUTH_WIRE_MESSAGE_H
+#define COMPONENTS_CRYPTAUTH_WIRE_MESSAGE_H
 
 #include <memory>
 #include <string>
 
 #include "base/macros.h"
 
-namespace proximity_auth {
+namespace cryptauth {
 
 class WireMessage {
  public:
@@ -50,6 +50,6 @@
   DISALLOW_COPY_AND_ASSIGN(WireMessage);
 };
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
 
-#endif  // COMPONENTS_PROXIMITY_AUTH_WIRE_MESSAGE_H
+#endif  // COMPONENTS_CRYPTAUTH_WIRE_MESSAGE_H
diff --git a/components/proximity_auth/wire_message_unittest.cc b/components/cryptauth/wire_message_unittest.cc
similarity index 98%
rename from components/proximity_auth/wire_message_unittest.cc
rename to components/cryptauth/wire_message_unittest.cc
index 0faed401..84dc625 100644
--- a/components/proximity_auth/wire_message_unittest.cc
+++ b/components/cryptauth/wire_message_unittest.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/proximity_auth/wire_message.h"
+#include "components/cryptauth/wire_message.h"
 
 #include <stdint.h>
 
 #include "base/strings/string_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace proximity_auth {
+namespace cryptauth {
 
 TEST(ProximityAuthWireMessage, Deserialize_EmptyMessage) {
   bool is_incomplete;
@@ -235,4 +235,4 @@
   EXPECT_TRUE(bytes.empty());
 }
 
-}  // namespace proximity_auth
+}  // namespace cryptauth
diff --git a/components/offline_pages/content/background_loader/BUILD.gn b/components/offline_pages/content/background_loader/BUILD.gn
index 9e6aaeda..b55274399 100644
--- a/components/offline_pages/content/background_loader/BUILD.gn
+++ b/components/offline_pages/content/background_loader/BUILD.gn
@@ -18,6 +18,20 @@
   ]
 }
 
+source_set("test_support") {
+  testonly = true
+
+  sources = [
+    "background_loader_contents_stub.cc",
+    "background_loader_contents_stub.h",
+  ]
+
+  deps = [
+    ":background_loader",
+    "//content/test:test_support",
+  ]
+}
+
 source_set("unit_tests") {
   testonly = true
   sources = [
diff --git a/components/offline_pages/content/background_loader/DEPS b/components/offline_pages/content/background_loader/DEPS
index 1c35d9c..d79a7d0 100644
--- a/components/offline_pages/content/background_loader/DEPS
+++ b/components/offline_pages/content/background_loader/DEPS
@@ -1,3 +1,4 @@
 include_rules = [
   "+content/public/browser",
+  "+content/public/test",
 ]
diff --git a/components/offline_pages/content/background_loader/background_loader_contents.h b/components/offline_pages/content/background_loader/background_loader_contents.h
index 2432c84..43b6cea 100644
--- a/components/offline_pages/content/background_loader/background_loader_contents.h
+++ b/components/offline_pages/content/background_loader/background_loader_contents.h
@@ -28,9 +28,9 @@
 
   // Loads the URL in a WebContents. Will call observe on all current observers
   // with the created WebContents.
-  void LoadPage(const GURL& url);
+  virtual void LoadPage(const GURL& url);
   // Cancels loading of the current page. Calls Close() on internal WebContents.
-  void Cancel();
+  virtual void Cancel();
   // Returns the inner web contents.
   content::WebContents* web_contents() { return web_contents_.get(); }
 
@@ -77,6 +77,8 @@
 
  private:
   friend class BackgroundLoaderContentsTest;
+  friend class BackgroundLoaderContentsStub;
+
   BackgroundLoaderContents();
 
   std::unique_ptr<content::WebContents> web_contents_;
diff --git a/components/offline_pages/content/background_loader/background_loader_contents_stub.cc b/components/offline_pages/content/background_loader/background_loader_contents_stub.cc
new file mode 100644
index 0000000..2acbe96
--- /dev/null
+++ b/components/offline_pages/content/background_loader/background_loader_contents_stub.cc
@@ -0,0 +1,27 @@
+// 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 "components/offline_pages/content/background_loader/background_loader_contents_stub.h"
+
+#include "base/logging.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/web_contents_tester.h"
+
+namespace background_loader {
+
+BackgroundLoaderContentsStub::BackgroundLoaderContentsStub(
+    content::BrowserContext* browser_context)
+    : BackgroundLoaderContents(), is_loading_(false) {
+  BackgroundLoaderContents::web_contents_.reset(
+      content::WebContentsTester::CreateTestWebContents(browser_context, NULL));
+  web_contents_.get()->SetDelegate(this);
+}
+
+BackgroundLoaderContentsStub::~BackgroundLoaderContentsStub() {}
+
+void BackgroundLoaderContentsStub::LoadPage(const GURL& url) {
+  is_loading_ = true;
+}
+
+}  // namespace background_loader
diff --git a/components/offline_pages/content/background_loader/background_loader_contents_stub.h b/components/offline_pages/content/background_loader/background_loader_contents_stub.h
new file mode 100644
index 0000000..5b13baba
--- /dev/null
+++ b/components/offline_pages/content/background_loader/background_loader_contents_stub.h
@@ -0,0 +1,31 @@
+// 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 COMPONENTS_OFFLINE_PAGES_CONTENT_BACKGROUND_LOADER_BACKGROUND_LOADER_CONTENTS_STUB_H_
+#define COMPONENTS_OFFLINE_PAGES_CONTENT_BACKGROUND_LOADER_BACKGROUND_LOADER_CONTENTS_STUB_H_
+
+#include "components/offline_pages/content/background_loader/background_loader_contents.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace background_loader {
+
+// Stub BackgroundLoaderContents for testing use.
+class BackgroundLoaderContentsStub : public BackgroundLoaderContents {
+ public:
+  BackgroundLoaderContentsStub(content::BrowserContext* browser_context);
+  ~BackgroundLoaderContentsStub() override;
+
+  void LoadPage(const GURL& url) override;
+  bool is_loading() const { return is_loading_; }
+
+ private:
+  bool is_loading_;
+  DISALLOW_COPY_AND_ASSIGN(BackgroundLoaderContentsStub);
+};
+
+}  // namespace background_loader
+#endif  // COMPONENTS_OFFLINE_PAGES_CONTENT_BACKGROUND_LOADER_BACKGROUND_LOADER_CONTENTS_STUB_H_
diff --git a/components/proximity_auth/BUILD.gn b/components/proximity_auth/BUILD.gn
index cb1261b..a8a1f66 100644
--- a/components/proximity_auth/BUILD.gn
+++ b/components/proximity_auth/BUILD.gn
@@ -11,16 +11,9 @@
     "bluetooth_connection.h",
     "bluetooth_connection_finder.cc",
     "bluetooth_connection_finder.h",
-    "bluetooth_throttler.h",
-    "bluetooth_throttler_impl.cc",
-    "bluetooth_throttler_impl.h",
     "bluetooth_util.cc",
     "bluetooth_util.h",
     "bluetooth_util_chromeos.cc",
-    "connection.cc",
-    "connection.h",
-    "connection_finder.h",
-    "connection_observer.h",
     "cryptauth_enroller_factory_impl.cc",
     "cryptauth_enroller_factory_impl.h",
     "device_to_device_authenticator.cc",
@@ -63,13 +56,12 @@
     "throttled_bluetooth_connection_finder.h",
     "unlock_manager.cc",
     "unlock_manager.h",
-    "wire_message.cc",
-    "wire_message.h",
   ]
 
   deps = [
     "//base",
     "//components/cryptauth",
+    "//components/cryptauth/ble",
     "//components/prefs",
     "//components/proximity_auth/ble",
     "//components/proximity_auth/logging",
@@ -94,14 +86,10 @@
   sources = [
     "device_to_device_responder_operations.cc",
     "device_to_device_responder_operations.h",
-    "fake_connection.cc",
-    "fake_connection.h",
     "fake_secure_context.cc",
     "fake_secure_context.h",
     "mock_proximity_auth_client.cc",
     "mock_proximity_auth_client.h",
-    "proximity_auth_test_util.cc",
-    "proximity_auth_test_util.h",
   ]
 
   public_deps = [
@@ -121,8 +109,6 @@
   sources = [
     "bluetooth_connection_finder_unittest.cc",
     "bluetooth_connection_unittest.cc",
-    "bluetooth_throttler_impl_unittest.cc",
-    "connection_unittest.cc",
     "device_to_device_authenticator_unittest.cc",
     "device_to_device_operations_unittest.cc",
     "device_to_device_secure_context_unittest.cc",
@@ -135,7 +121,6 @@
     "remote_status_update_unittest.cc",
     "throttled_bluetooth_connection_finder_unittest.cc",
     "unlock_manager_unittest.cc",
-    "wire_message_unittest.cc",
   ]
 
   configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
diff --git a/components/proximity_auth/ble/BUILD.gn b/components/proximity_auth/ble/BUILD.gn
index 83755066..4641f5a 100644
--- a/components/proximity_auth/ble/BUILD.gn
+++ b/components/proximity_auth/ble/BUILD.gn
@@ -6,31 +6,20 @@
 
 static_library("ble") {
   sources = [
-    "bluetooth_low_energy_characteristics_finder.cc",
-    "bluetooth_low_energy_characteristics_finder.h",
     "bluetooth_low_energy_connection.cc",
     "bluetooth_low_energy_connection.h",
     "bluetooth_low_energy_connection_finder.cc",
     "bluetooth_low_energy_connection_finder.h",
     "bluetooth_low_energy_device_whitelist.cc",
     "bluetooth_low_energy_device_whitelist.h",
-    "bluetooth_low_energy_weave_client_connection.cc",
-    "bluetooth_low_energy_weave_client_connection.h",
-    "bluetooth_low_energy_weave_defines.h",
-    "bluetooth_low_energy_weave_packet_generator.cc",
-    "bluetooth_low_energy_weave_packet_generator.h",
-    "bluetooth_low_energy_weave_packet_receiver.cc",
-    "bluetooth_low_energy_weave_packet_receiver.h",
-    "fake_wire_message.cc",
-    "fake_wire_message.h",
     "pref_names.cc",
     "pref_names.h",
-    "remote_attribute.h",
   ]
 
   deps = [
     "//base",
     "//components/cryptauth",
+    "//components/cryptauth/ble",
     "//components/prefs",
     "//components/proximity_auth/logging",
 
@@ -50,13 +39,9 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
-    "bluetooth_low_energy_characteristics_finder_unittest.cc",
     "bluetooth_low_energy_connection_finder_unittest.cc",
     "bluetooth_low_energy_connection_unittest.cc",
     "bluetooth_low_energy_device_whitelist_unittest.cc",
-    "bluetooth_low_energy_weave_client_connection_unittest.cc",
-    "bluetooth_low_energy_weave_packet_generator_unittest.cc",
-    "bluetooth_low_energy_weave_packet_receiver_unittest.cc",
   ]
 
   configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
@@ -65,6 +50,8 @@
     ":ble",
     "//base/test:test_support",
     "//components/cryptauth",
+    "//components/cryptauth:test_support",
+    "//components/cryptauth/ble:ble",
     "//components/prefs:test_support",
     "//components/proximity_auth:test_support",
     "//device/bluetooth:mocks",
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_connection.cc b/components/proximity_auth/ble/bluetooth_low_energy_connection.cc
index cd1cb50..4899158 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_connection.cc
+++ b/components/proximity_auth/ble/bluetooth_low_energy_connection.cc
@@ -13,12 +13,13 @@
 #include "base/task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
-#include "components/proximity_auth/ble/bluetooth_low_energy_characteristics_finder.h"
-#include "components/proximity_auth/ble/fake_wire_message.h"
-#include "components/proximity_auth/bluetooth_throttler.h"
-#include "components/proximity_auth/connection_finder.h"
+#include "components/cryptauth/ble/bluetooth_low_energy_characteristics_finder.h"
+#include "components/cryptauth/ble/fake_wire_message.h"
+#include "components/cryptauth/bluetooth_throttler.h"
+#include "components/cryptauth/connection.h"
+#include "components/cryptauth/connection_finder.h"
+#include "components/cryptauth/wire_message.h"
 #include "components/proximity_auth/logging/logging.h"
-#include "components/proximity_auth/wire_message.h"
 #include "device/bluetooth/bluetooth_adapter.h"
 #include "device/bluetooth/bluetooth_device.h"
 #include "device/bluetooth/bluetooth_gatt_connection.h"
@@ -56,9 +57,9 @@
     const cryptauth::RemoteDevice& device,
     scoped_refptr<device::BluetoothAdapter> adapter,
     const BluetoothUUID remote_service_uuid,
-    BluetoothThrottler* bluetooth_throttler,
+    cryptauth::BluetoothThrottler* bluetooth_throttler,
     int max_number_of_write_attempts)
-    : Connection(device),
+    : cryptauth::Connection(device),
       adapter_(adapter),
       remote_service_({remote_service_uuid, ""}),
       to_peripheral_char_({BluetoothUUID(kToPeripheralCharUUID), ""}),
@@ -149,7 +150,7 @@
 void BluetoothLowEnergyConnection::SetSubStatus(SubStatus new_sub_status) {
   sub_status_ = new_sub_status;
 
-  // Sets the status of parent class proximity_auth::Connection accordingly.
+  // Sets the status of parent class cryptauth::Connection accordingly.
   if (new_sub_status == SubStatus::CONNECTED) {
     SetStatus(CONNECTED);
   } else if (new_sub_status == SubStatus::DISCONNECTED) {
@@ -165,7 +166,7 @@
 }
 
 void BluetoothLowEnergyConnection::SendMessageImpl(
-    std::unique_ptr<WireMessage> message) {
+    std::unique_ptr<cryptauth::WireMessage> message) {
   PA_LOG(INFO) << "Sending message " << message->Serialize();
   std::string serialized_msg = message->Serialize();
 
@@ -357,21 +358,21 @@
                  weak_ptr_factory_.GetWeakPtr())));
 }
 
-BluetoothLowEnergyCharacteristicsFinder*
+cryptauth::BluetoothLowEnergyCharacteristicsFinder*
 BluetoothLowEnergyConnection::CreateCharacteristicsFinder(
-    const BluetoothLowEnergyCharacteristicsFinder::SuccessCallback&
+    const cryptauth::BluetoothLowEnergyCharacteristicsFinder::SuccessCallback&
         success_callback,
-    const BluetoothLowEnergyCharacteristicsFinder::ErrorCallback&
+    const cryptauth::BluetoothLowEnergyCharacteristicsFinder::ErrorCallback&
         error_callback) {
-  return new BluetoothLowEnergyCharacteristicsFinder(
+  return new cryptauth::BluetoothLowEnergyCharacteristicsFinder(
       adapter_, GetRemoteDevice(), remote_service_, to_peripheral_char_,
       from_peripheral_char_, success_callback, error_callback);
 }
 
 void BluetoothLowEnergyConnection::OnCharacteristicsFound(
-    const RemoteAttribute& service,
-    const RemoteAttribute& to_peripheral_char,
-    const RemoteAttribute& from_peripheral_char) {
+    const cryptauth::RemoteAttribute& service,
+    const cryptauth::RemoteAttribute& to_peripheral_char,
+    const cryptauth::RemoteAttribute& from_peripheral_char) {
   PA_LOG(INFO) << "Remote chacteristics found.";
   PrintTimeElapsed();
 
@@ -385,8 +386,8 @@
 }
 
 void BluetoothLowEnergyConnection::OnCharacteristicsFinderError(
-    const RemoteAttribute& to_peripheral_char,
-    const RemoteAttribute& from_peripheral_char) {
+    const cryptauth::RemoteAttribute& to_peripheral_char,
+    const cryptauth::RemoteAttribute& from_peripheral_char) {
   DCHECK(sub_status() == SubStatus::WAITING_CHARACTERISTICS);
   PA_LOG(WARNING) << "Connection error, missing characteristics for SmartLock "
                      "service.\n"
@@ -499,7 +500,8 @@
   write_remote_characteristic_pending_ = false;
   // TODO(sacomoto): Actually pass the current message to the observer.
   if (run_did_send_message_callback)
-    OnDidSendMessage(WireMessage(std::string(), std::string()), true);
+    OnDidSendMessage(cryptauth::WireMessage(std::string(), std::string()),
+                     true);
 
   // Removes the top of queue (already processed) and process the next request.
   DCHECK(!write_requests_queue_.empty());
@@ -515,7 +517,8 @@
   write_remote_characteristic_pending_ = false;
   // TODO(sacomoto): Actually pass the current message to the observer.
   if (run_did_send_message_callback)
-    OnDidSendMessage(WireMessage(std::string(), std::string()), false);
+    OnDidSendMessage(cryptauth::WireMessage(std::string(), std::string()),
+                     false);
 
   // Increases the number of failed attempts and retry.
   DCHECK(!write_requests_queue_.empty());
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_connection.h b/components/proximity_auth/ble/bluetooth_low_energy_connection.h
index eaa766c835..c492aaee 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_connection.h
+++ b/components/proximity_auth/ble/bluetooth_low_energy_connection.h
@@ -16,10 +16,11 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
-#include "components/proximity_auth/ble/bluetooth_low_energy_characteristics_finder.h"
-#include "components/proximity_auth/ble/fake_wire_message.h"
-#include "components/proximity_auth/ble/remote_attribute.h"
-#include "components/proximity_auth/connection.h"
+#include "components/cryptauth/ble/bluetooth_low_energy_characteristics_finder.h"
+#include "components/cryptauth/ble/fake_wire_message.h"
+#include "components/cryptauth/ble/remote_attribute.h"
+#include "components/cryptauth/bluetooth_throttler.h"
+#include "components/cryptauth/connection.h"
 #include "device/bluetooth/bluetooth_adapter.h"
 #include "device/bluetooth/bluetooth_device.h"
 #include "device/bluetooth/bluetooth_gatt_notify_session.h"
@@ -32,8 +33,6 @@
 
 namespace proximity_auth {
 
-class BluetoothThrottler;
-
 // Represents a connection with a remote device over Bluetooth low energy. The
 // connection is a persistent bidirectional channel for sending and receiving
 // wire messages. The remote device is the peripheral mode and the service
@@ -58,7 +57,7 @@
 //                              |
 //                              |
 //           Proximity Auth Connection Established
-class BluetoothLowEnergyConnection : public Connection,
+class BluetoothLowEnergyConnection : public cryptauth::Connection,
                                      public device::BluetoothAdapter::Observer {
  public:
   // Signals sent to the remote device to indicate connection related events.
@@ -87,15 +86,16 @@
   // initaalized and ready. The GATT connection may alreaady be established and
   // pass through |gatt_connection|. A subsequent call to Connect() must be
   // made.
-  BluetoothLowEnergyConnection(const cryptauth::RemoteDevice& remote_device,
-                               scoped_refptr<device::BluetoothAdapter> adapter,
-                               const device::BluetoothUUID remote_service_uuid,
-                               BluetoothThrottler* bluetooth_throttler,
-                               int max_number_of_write_attempts);
+  BluetoothLowEnergyConnection(
+      const cryptauth::RemoteDevice& remote_device,
+      scoped_refptr<device::BluetoothAdapter> adapter,
+      const device::BluetoothUUID remote_service_uuid,
+      cryptauth::BluetoothThrottler* bluetooth_throttler,
+      int max_number_of_write_attempts);
 
   ~BluetoothLowEnergyConnection() override;
 
-  // proximity_auth::Connection:
+  // cryptauth::Connection:
   void Connect() override;
   void Disconnect() override;
   std::string GetDeviceAddress() override;
@@ -109,14 +109,16 @@
   void SetTaskRunnerForTesting(scoped_refptr<base::TaskRunner> task_runner);
 
   // Virtual for testing.
-  virtual BluetoothLowEnergyCharacteristicsFinder* CreateCharacteristicsFinder(
-      const BluetoothLowEnergyCharacteristicsFinder::SuccessCallback&
+  virtual cryptauth::BluetoothLowEnergyCharacteristicsFinder*
+  CreateCharacteristicsFinder(
+      const cryptauth::BluetoothLowEnergyCharacteristicsFinder::SuccessCallback&
           success_callback,
-      const BluetoothLowEnergyCharacteristicsFinder::ErrorCallback&
+      const cryptauth::BluetoothLowEnergyCharacteristicsFinder::ErrorCallback&
           error_callback);
 
-  // proximity_auth::Connection:
-  void SendMessageImpl(std::unique_ptr<WireMessage> message) override;
+  // cryptauth::Connection:
+  void SendMessageImpl(
+      std::unique_ptr<cryptauth::WireMessage> message) override;
 
   // device::BluetoothAdapter::Observer:
   void DeviceChanged(device::BluetoothAdapter* adapter,
@@ -132,9 +134,11 @@
   // Represents a request to write |value| to a some characteristic.
   // |is_last_write_for_wire_messsage| indicates whether this request
   // corresponds to the last write request for some wire message.
-  // A WireMessage corresponds to exactly two WriteRequest: the first containing
-  // a kSendSignal + the size of the WireMessage, and the second containing a
-  // SendStatusSignal + the serialized WireMessage.
+  // A cryptauth::WireMessage corresponds to exactly two WriteRequest: the first
+  // containing
+  // a kSendSignal + the size of the cryptauth::WireMessage, and the second
+  // containing a
+  // SendStatusSignal + the serialized cryptauth::WireMessage.
   struct WriteRequest {
     WriteRequest(const std::vector<uint8_t>& val, bool flag);
     WriteRequest(const WriteRequest& other);
@@ -158,14 +162,15 @@
 
   // Callback called when |to_peripheral_char_| and |from_peripheral_char_| were
   // found.
-  void OnCharacteristicsFound(const RemoteAttribute& service,
-                              const RemoteAttribute& to_peripheral_char,
-                              const RemoteAttribute& from_peripheral_char);
+  void OnCharacteristicsFound(
+      const cryptauth::RemoteAttribute& service,
+      const cryptauth::RemoteAttribute& to_peripheral_char,
+      const cryptauth::RemoteAttribute& from_peripheral_char);
 
   // Callback called there was an error finding the characteristics.
   void OnCharacteristicsFinderError(
-      const RemoteAttribute& to_peripheral_char,
-      const RemoteAttribute& from_peripheral_char);
+      const cryptauth::RemoteAttribute& to_peripheral_char,
+      const cryptauth::RemoteAttribute& from_peripheral_char);
 
   // Starts a notify session for |from_peripheral_char_| when ready
   // (SubStatus::CHARACTERISTICS_FOUND).
@@ -248,17 +253,17 @@
   scoped_refptr<device::BluetoothAdapter> adapter_;
 
   // Remote service the |gatt_connection_| was established with.
-  RemoteAttribute remote_service_;
+  cryptauth::RemoteAttribute remote_service_;
 
   // Characteristic used to send data to the remote device.
-  RemoteAttribute to_peripheral_char_;
+  cryptauth::RemoteAttribute to_peripheral_char_;
 
   // Characteristic used to receive data from the remote device.
-  RemoteAttribute from_peripheral_char_;
+  cryptauth::RemoteAttribute from_peripheral_char_;
 
   // Throttles repeated connection attempts to the same device. This is a
   // workaround for crbug.com/508919. Not owned, must outlive this instance.
-  BluetoothThrottler* bluetooth_throttler_;
+  cryptauth::BluetoothThrottler* bluetooth_throttler_;
 
   scoped_refptr<base::TaskRunner> task_runner_;
 
@@ -266,7 +271,7 @@
   std::unique_ptr<device::BluetoothGattConnection> gatt_connection_;
 
   // The characteristics finder for remote device.
-  std::unique_ptr<BluetoothLowEnergyCharacteristicsFinder>
+  std::unique_ptr<cryptauth::BluetoothLowEnergyCharacteristicsFinder>
       characteristic_finder_;
 
   // The notify session for |from_peripheral_char|.
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_connection_finder.cc b/components/proximity_auth/ble/bluetooth_low_energy_connection_finder.cc
index 1e7de73a..3ea4363 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_connection_finder.cc
+++ b/components/proximity_auth/ble/bluetooth_low_energy_connection_finder.cc
@@ -15,6 +15,8 @@
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "components/cryptauth/bluetooth_throttler.h"
+#include "components/cryptauth/connection.h"
 #include "components/proximity_auth/ble/bluetooth_low_energy_connection.h"
 #include "components/proximity_auth/ble/bluetooth_low_energy_device_whitelist.h"
 #include "components/proximity_auth/logging/logging.h"
@@ -34,14 +36,12 @@
 const int kMinDiscoveryRSSI = -90;
 }  // namespace
 
-class BluetoothThrottler;
-
 BluetoothLowEnergyConnectionFinder::BluetoothLowEnergyConnectionFinder(
     const cryptauth::RemoteDevice remote_device,
     const std::string& remote_service_uuid,
     FinderStrategy finder_strategy,
     const BluetoothLowEnergyDeviceWhitelist* device_whitelist,
-    BluetoothThrottler* bluetooth_throttler,
+    cryptauth::BluetoothThrottler* bluetooth_throttler,
     int max_number_of_tries)
     : remote_device_(remote_device),
       remote_service_uuid_(device::BluetoothUUID(remote_service_uuid)),
@@ -71,7 +71,8 @@
 }
 
 void BluetoothLowEnergyConnectionFinder::Find(
-    const ConnectionCallback& connection_callback) {
+    const cryptauth::ConnectionFinder::ConnectionCallback&
+        connection_callback) {
   if (!device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) {
     PA_LOG(WARNING) << "Bluetooth is unsupported on this platform. Aborting.";
     return;
@@ -245,7 +246,7 @@
   discovery_session_.reset();
 }
 
-std::unique_ptr<Connection>
+std::unique_ptr<cryptauth::Connection>
 BluetoothLowEnergyConnectionFinder::CreateConnection(
     const std::string& device_address) {
   DCHECK(remote_device_.bluetooth_address.empty() ||
@@ -257,9 +258,9 @@
 }
 
 void BluetoothLowEnergyConnectionFinder::OnConnectionStatusChanged(
-    Connection* connection,
-    Connection::Status old_status,
-    Connection::Status new_status) {
+    cryptauth::Connection* connection,
+    cryptauth::Connection::Status old_status,
+    cryptauth::Connection::Status new_status) {
   DCHECK_EQ(connection, connection_.get());
   PA_LOG(INFO) << "OnConnectionStatusChanged: " << old_status << " -> "
                << new_status;
@@ -277,7 +278,7 @@
         FROM_HERE,
         base::Bind(&BluetoothLowEnergyConnectionFinder::InvokeCallbackAsync,
                    weak_ptr_factory_.GetWeakPtr()));
-  } else if (old_status == Connection::IN_PROGRESS) {
+  } else if (old_status == cryptauth::Connection::IN_PROGRESS) {
     PA_LOG(WARNING) << "Connection failed. Retrying.";
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_connection_finder.h b/components/proximity_auth/ble/bluetooth_low_energy_connection_finder.h
index 426348a..5140d46 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_connection_finder.h
+++ b/components/proximity_auth/ble/bluetooth_low_energy_connection_finder.h
@@ -13,10 +13,11 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "components/cryptauth/bluetooth_throttler.h"
+#include "components/cryptauth/connection.h"
+#include "components/cryptauth/connection_finder.h"
+#include "components/cryptauth/connection_observer.h"
 #include "components/cryptauth/remote_device.h"
-#include "components/proximity_auth/connection.h"
-#include "components/proximity_auth/connection_finder.h"
-#include "components/proximity_auth/connection_observer.h"
 #include "device/bluetooth/bluetooth_adapter.h"
 #include "device/bluetooth/bluetooth_device.h"
 #include "device/bluetooth/bluetooth_discovery_session.h"
@@ -25,13 +26,13 @@
 namespace proximity_auth {
 
 class BluetoothLowEnergyDeviceWhitelist;
-class BluetoothThrottler;
 
-// This ConnectionFinder implementation is specialized in finding a Bluetooth
+// This cryptauth::ConnectionFinder implementation is specialized in finding a
+// Bluetooth
 // Low Energy remote device.
 class BluetoothLowEnergyConnectionFinder
-    : public ConnectionFinder,
-      public ConnectionObserver,
+    : public cryptauth::ConnectionFinder,
+      public cryptauth::ConnectionObserver,
       public device::BluetoothAdapter::Observer {
  public:
   enum FinderStrategy { FIND_PAIRED_DEVICE, FIND_ANY_DEVICE };
@@ -57,18 +58,20 @@
       const std::string& remote_service_uuid,
       const FinderStrategy finder_strategy,
       const BluetoothLowEnergyDeviceWhitelist* device_whitelist,
-      BluetoothThrottler* bluetooth_throttler,
+      cryptauth::BluetoothThrottler* bluetooth_throttler,
       int max_number_of_tries);
 
   ~BluetoothLowEnergyConnectionFinder() override;
 
   // Finds a connection to the remote device.
-  void Find(const ConnectionCallback& connection_callback) override;
+  void Find(const cryptauth::ConnectionFinder::ConnectionCallback&
+                connection_callback) override;
 
-  // proximity_auth::ConnectionObserver:
-  void OnConnectionStatusChanged(Connection* connection,
-                                 Connection::Status old_status,
-                                 Connection::Status new_status) override;
+  // cryptauth::ConnectionObserver:
+  void OnConnectionStatusChanged(
+      cryptauth::Connection* connection,
+      cryptauth::Connection::Status old_status,
+      cryptauth::Connection::Status new_status) override;
 
   // device::BluetoothAdapter::Observer:
   void AdapterPoweredChanged(device::BluetoothAdapter* adapter,
@@ -81,7 +84,7 @@
  protected:
   // Creates a proximity_auth::Connection with the device given by
   // |device_address|. Exposed for testing.
-  virtual std::unique_ptr<Connection> CreateConnection(
+  virtual std::unique_ptr<cryptauth::Connection> CreateConnection(
       const std::string& device_address);
 
  private:
@@ -141,7 +144,7 @@
 
   // Throttles repeated connection attempts to the same device. This is a
   // workaround for crbug.com/508919. Not owned, must outlive this instance.
-  BluetoothThrottler* bluetooth_throttler_;
+  cryptauth::BluetoothThrottler* bluetooth_throttler_;
 
   // The Bluetooth adapter over which the Bluetooth connection will be made.
   scoped_refptr<device::BluetoothAdapter> adapter_;
@@ -150,11 +153,10 @@
   std::unique_ptr<device::BluetoothDiscoverySession> discovery_session_;
 
   // The connection with |remote_device|.
-  std::unique_ptr<Connection> connection_;
+  std::unique_ptr<cryptauth::Connection> connection_;
 
   // Callback called when the connection is established.
-  // device::BluetoothDevice::GattConnectionCallback connection_callback_;
-  ConnectionCallback connection_callback_;
+  cryptauth::ConnectionFinder::ConnectionCallback connection_callback_;
 
   // BluetoothLowEnergyConnection parameter.
   int max_number_of_tries_;
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_connection_finder_unittest.cc b/components/proximity_auth/ble/bluetooth_low_energy_connection_finder_unittest.cc
index 845af2c..e2abae9 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_connection_finder_unittest.cc
+++ b/components/proximity_auth/ble/bluetooth_low_energy_connection_finder_unittest.cc
@@ -16,11 +16,12 @@
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
+#include "components/cryptauth/connection.h"
+#include "components/cryptauth/cryptauth_test_util.h"
+#include "components/cryptauth/fake_connection.h"
 #include "components/cryptauth/remote_device.h"
+#include "components/cryptauth/wire_message.h"
 #include "components/proximity_auth/ble/bluetooth_low_energy_device_whitelist.h"
-#include "components/proximity_auth/fake_connection.h"
-#include "components/proximity_auth/proximity_auth_test_util.h"
-#include "components/proximity_auth/wire_message.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "device/bluetooth/bluetooth_uuid.h"
 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
@@ -63,29 +64,31 @@
   MockBluetoothLowEnergyConnectionFinder(
       const BluetoothLowEnergyDeviceWhitelist* device_whitelist,
       FinderStrategy finder_strategy)
-      : BluetoothLowEnergyConnectionFinder(CreateLERemoteDeviceForTest(),
-                                           kServiceUUID,
-                                           finder_strategy,
-                                           device_whitelist,
-                                           nullptr,
-                                           kMaxNumberOfAttempts) {}
+      : BluetoothLowEnergyConnectionFinder(
+            cryptauth::CreateLERemoteDeviceForTest(),
+            kServiceUUID,
+            finder_strategy,
+            device_whitelist,
+            nullptr,
+            kMaxNumberOfAttempts) {}
 
   ~MockBluetoothLowEnergyConnectionFinder() override {}
 
   // Mock methods don't support return type std::unique_ptr<>. This is a
   // possible workaround: mock a proxy method to be called by the target
   // overridden method (CreateConnection).
-  MOCK_METHOD0(CreateConnectionProxy, Connection*());
+  MOCK_METHOD0(CreateConnectionProxy, cryptauth::Connection*());
 
   // Creates a mock connection and sets an expectation that the mock connection
   // finder's CreateConnection() method will be called and will return the
   // created connection. Returns a reference to the created connection.
   // NOTE: The returned connection's lifetime is managed by the connection
   // finder.
-  FakeConnection* ExpectCreateConnection() {
-    std::unique_ptr<FakeConnection> connection(
-        new FakeConnection(CreateLERemoteDeviceForTest()));
-    FakeConnection* connection_alias = connection.get();
+  cryptauth::FakeConnection* ExpectCreateConnection() {
+    std::unique_ptr<cryptauth::FakeConnection> connection(
+        new cryptauth::FakeConnection(
+            cryptauth::CreateLERemoteDeviceForTest()));
+    cryptauth::FakeConnection* connection_alias = connection.get();
     EXPECT_CALL(*this, CreateConnectionProxy())
         .WillOnce(Return(connection.release()));
     return connection_alias;
@@ -94,7 +97,7 @@
   MOCK_METHOD0(CloseGattConnectionProxy, void(void));
 
  protected:
-  std::unique_ptr<Connection> CreateConnection(
+  std::unique_ptr<cryptauth::Connection> CreateConnection(
       const std::string& device_address) override {
     return base::WrapUnique(CreateConnectionProxy());
   }
@@ -117,8 +120,8 @@
         device_(new NiceMock<device::MockBluetoothDevice>(
             adapter_.get(),
             0,
-            kTestRemoteDeviceName,
-            kTestRemoteDeviceBluetoothAddress,
+            cryptauth::kTestRemoteDeviceName,
+            cryptauth::kTestRemoteDeviceBluetoothAddress,
             false,
             false)),
         device_whitelist_(new MockBluetoothLowEnergyDeviceWhitelist()),
@@ -135,7 +138,7 @@
         .WillByDefault(Return(false));
   }
 
-  void OnConnectionFound(std::unique_ptr<Connection> connection) {
+  void OnConnectionFound(std::unique_ptr<cryptauth::Connection> connection) {
     last_found_connection_ = std::move(connection);
   }
 
@@ -173,9 +176,9 @@
   }
 
   scoped_refptr<device::MockBluetoothAdapter> adapter_;
-  ConnectionFinder::ConnectionCallback connection_callback_;
+  cryptauth::ConnectionFinder::ConnectionCallback connection_callback_;
   std::unique_ptr<device::MockBluetoothDevice> device_;
-  std::unique_ptr<Connection> last_found_connection_;
+  std::unique_ptr<cryptauth::Connection> last_found_connection_;
   std::unique_ptr<MockBluetoothLowEnergyDeviceWhitelist> device_whitelist_;
   device::MockBluetoothDiscoverySession* last_discovery_session_alias_;
 
@@ -188,7 +191,7 @@
   // Destroying a BluetoothConnectionFinder for which Find() has not been called
   // should not crash.
   BluetoothLowEnergyConnectionFinder connection_finder(
-      CreateLERemoteDeviceForTest(), kServiceUUID,
+      cryptauth::CreateLERemoteDeviceForTest(), kServiceUUID,
       BluetoothLowEnergyConnectionFinder::FIND_PAIRED_DEVICE,
       device_whitelist_.get(), nullptr, kMaxNumberOfAttempts);
 }
@@ -196,7 +199,7 @@
 TEST_F(ProximityAuthBluetoothLowEnergyConnectionFinderTest,
        Find_StartsDiscoverySession) {
   BluetoothLowEnergyConnectionFinder connection_finder(
-      CreateLERemoteDeviceForTest(), kServiceUUID,
+      cryptauth::CreateLERemoteDeviceForTest(), kServiceUUID,
       BluetoothLowEnergyConnectionFinder::FIND_PAIRED_DEVICE,
       device_whitelist_.get(), nullptr, kMaxNumberOfAttempts);
 
@@ -208,7 +211,7 @@
 TEST_F(ProximityAuthBluetoothLowEnergyConnectionFinderTest,
        Find_StopsDiscoverySessionBeforeDestroying) {
   BluetoothLowEnergyConnectionFinder connection_finder(
-      CreateLERemoteDeviceForTest(), kServiceUUID,
+      cryptauth::CreateLERemoteDeviceForTest(), kServiceUUID,
       BluetoothLowEnergyConnectionFinder::FIND_PAIRED_DEVICE,
       device_whitelist_.get(), nullptr, kMaxNumberOfAttempts);
 
@@ -257,9 +260,10 @@
   FindAndExpectStartDiscovery(connection_finder);
   ExpectRemoveObserver();
 
-  PrepareDevice(kServiceUUID, kTestRemoteDeviceBluetoothAddress, false);
+  PrepareDevice(kServiceUUID, cryptauth::kTestRemoteDeviceBluetoothAddress,
+                false);
   ON_CALL(*device_, GetName())
-      .WillByDefault(Return(std::string(kTestRemoteDeviceName)));
+      .WillByDefault(Return(std::string(cryptauth::kTestRemoteDeviceName)));
 
   connection_finder.ExpectCreateConnection();
   connection_finder.DeviceAdded(adapter_.get(), device_.get());
@@ -273,7 +277,8 @@
   FindAndExpectStartDiscovery(connection_finder);
   ExpectRemoveObserver();
 
-  PrepareDevice(kOtherUUID, kTestRemoteDeviceBluetoothAddress, false);
+  PrepareDevice(kOtherUUID, cryptauth::kTestRemoteDeviceBluetoothAddress,
+                false);
   ON_CALL(*device_, GetName()).WillByDefault(Return(std::string("Other name")));
 
   EXPECT_CALL(connection_finder, CreateConnectionProxy()).Times(0);
@@ -288,7 +293,8 @@
   FindAndExpectStartDiscovery(connection_finder);
   ExpectRemoveObserver();
 
-  PrepareDevice(kServiceUUID, kTestRemoteDeviceBluetoothAddress, true);
+  PrepareDevice(kServiceUUID, cryptauth::kTestRemoteDeviceBluetoothAddress,
+                true);
   connection_finder.ExpectCreateConnection();
   connection_finder.DeviceAdded(adapter_.get(), device_.get());
 }
@@ -313,7 +319,8 @@
   FindAndExpectStartDiscovery(connection_finder);
   ExpectRemoveObserver();
 
-  PrepareDevice(kServiceUUID, kTestRemoteDeviceBluetoothAddress, true);
+  PrepareDevice(kServiceUUID, cryptauth::kTestRemoteDeviceBluetoothAddress,
+                true);
   connection_finder.ExpectCreateConnection();
   connection_finder.DeviceChanged(adapter_.get(), device_.get());
 }
@@ -339,15 +346,16 @@
   ExpectRemoveObserver();
 
   // Prepare to add |device_|.
-  PrepareDevice(kServiceUUID, kTestRemoteDeviceBluetoothAddress, true);
+  PrepareDevice(kServiceUUID, cryptauth::kTestRemoteDeviceBluetoothAddress,
+                true);
 
   // Prepare to add |other_device|.
   NiceMock<device::MockBluetoothDevice> other_device(
-      adapter_.get(), 0, kTestRemoteDeviceName,
-      kTestRemoteDeviceBluetoothAddress, false, false);
+      adapter_.get(), 0, cryptauth::kTestRemoteDeviceName,
+      cryptauth::kTestRemoteDeviceBluetoothAddress, false, false);
   BluetoothDevice::UUIDSet uuids = {device::BluetoothUUID(kServiceUUID)};
   ON_CALL(other_device, GetAddress())
-      .WillByDefault(Return(kTestRemoteDeviceBluetoothAddress));
+      .WillByDefault(Return(cryptauth::kTestRemoteDeviceBluetoothAddress));
   ON_CALL(other_device, IsPaired()).WillByDefault(Return(true));
   ON_CALL(other_device, GetUUIDs()).WillByDefault((Return(uuids)));
 
@@ -368,15 +376,17 @@
   ExpectRemoveObserver();
 
   // Finding and creating a connection to the right device.
-  FakeConnection* connection = connection_finder.ExpectCreateConnection();
-  PrepareDevice(kServiceUUID, kTestRemoteDeviceBluetoothAddress, true);
+  cryptauth::FakeConnection* connection =
+      connection_finder.ExpectCreateConnection();
+  PrepareDevice(kServiceUUID, cryptauth::kTestRemoteDeviceBluetoothAddress,
+                true);
   connection_finder.DeviceAdded(adapter_.get(), device_.get());
 
   // Creating a connection.
   base::RunLoop run_loop;
   EXPECT_FALSE(last_found_connection_);
-  connection->SetStatus(Connection::IN_PROGRESS);
-  connection->SetStatus(Connection::CONNECTED);
+  connection->SetStatus(cryptauth::Connection::IN_PROGRESS);
+  connection->SetStatus(cryptauth::Connection::CONNECTED);
   run_loop.RunUntilIdle();
   EXPECT_TRUE(last_found_connection_);
 }
@@ -390,13 +400,15 @@
   FindAndExpectStartDiscovery(connection_finder);
 
   // Preparing to create a GATT connection to the right device.
-  PrepareDevice(kServiceUUID, kTestRemoteDeviceBluetoothAddress, true);
-  FakeConnection* connection = connection_finder.ExpectCreateConnection();
+  PrepareDevice(kServiceUUID, cryptauth::kTestRemoteDeviceBluetoothAddress,
+                true);
+  cryptauth::FakeConnection* connection =
+      connection_finder.ExpectCreateConnection();
 
   // Trying to create a connection.
   connection_finder.DeviceAdded(adapter_.get(), device_.get());
   ASSERT_FALSE(last_found_connection_);
-  connection->SetStatus(Connection::IN_PROGRESS);
+  connection->SetStatus(cryptauth::Connection::IN_PROGRESS);
 
   // Preparing to restart the discovery session.
   device::BluetoothAdapter::DiscoverySessionCallback discovery_callback;
@@ -408,7 +420,7 @@
   // Connection fails.
   {
     base::RunLoop run_loop;
-    connection->SetStatus(Connection::DISCONNECTED);
+    connection->SetStatus(cryptauth::Connection::DISCONNECTED);
     run_loop.RunUntilIdle();
   }
 
@@ -422,7 +434,8 @@
   discovery_callback.Run(std::move(discovery_session));
 
   // Preparing to create a GATT connection to the right device.
-  PrepareDevice(kServiceUUID, kTestRemoteDeviceBluetoothAddress, true);
+  PrepareDevice(kServiceUUID, cryptauth::kTestRemoteDeviceBluetoothAddress,
+                true);
   connection = connection_finder.ExpectCreateConnection();
 
   // Trying to create a connection.
@@ -432,8 +445,8 @@
   {
     base::RunLoop run_loop;
     EXPECT_FALSE(last_found_connection_);
-    connection->SetStatus(Connection::IN_PROGRESS);
-    connection->SetStatus(Connection::CONNECTED);
+    connection->SetStatus(cryptauth::Connection::IN_PROGRESS);
+    connection->SetStatus(cryptauth::Connection::CONNECTED);
     run_loop.RunUntilIdle();
   }
   EXPECT_TRUE(last_found_connection_);
@@ -476,8 +489,10 @@
   discovery_callback.Run(std::move(discovery_session));
 
   // Preparing to create a GATT connection to the right device.
-  PrepareDevice(kServiceUUID, kTestRemoteDeviceBluetoothAddress, true);
-  FakeConnection* connection = connection_finder.ExpectCreateConnection();
+  PrepareDevice(kServiceUUID, cryptauth::kTestRemoteDeviceBluetoothAddress,
+                true);
+  cryptauth::FakeConnection* connection =
+      connection_finder.ExpectCreateConnection();
 
   // Trying to create a connection.
   connection_finder.DeviceAdded(adapter_.get(), device_.get());
@@ -485,8 +500,8 @@
   // Completing the connection.
   base::RunLoop run_loop;
   ASSERT_FALSE(last_found_connection_);
-  connection->SetStatus(Connection::IN_PROGRESS);
-  connection->SetStatus(Connection::CONNECTED);
+  connection->SetStatus(cryptauth::Connection::IN_PROGRESS);
+  connection->SetStatus(cryptauth::Connection::CONNECTED);
   run_loop.RunUntilIdle();
   EXPECT_TRUE(last_found_connection_);
 }
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_connection_unittest.cc b/components/proximity_auth/ble/bluetooth_low_energy_connection_unittest.cc
index 87c814fe..4266d8e 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_connection_unittest.cc
+++ b/components/proximity_auth/ble/bluetooth_low_energy_connection_unittest.cc
@@ -16,12 +16,12 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/test/test_simple_task_runner.h"
+#include "components/cryptauth/ble/bluetooth_low_energy_characteristics_finder.h"
+#include "components/cryptauth/bluetooth_throttler.h"
+#include "components/cryptauth/connection_finder.h"
+#include "components/cryptauth/cryptauth_test_util.h"
 #include "components/cryptauth/remote_device.h"
-#include "components/proximity_auth/ble/bluetooth_low_energy_characteristics_finder.h"
-#include "components/proximity_auth/bluetooth_throttler.h"
-#include "components/proximity_auth/connection_finder.h"
-#include "components/proximity_auth/proximity_auth_test_util.h"
-#include "components/proximity_auth/wire_message.h"
+#include "components/cryptauth/wire_message.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"
 #include "device/bluetooth/bluetooth_uuid.h"
@@ -62,20 +62,20 @@
 
 const int kMaxNumberOfTries = 3;
 
-class MockBluetoothThrottler : public BluetoothThrottler {
+class MockBluetoothThrottler : public cryptauth::BluetoothThrottler {
  public:
   MockBluetoothThrottler() {}
   ~MockBluetoothThrottler() override {}
 
   MOCK_CONST_METHOD0(GetDelay, base::TimeDelta());
-  MOCK_METHOD1(OnConnection, void(Connection* connection));
+  MOCK_METHOD1(OnConnection, void(cryptauth::Connection* connection));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockBluetoothThrottler);
 };
 
 class MockBluetoothLowEnergyCharacteristicsFinder
-    : public BluetoothLowEnergyCharacteristicsFinder {
+    : public cryptauth::BluetoothLowEnergyCharacteristicsFinder {
  public:
   MockBluetoothLowEnergyCharacteristicsFinder() {}
   ~MockBluetoothLowEnergyCharacteristicsFinder() override {}
@@ -90,7 +90,7 @@
       const cryptauth::RemoteDevice& remote_device,
       scoped_refptr<device::BluetoothAdapter> adapter,
       const device::BluetoothUUID remote_service_uuid,
-      BluetoothThrottler* bluetooth_throttler,
+      cryptauth::BluetoothThrottler* bluetooth_throttler,
       int max_number_of_write_attempts)
       : BluetoothLowEnergyConnection(remote_device,
                                      adapter,
@@ -100,15 +100,15 @@
 
   ~MockBluetoothLowEnergyConnection() override {}
 
-  MOCK_METHOD2(
-      CreateCharacteristicsFinder,
-      BluetoothLowEnergyCharacteristicsFinder*(
-          const BluetoothLowEnergyCharacteristicsFinder::SuccessCallback&
-              success,
-          const BluetoothLowEnergyCharacteristicsFinder::ErrorCallback& error));
+  MOCK_METHOD2(CreateCharacteristicsFinder,
+               cryptauth::BluetoothLowEnergyCharacteristicsFinder*(
+                   const cryptauth::BluetoothLowEnergyCharacteristicsFinder::
+                       SuccessCallback& success,
+                   const cryptauth::BluetoothLowEnergyCharacteristicsFinder::
+                       ErrorCallback& error));
 
   MOCK_METHOD2(OnDidSendMessage,
-               void(const WireMessage& message, bool success));
+               void(const cryptauth::WireMessage& message, bool success));
   MOCK_METHOD1(OnBytesReceived, void(const std::string& bytes));
 
   // Exposing inherited protected methods for testing.
@@ -129,7 +129,7 @@
  public:
   ProximityAuthBluetoothLowEnergyConnectionTest()
       : adapter_(new NiceMock<device::MockBluetoothAdapter>),
-        remote_device_(CreateLERemoteDeviceForTest()),
+        remote_device_(cryptauth::CreateLERemoteDeviceForTest()),
         service_uuid_(device::BluetoothUUID(kServiceUUID)),
         to_peripheral_char_uuid_(device::BluetoothUUID(kToPeripheralCharUUID)),
         from_peripheral_char_uuid_(
@@ -140,8 +140,8 @@
 
   void SetUp() override {
     device_ = base::MakeUnique<NiceMock<device::MockBluetoothDevice>>(
-        adapter_.get(), 0, kTestRemoteDeviceName,
-        kTestRemoteDeviceBluetoothAddress, false, false);
+        adapter_.get(), 0, cryptauth::kTestRemoteDeviceName,
+        cryptauth::kTestRemoteDeviceBluetoothAddress, false, false);
 
     service_ = base::MakeUnique<NiceMock<device::MockBluetoothGattService>>(
         device_.get(), kServiceID, service_uuid_, true, false);
@@ -162,7 +162,7 @@
     std::vector<const device::BluetoothDevice*> devices;
     devices.push_back(device_.get());
     ON_CALL(*adapter_, GetDevices()).WillByDefault(Return(devices));
-    ON_CALL(*adapter_, GetDevice(kTestRemoteDeviceBluetoothAddress))
+    ON_CALL(*adapter_, GetDevice(cryptauth::kTestRemoteDeviceBluetoothAddress))
         .WillByDefault(Return(device_.get()));
     ON_CALL(*device_, GetGattService(kServiceID))
         .WillByDefault(Return(service_.get()));
@@ -185,7 +185,7 @@
 
     EXPECT_EQ(connection->sub_status(),
               BluetoothLowEnergyConnection::SubStatus::DISCONNECTED);
-    EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+    EXPECT_EQ(connection->status(), cryptauth::Connection::DISCONNECTED);
 
     connection->SetTaskRunnerForTesting(task_runner_);
 
@@ -208,7 +208,7 @@
 
     EXPECT_EQ(connection->sub_status(),
               BluetoothLowEnergyConnection::SubStatus::WAITING_GATT_CONNECTION);
-    EXPECT_EQ(connection->status(), Connection::IN_PROGRESS);
+    EXPECT_EQ(connection->status(), cryptauth::Connection::IN_PROGRESS);
 
     // Preparing |connection| to run |create_gatt_connection_success_callback_|.
     EXPECT_FALSE(create_gatt_connection_error_callback_.is_null());
@@ -221,11 +221,11 @@
 
     create_gatt_connection_success_callback_.Run(
         base::MakeUnique<NiceMock<device::MockBluetoothGattConnection>>(
-            adapter_, kTestRemoteDeviceBluetoothAddress));
+            adapter_, cryptauth::kTestRemoteDeviceBluetoothAddress));
 
     EXPECT_EQ(connection->sub_status(),
               BluetoothLowEnergyConnection::SubStatus::WAITING_CHARACTERISTICS);
-    EXPECT_EQ(connection->status(), Connection::IN_PROGRESS);
+    EXPECT_EQ(connection->status(), cryptauth::Connection::IN_PROGRESS);
   }
 
   // Transitions |connection| from WAITING_CHARACTERISTICS to
@@ -244,7 +244,7 @@
 
     EXPECT_EQ(connection->sub_status(),
               BluetoothLowEnergyConnection::SubStatus::WAITING_NOTIFY_SESSION);
-    EXPECT_EQ(connection->status(), Connection::IN_PROGRESS);
+    EXPECT_EQ(connection->status(), cryptauth::Connection::IN_PROGRESS);
   }
 
   // Transitions |connection| from WAITING_NOTIFY_SESSION to
@@ -269,7 +269,7 @@
 
     EXPECT_EQ(connection->sub_status(),
               BluetoothLowEnergyConnection::SubStatus::WAITING_RESPONSE_SIGNAL);
-    EXPECT_EQ(connection->status(), Connection::IN_PROGRESS);
+    EXPECT_EQ(connection->status(), cryptauth::Connection::IN_PROGRESS);
   }
 
   // Transitions |connection| from WAITING_RESPONSE_SIGNAL to CONNECTED state.
@@ -295,7 +295,7 @@
 
     EXPECT_EQ(connection->sub_status(),
               BluetoothLowEnergyConnection::SubStatus::CONNECTED);
-    EXPECT_EQ(connection->status(), Connection::CONNECTED);
+    EXPECT_EQ(connection->status(), cryptauth::Connection::CONNECTED);
   }
 
   // Transitions |connection| to a DISCONNECTED state regardless of its initial
@@ -309,7 +309,7 @@
 
     EXPECT_EQ(connection->sub_status(),
               BluetoothLowEnergyConnection::SubStatus::DISCONNECTED);
-    EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+    EXPECT_EQ(connection->status(), cryptauth::Connection::DISCONNECTED);
   }
 
   void InitializeConnection(MockBluetoothLowEnergyConnection* connection) {
@@ -375,9 +375,9 @@
   device::BluetoothDevice::ConnectErrorCallback
       create_gatt_connection_error_callback_;
 
-  BluetoothLowEnergyCharacteristicsFinder::SuccessCallback
+  cryptauth::BluetoothLowEnergyCharacteristicsFinder::SuccessCallback
       characteristics_finder_success_callback_;
-  BluetoothLowEnergyCharacteristicsFinder::ErrorCallback
+  cryptauth::BluetoothLowEnergyCharacteristicsFinder::ErrorCallback
       characteristics_finder_error_callback_;
 
   device::BluetoothRemoteGattCharacteristic::NotifySessionCallback
@@ -464,7 +464,7 @@
 
   EXPECT_EQ(connection->sub_status(),
             BluetoothLowEnergyConnection::SubStatus::DISCONNECTED);
-  EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+  EXPECT_EQ(connection->status(), cryptauth::Connection::DISCONNECTED);
 }
 
 TEST_F(ProximityAuthBluetoothLowEnergyConnectionTest,
@@ -484,7 +484,7 @@
 
   EXPECT_EQ(connection->sub_status(),
             BluetoothLowEnergyConnection::SubStatus::DISCONNECTED);
-  EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+  EXPECT_EQ(connection->status(), cryptauth::Connection::DISCONNECTED);
 }
 
 TEST_F(ProximityAuthBluetoothLowEnergyConnectionTest,
@@ -521,7 +521,7 @@
 
   EXPECT_EQ(connection->sub_status(),
             BluetoothLowEnergyConnection::SubStatus::DISCONNECTED);
-  EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+  EXPECT_EQ(connection->status(), cryptauth::Connection::DISCONNECTED);
 }
 
 TEST_F(ProximityAuthBluetoothLowEnergyConnectionTest,
@@ -598,7 +598,8 @@
   int message_size = 100;
   std::string message(message_size, 'A');
   message[0] = 'B';
-  connection->SendMessage(base::MakeUnique<FakeWireMessage>(message));
+  connection->SendMessage(
+      base::MakeUnique<cryptauth::FakeWireMessage>(message));
 
   // Expecting that |kSendSignal| + |message_size| + |message| was written.
   EXPECT_EQ(last_value_written_on_to_peripheral_char_,
@@ -626,7 +627,8 @@
   int message_size = 600;
   std::string message(message_size, 'A');
   message[0] = 'B';
-  connection->SendMessage(base::MakeUnique<FakeWireMessage>(message));
+  connection->SendMessage(
+      base::MakeUnique<cryptauth::FakeWireMessage>(message));
 
   // Expecting that |kSendSignal| + |message_size| was written in the first 8
   // bytes.
@@ -675,7 +677,7 @@
   connection->Connect();
   EXPECT_EQ(connection->sub_status(),
             BluetoothLowEnergyConnection::SubStatus::WAITING_GATT_CONNECTION);
-  EXPECT_EQ(connection->status(), Connection::IN_PROGRESS);
+  EXPECT_EQ(connection->status(), cryptauth::Connection::IN_PROGRESS);
   EXPECT_TRUE(create_gatt_connection_error_callback_.is_null());
   EXPECT_TRUE(create_gatt_connection_success_callback_.is_null());
 
@@ -693,7 +695,7 @@
 
   create_gatt_connection_success_callback_.Run(
       base::MakeUnique<NiceMock<device::MockBluetoothGattConnection>>(
-          adapter_, kTestRemoteDeviceBluetoothAddress));
+          adapter_, cryptauth::kTestRemoteDeviceBluetoothAddress));
 
   CharacteristicsFound(connection.get());
   NotifySessionStarted(connection.get());
diff --git a/components/proximity_auth/bluetooth_connection.cc b/components/proximity_auth/bluetooth_connection.cc
index 511e7ef..563446d 100644
--- a/components/proximity_auth/bluetooth_connection.cc
+++ b/components/proximity_auth/bluetooth_connection.cc
@@ -12,8 +12,8 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/cryptauth/remote_device.h"
+#include "components/cryptauth/wire_message.h"
 #include "components/proximity_auth/logging/logging.h"
-#include "components/proximity_auth/wire_message.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "device/bluetooth/bluetooth_device.h"
 #include "net/base/io_buffer.h"
@@ -26,7 +26,9 @@
 BluetoothConnection::BluetoothConnection(
     const cryptauth::RemoteDevice& remote_device,
     const device::BluetoothUUID& uuid)
-    : Connection(remote_device), uuid_(uuid), weak_ptr_factory_(this) {}
+    : cryptauth::Connection(remote_device),
+      uuid_(uuid),
+      weak_ptr_factory_(this) {}
 
 BluetoothConnection::~BluetoothConnection() {
   if (status() != DISCONNECTED)
@@ -73,7 +75,7 @@
 }
 
 void BluetoothConnection::SendMessageImpl(
-    std::unique_ptr<WireMessage> message) {
+    std::unique_ptr<cryptauth::WireMessage> message) {
   DCHECK_EQ(status(), CONNECTED);
 
   // Serialize the message.
diff --git a/components/proximity_auth/bluetooth_connection.h b/components/proximity_auth/bluetooth_connection.h
index ccebdbd..4099f57f 100644
--- a/components/proximity_auth/bluetooth_connection.h
+++ b/components/proximity_auth/bluetooth_connection.h
@@ -10,7 +10,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "components/proximity_auth/connection.h"
+#include "components/cryptauth/connection.h"
 #include "device/bluetooth/bluetooth_adapter.h"
 #include "device/bluetooth/bluetooth_device.h"
 #include "device/bluetooth/bluetooth_socket.h"
@@ -28,7 +28,7 @@
 
 // Represents a Bluetooth connection with a remote device. The connection is a
 // persistent bidirectional channel for sending and receiving wire messages.
-class BluetoothConnection : public Connection,
+class BluetoothConnection : public cryptauth::Connection,
                             public device::BluetoothAdapter::Observer {
  public:
   // Constructs a Bluetooth connection to the service with |uuid| on the
@@ -44,7 +44,8 @@
 
  protected:
   // Connection:
-  void SendMessageImpl(std::unique_ptr<WireMessage> message) override;
+  void SendMessageImpl(
+      std::unique_ptr<cryptauth::WireMessage> message) override;
 
   // BluetoothAdapter::Observer:
   void DeviceChanged(device::BluetoothAdapter* adapter,
@@ -80,7 +81,7 @@
 
   // The message that was sent over the backing |socket_|. NULL iff there is no
   // send operation in progress.
-  std::unique_ptr<WireMessage> pending_message_;
+  std::unique_ptr<cryptauth::WireMessage> pending_message_;
 
   base::WeakPtrFactory<BluetoothConnection> weak_ptr_factory_;
 
diff --git a/components/proximity_auth/bluetooth_connection_finder.cc b/components/proximity_auth/bluetooth_connection_finder.cc
index 39f240fe7..fd48587 100644
--- a/components/proximity_auth/bluetooth_connection_finder.cc
+++ b/components/proximity_auth/bluetooth_connection_finder.cc
@@ -11,6 +11,7 @@
 #include "base/logging.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "components/cryptauth/connection.h"
 #include "components/proximity_auth/bluetooth_connection.h"
 #include "components/proximity_auth/logging/logging.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
@@ -34,7 +35,8 @@
 }
 
 void BluetoothConnectionFinder::Find(
-    const ConnectionCallback& connection_callback) {
+    const cryptauth::ConnectionFinder::ConnectionCallback&
+        connection_callback) {
   if (!device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) {
     PA_LOG(WARNING) << "Bluetooth is unsupported on this platform. Aborting.";
     return;
@@ -50,8 +52,9 @@
                  weak_ptr_factory_.GetWeakPtr()));
 }
 
-std::unique_ptr<Connection> BluetoothConnectionFinder::CreateConnection() {
-  return std::unique_ptr<Connection>(
+std::unique_ptr<cryptauth::Connection>
+BluetoothConnectionFinder::CreateConnection() {
+  return std::unique_ptr<cryptauth::Connection>(
       new BluetoothConnection(remote_device_, uuid_));
 }
 
@@ -84,7 +87,8 @@
 
   // If the |connection_| is pending, wait for it to connect or fail prior to
   // polling again.
-  if (connection_ && connection_->status() != Connection::DISCONNECTED)
+  if (connection_ &&
+      connection_->status() != cryptauth::Connection::DISCONNECTED)
     return;
 
   // This SeekDeviceByAddress operation is needed to connect to a device if
@@ -174,9 +178,9 @@
 }
 
 void BluetoothConnectionFinder::OnConnectionStatusChanged(
-    Connection* connection,
-    Connection::Status old_status,
-    Connection::Status new_status) {
+    cryptauth::Connection* connection,
+    cryptauth::Connection::Status old_status,
+    cryptauth::Connection::Status new_status) {
   DCHECK_EQ(connection, connection_.get());
 
   if (connection_->IsConnected()) {
@@ -186,13 +190,14 @@
     UnregisterAsObserver();
 
     // If we invoke the callback now, the callback function may install its own
-    // observer to |connection_|. Because we are in the ConnectionObserver
+    // observer to |connection_|. Because we are in the
+    // cryptauth::ConnectionObserver
     // callstack, this new observer will receive this connection event.
     // Therefore, we need to invoke the callback asynchronously.
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&BluetoothConnectionFinder::InvokeCallbackAsync,
                               weak_ptr_factory_.GetWeakPtr()));
-  } else if (old_status == Connection::IN_PROGRESS) {
+  } else if (old_status == cryptauth::Connection::IN_PROGRESS) {
     PA_LOG(WARNING)
         << "Connection failed! Scheduling another polling iteration.";
     PostDelayedPoll();
diff --git a/components/proximity_auth/bluetooth_connection_finder.h b/components/proximity_auth/bluetooth_connection_finder.h
index a2f5ee7..c3625fe 100644
--- a/components/proximity_auth/bluetooth_connection_finder.h
+++ b/components/proximity_auth/bluetooth_connection_finder.h
@@ -12,19 +12,21 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
+#include "components/cryptauth/connection.h"
+#include "components/cryptauth/connection_finder.h"
+#include "components/cryptauth/connection_observer.h"
 #include "components/cryptauth/remote_device.h"
 #include "components/proximity_auth/bluetooth_util.h"
-#include "components/proximity_auth/connection_finder.h"
-#include "components/proximity_auth/connection_observer.h"
 #include "device/bluetooth/bluetooth_adapter.h"
 #include "device/bluetooth/bluetooth_uuid.h"
 
 namespace proximity_auth {
 
-// This ConnectionFinder implementation tries to find a Bluetooth connection to
+// This cryptauth::ConnectionFinder implementation tries to find a Bluetooth
+// connection to
 // the remote device by polling at a fixed interval.
-class BluetoothConnectionFinder : public ConnectionFinder,
-                                  public ConnectionObserver,
+class BluetoothConnectionFinder : public cryptauth::ConnectionFinder,
+                                  public cryptauth::ConnectionObserver,
                                   public device::BluetoothAdapter::Observer {
  public:
   BluetoothConnectionFinder(const cryptauth::RemoteDevice& remote_device,
@@ -32,12 +34,13 @@
                             const base::TimeDelta& polling_interval);
   ~BluetoothConnectionFinder() override;
 
-  // ConnectionFinder:
-  void Find(const ConnectionCallback& connection_callback) override;
+  // cryptauth::ConnectionFinder:
+  void Find(const cryptauth::ConnectionFinder::ConnectionCallback&
+                connection_callback) override;
 
  protected:
   // Exposed for mocking out the connection in tests.
-  virtual std::unique_ptr<Connection> CreateConnection();
+  virtual std::unique_ptr<cryptauth::Connection> CreateConnection();
 
   // Calls bluetooth_util::SeekDeviceByAddress. Exposed for testing, as this
   // utility function is platform dependent.
@@ -77,9 +80,10 @@
   void OnAdapterInitialized(scoped_refptr<device::BluetoothAdapter> adapter);
 
   // ConnectionObserver:
-  void OnConnectionStatusChanged(Connection* connection,
-                                 Connection::Status old_status,
-                                 Connection::Status new_status) override;
+  void OnConnectionStatusChanged(
+      cryptauth::Connection* connection,
+      cryptauth::Connection::Status old_status,
+      cryptauth::Connection::Status new_status) override;
 
   // Used to invoke |connection_callback_| asynchronously, decoupling the
   // callback invocation from the ConnectionObserver callstack.
@@ -98,13 +102,13 @@
   base::TimeTicks start_time_;
 
   // The callback that should be called upon a successful connection.
-  ConnectionCallback connection_callback_;
+  cryptauth::ConnectionFinder::ConnectionCallback connection_callback_;
 
   // The Bluetooth adapter over which the Bluetooth connection will be made.
   scoped_refptr<device::BluetoothAdapter> adapter_;
 
   // The Bluetooth connection that will be opened.
-  std::unique_ptr<Connection> connection_;
+  std::unique_ptr<cryptauth::Connection> connection_;
 
   // Whether there is currently a polling task scheduled.
   bool has_delayed_poll_scheduled_;
diff --git a/components/proximity_auth/bluetooth_connection_finder_unittest.cc b/components/proximity_auth/bluetooth_connection_finder_unittest.cc
index 49b4579..56488bd 100644
--- a/components/proximity_auth/bluetooth_connection_finder_unittest.cc
+++ b/components/proximity_auth/bluetooth_connection_finder_unittest.cc
@@ -14,9 +14,9 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/time/time.h"
+#include "components/cryptauth/cryptauth_test_util.h"
 #include "components/cryptauth/remote_device.h"
-#include "components/proximity_auth/proximity_auth_test_util.h"
-#include "components/proximity_auth/wire_message.h"
+#include "components/cryptauth/wire_message.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "device/bluetooth/bluetooth_uuid.h"
 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
@@ -34,26 +34,27 @@
 
 const char kUuid[] = "DEADBEEF-CAFE-FEED-FOOD-D15EA5EBEEF";
 
-class MockConnection : public Connection {
+class MockConnection : public cryptauth::Connection {
  public:
   MockConnection()
-      : Connection(CreateClassicRemoteDeviceForTest()),
+      : Connection(cryptauth::CreateClassicRemoteDeviceForTest()),
         do_not_destroy_(false) {}
   ~MockConnection() override { EXPECT_FALSE(do_not_destroy_); }
 
   MOCK_METHOD0(Connect, void());
 
-  void SetStatus(Connection::Status status) {
+  void SetStatus(cryptauth::Connection::Status status) {
     // This object should not be destroyed after setting the status and calling
     // observers.
     do_not_destroy_ = true;
-    Connection::SetStatus(status);
+    cryptauth::Connection::SetStatus(status);
     do_not_destroy_ = false;
   }
 
  private:
   void Disconnect() override {}
-  void SendMessageImpl(std::unique_ptr<WireMessage> message) override {}
+  void SendMessageImpl(
+      std::unique_ptr<cryptauth::WireMessage> message) override {}
 
   // If true, we do not expect |this| object to be destroyed until this value is
   // toggled back to false.
@@ -65,12 +66,12 @@
 class MockBluetoothConnectionFinder : public BluetoothConnectionFinder {
  public:
   MockBluetoothConnectionFinder()
-      : BluetoothConnectionFinder(CreateClassicRemoteDeviceForTest(),
+      : BluetoothConnectionFinder(cryptauth::CreateClassicRemoteDeviceForTest(),
                                   device::BluetoothUUID(kUuid),
                                   base::TimeDelta()) {}
   ~MockBluetoothConnectionFinder() override {}
 
-  MOCK_METHOD0(CreateConnectionProxy, Connection*());
+  MOCK_METHOD0(CreateConnectionProxy, cryptauth::Connection*());
 
   // Creates a mock connection and sets an expectation that the mock connection
   // finder's CreateConnection() method will be called and will return the
@@ -100,7 +101,7 @@
 
  protected:
   // BluetoothConnectionFinder:
-  std::unique_ptr<Connection> CreateConnection() override {
+  std::unique_ptr<cryptauth::Connection> CreateConnection() override {
     return base::WrapUnique(CreateConnectionProxy());
   }
 
@@ -108,7 +109,7 @@
       const std::string& bluetooth_address,
       const base::Closure& callback,
       const bluetooth_util::ErrorCallback& error_callback) override {
-    EXPECT_EQ(kTestRemoteDeviceBluetoothAddress, bluetooth_address);
+    EXPECT_EQ(cryptauth::kTestRemoteDeviceBluetoothAddress, bluetooth_address);
     seek_callback_ = callback;
     seek_error_callback_ = error_callback;
   }
@@ -129,8 +130,8 @@
         bluetooth_device_(new NiceMock<device::MockBluetoothDevice>(
             adapter_.get(),
             static_cast<uint32_t>(device::BluetoothDeviceType::PHONE),
-            kTestRemoteDeviceName,
-            kTestRemoteDeviceBluetoothAddress,
+            cryptauth::kTestRemoteDeviceName,
+            cryptauth::kTestRemoteDeviceBluetoothAddress,
             true,
             false)),
         connection_callback_(base::Bind(
@@ -145,12 +146,12 @@
 
     // By default, the remote device is known to |adapter_| so
     // |SeekDeviceByAddress()| will not be called.
-    ON_CALL(*adapter_, GetDevice(kTestRemoteDeviceBluetoothAddress))
+    ON_CALL(*adapter_, GetDevice(cryptauth::kTestRemoteDeviceBluetoothAddress))
         .WillByDefault(Return(bluetooth_device_.get()));
   }
 
-  MOCK_METHOD1(OnConnectionFoundProxy, void(Connection* connection));
-  void OnConnectionFound(std::unique_ptr<Connection> connection) {
+  MOCK_METHOD1(OnConnectionFoundProxy, void(cryptauth::Connection* connection));
+  void OnConnectionFound(std::unique_ptr<cryptauth::Connection> connection) {
     OnConnectionFoundProxy(connection.get());
     last_found_connection_ = std::move(connection);
   }
@@ -168,21 +169,21 @@
   // Given an in-progress |connection| returned by |StartConnectionFinder()|,
   // simulate it transitioning to the CONNECTED state.
   void SimulateDeviceConnection(MockConnection* connection) {
-    connection->SetStatus(Connection::IN_PROGRESS);
+    connection->SetStatus(cryptauth::Connection::IN_PROGRESS);
     base::RunLoop run_loop;
     EXPECT_CALL(*this, OnConnectionFoundProxy(_));
-    connection->SetStatus(Connection::CONNECTED);
+    connection->SetStatus(cryptauth::Connection::CONNECTED);
     run_loop.RunUntilIdle();
   }
 
   scoped_refptr<device::MockBluetoothAdapter> adapter_;
   StrictMock<MockBluetoothConnectionFinder> connection_finder_;
   std::unique_ptr<device::MockBluetoothDevice> bluetooth_device_;
-  ConnectionFinder::ConnectionCallback connection_callback_;
+  cryptauth::ConnectionFinder::ConnectionCallback connection_callback_;
 
  private:
   // Save a pointer to the last found connection, to extend its lifetime.
-  std::unique_ptr<Connection> last_found_connection_;
+  std::unique_ptr<cryptauth::Connection> last_found_connection_;
 
   base::MessageLoop message_loop_;
 };
@@ -192,8 +193,8 @@
   // Destroying a BluetoothConnectionFinder for which Find() has not been called
   // should not crash.
   BluetoothConnectionFinder connection_finder(
-      CreateClassicRemoteDeviceForTest(), device::BluetoothUUID(kUuid),
-      base::TimeDelta::FromMilliseconds(1));
+      cryptauth::CreateClassicRemoteDeviceForTest(),
+      device::BluetoothUUID(kUuid), base::TimeDelta::FromMilliseconds(1));
 }
 
 TEST_F(ProximityAuthBluetoothConnectionFinderTest, Find_NoBluetoothAdapter) {
@@ -235,8 +236,8 @@
   // be ignored.
   base::RunLoop run_loop;
   EXPECT_CALL(*this, OnConnectionFoundProxy(_)).Times(0);
-  connection->SetStatus(Connection::IN_PROGRESS);
-  connection->SetStatus(Connection::CONNECTED);
+  connection->SetStatus(cryptauth::Connection::IN_PROGRESS);
+  connection->SetStatus(cryptauth::Connection::CONNECTED);
   run_loop.RunUntilIdle();
 }
 
@@ -245,8 +246,8 @@
   MockConnection* connection = StartConnectionFinder(true);
 
   // Simulate a connection that fails to connect.
-  connection->SetStatus(Connection::IN_PROGRESS);
-  connection->SetStatus(Connection::DISCONNECTED);
+  connection->SetStatus(cryptauth::Connection::IN_PROGRESS);
+  connection->SetStatus(cryptauth::Connection::DISCONNECTED);
 
   // A task should have been posted to poll again.
   base::RunLoop run_loop;
@@ -278,7 +279,7 @@
        Find_DoesNotPollIfConnectionPending) {
   MockConnection* connection = StartConnectionFinder(true);
 
-  connection->SetStatus(Connection::IN_PROGRESS);
+  connection->SetStatus(cryptauth::Connection::IN_PROGRESS);
 
   // At this point, there is a pending connection in progress. Hence, an event
   // that would normally trigger a new polling iteration should not do so now,
@@ -292,8 +293,8 @@
        Find_ConnectionFails_PostsTaskToPollAgain_PollWaitsForTask) {
   MockConnection* connection = StartConnectionFinder(true);
 
-  connection->SetStatus(Connection::IN_PROGRESS);
-  connection->SetStatus(Connection::DISCONNECTED);
+  connection->SetStatus(cryptauth::Connection::IN_PROGRESS);
+  connection->SetStatus(cryptauth::Connection::DISCONNECTED);
 
   // At this point, there is a pending poll scheduled. Hence, an event that
   // would normally trigger a new polling iteration should not do so now,
@@ -319,14 +320,14 @@
        Find_DeviceNotKnown_SeekDeviceSucceeds) {
   // If the BluetoothDevice is not known by the adapter, |connection_finder|
   // will call SeekDeviceByAddress() first to make it known.
-  ON_CALL(*adapter_, GetDevice(kTestRemoteDeviceBluetoothAddress))
+  ON_CALL(*adapter_, GetDevice(cryptauth::kTestRemoteDeviceBluetoothAddress))
       .WillByDefault(Return(nullptr));
   connection_finder_.Find(connection_callback_);
   ASSERT_FALSE(connection_finder_.seek_callback().is_null());
   EXPECT_FALSE(connection_finder_.seek_error_callback().is_null());
 
   // After seeking is successful, the normal flow should resume.
-  ON_CALL(*adapter_, GetDevice(kTestRemoteDeviceBluetoothAddress))
+  ON_CALL(*adapter_, GetDevice(cryptauth::kTestRemoteDeviceBluetoothAddress))
       .WillByDefault(Return(bluetooth_device_.get()));
   MockConnection* connection = connection_finder_.ExpectCreateConnection();
   connection_finder_.seek_callback().Run();
@@ -337,7 +338,7 @@
        Find_DeviceNotKnown_SeekDeviceFailThenSucceeds) {
   // If the BluetoothDevice is not known by the adapter, |connection_finder|
   // will call SeekDeviceByAddress() first to make it known.
-  ON_CALL(*adapter_, GetDevice(kTestRemoteDeviceBluetoothAddress))
+  ON_CALL(*adapter_, GetDevice(cryptauth::kTestRemoteDeviceBluetoothAddress))
       .WillByDefault(Return(nullptr));
   connection_finder_.Find(connection_callback_);
   EXPECT_FALSE(connection_finder_.seek_callback().is_null());
@@ -357,7 +358,7 @@
   EXPECT_FALSE(connection_finder_.seek_error_callback().is_null());
 
   // Successfully connect to the Bluetooth device.
-  ON_CALL(*adapter_, GetDevice(kTestRemoteDeviceBluetoothAddress))
+  ON_CALL(*adapter_, GetDevice(cryptauth::kTestRemoteDeviceBluetoothAddress))
       .WillByDefault(Return(bluetooth_device_.get()));
   MockConnection* connection = connection_finder_.ExpectCreateConnection();
   connection_finder_.seek_callback().Run();
diff --git a/components/proximity_auth/bluetooth_connection_unittest.cc b/components/proximity_auth/bluetooth_connection_unittest.cc
index 1c2cd24..e318c21 100644
--- a/components/proximity_auth/bluetooth_connection_unittest.cc
+++ b/components/proximity_auth/bluetooth_connection_unittest.cc
@@ -10,9 +10,9 @@
 #include "base/message_loop/message_loop.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/run_loop.h"
+#include "components/cryptauth/cryptauth_test_util.h"
 #include "components/cryptauth/remote_device.h"
-#include "components/proximity_auth/proximity_auth_test_util.h"
-#include "components/proximity_auth/wire_message.h"
+#include "components/cryptauth/wire_message.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "device/bluetooth/bluetooth_uuid.h"
 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
@@ -54,14 +54,14 @@
 class MockBluetoothConnection : public BluetoothConnection {
  public:
   MockBluetoothConnection()
-      : BluetoothConnection(CreateClassicRemoteDeviceForTest(),
+      : BluetoothConnection(cryptauth::CreateClassicRemoteDeviceForTest(),
                             device::BluetoothUUID(kUuid)) {}
 
   // Calls back into the parent Connection class.
   MOCK_METHOD1(SetStatusProxy, void(Status status));
   MOCK_METHOD1(OnBytesReceived, void(const std::string& bytes));
   MOCK_METHOD2(OnDidSendMessage,
-               void(const WireMessage& message, bool success));
+               void(const cryptauth::WireMessage& message, bool success));
 
   void SetStatus(Status status) override {
     SetStatusProxy(status);
@@ -78,9 +78,9 @@
   DISALLOW_COPY_AND_ASSIGN(MockBluetoothConnection);
 };
 
-class TestWireMessage : public WireMessage {
+class TestWireMessage : public cryptauth::WireMessage {
  public:
-  TestWireMessage() : WireMessage("permit id", "payload") {}
+  TestWireMessage() : cryptauth::WireMessage("permit id", "payload") {}
   ~TestWireMessage() override {}
 
   std::string Serialize() const override { return kSerializedMessage; }
@@ -97,8 +97,8 @@
       : adapter_(new device::MockBluetoothAdapter),
         device_(adapter_.get(),
                 0,
-                kTestRemoteDeviceName,
-                kTestRemoteDeviceBluetoothAddress,
+                cryptauth::kTestRemoteDeviceName,
+                cryptauth::kTestRemoteDeviceBluetoothAddress,
                 true,
                 true),
         socket_(new StrictMock<device::MockBluetoothSocket>),
@@ -111,40 +111,42 @@
 
   // Transition the connection into an in-progress state.
   void BeginConnecting(MockBluetoothConnection* connection) {
-    EXPECT_EQ(Connection::DISCONNECTED, connection->status());
+    EXPECT_EQ(cryptauth::Connection::DISCONNECTED, connection->status());
     ON_CALL(device_, IsConnected()).WillByDefault(Return(false));
 
     ON_CALL(*adapter_, GetDevice(_)).WillByDefault(Return(&device_));
-    EXPECT_CALL(*connection, SetStatusProxy(Connection::IN_PROGRESS));
+    EXPECT_CALL(*connection,
+                SetStatusProxy(cryptauth::Connection::IN_PROGRESS));
     EXPECT_CALL(*adapter_, AddObserver(connection));
     EXPECT_CALL(device_, ConnectToServiceInsecurely(uuid_, _, _));
     connection->Connect();
 
-    EXPECT_EQ(Connection::IN_PROGRESS, connection->status());
+    EXPECT_EQ(cryptauth::Connection::IN_PROGRESS, connection->status());
   }
 
   // Transition the connection into a connected state.
   // Saves the success and error callbacks passed into OnReceive(), which can be
   // accessed via receive_callback() and receive_success_callback().
   void Connect(MockBluetoothConnection* connection) {
-    EXPECT_EQ(Connection::DISCONNECTED, connection->status());
+    EXPECT_EQ(cryptauth::Connection::DISCONNECTED, connection->status());
 
     device::BluetoothDevice::ConnectToServiceCallback callback;
     ON_CALL(*adapter_, GetDevice(_)).WillByDefault(Return(&device_));
-    EXPECT_CALL(*connection, SetStatusProxy(Connection::IN_PROGRESS));
+    EXPECT_CALL(*connection,
+                SetStatusProxy(cryptauth::Connection::IN_PROGRESS));
     EXPECT_CALL(*adapter_, AddObserver(connection));
     EXPECT_CALL(device_, ConnectToServiceInsecurely(_, _, _))
         .WillOnce(SaveArg<1>(&callback));
     connection->Connect();
     ASSERT_FALSE(callback.is_null());
 
-    EXPECT_CALL(*connection, SetStatusProxy(Connection::CONNECTED));
+    EXPECT_CALL(*connection, SetStatusProxy(cryptauth::Connection::CONNECTED));
     EXPECT_CALL(*socket_, Receive(_, _, _))
         .WillOnce(DoAll(SaveArg<1>(&receive_callback_),
                         SaveArg<2>(&receive_error_callback_)));
     callback.Run(socket_);
 
-    EXPECT_EQ(Connection::CONNECTED, connection->status());
+    EXPECT_EQ(cryptauth::Connection::CONNECTED, connection->status());
     ON_CALL(device_, IsConnected()).WillByDefault(Return(true));
   }
 
@@ -215,8 +217,8 @@
   StrictMock<MockBluetoothConnection> connection;
 
   ON_CALL(*adapter_, GetDevice(_)).WillByDefault(Return(nullptr));
-  EXPECT_CALL(connection, SetStatusProxy(Connection::IN_PROGRESS));
-  EXPECT_CALL(connection, SetStatusProxy(Connection::DISCONNECTED));
+  EXPECT_CALL(connection, SetStatusProxy(cryptauth::Connection::IN_PROGRESS));
+  EXPECT_CALL(connection, SetStatusProxy(cryptauth::Connection::DISCONNECTED));
   connection.Connect();
 }
 
@@ -228,7 +230,7 @@
 
   // Remove the device while the connection is in-progress. This should cause
   // the connection to disconnect.
-  EXPECT_CALL(connection, SetStatusProxy(Connection::DISCONNECTED));
+  EXPECT_CALL(connection, SetStatusProxy(cryptauth::Connection::DISCONNECTED));
   EXPECT_CALL(*adapter_, RemoveObserver(&connection));
   connection.DeviceRemoved(adapter_.get(), &device_);
 }
@@ -255,14 +257,14 @@
 
   device::BluetoothDevice::ConnectToServiceErrorCallback error_callback;
   ON_CALL(*adapter_, GetDevice(_)).WillByDefault(Return(&device_));
-  EXPECT_CALL(connection, SetStatusProxy(Connection::IN_PROGRESS));
+  EXPECT_CALL(connection, SetStatusProxy(cryptauth::Connection::IN_PROGRESS));
   EXPECT_CALL(*adapter_, AddObserver(&connection));
   EXPECT_CALL(device_, ConnectToServiceInsecurely(uuid_, _, _))
       .WillOnce(SaveArg<2>(&error_callback));
   connection.Connect();
   ASSERT_FALSE(error_callback.is_null());
 
-  EXPECT_CALL(connection, SetStatusProxy(Connection::DISCONNECTED));
+  EXPECT_CALL(connection, SetStatusProxy(cryptauth::Connection::DISCONNECTED));
   EXPECT_CALL(*adapter_, RemoveObserver(&connection));
   error_callback.Run("super descriptive error message");
 }
@@ -281,7 +283,7 @@
   StrictMock<MockBluetoothConnection> connection;
   Connect(&connection);
 
-  EXPECT_CALL(connection, SetStatusProxy(Connection::DISCONNECTED));
+  EXPECT_CALL(connection, SetStatusProxy(cryptauth::Connection::DISCONNECTED));
   EXPECT_CALL(*socket_, Disconnect(_));
   EXPECT_CALL(*adapter_, RemoveObserver(&connection));
   connection.DeviceRemoved(adapter_.get(), &device_);
@@ -354,7 +356,7 @@
   StrictMock<MockBluetoothConnection> connection;
   BeginConnecting(&connection);
 
-  EXPECT_CALL(connection, SetStatusProxy(Connection::DISCONNECTED));
+  EXPECT_CALL(connection, SetStatusProxy(cryptauth::Connection::DISCONNECTED));
   EXPECT_CALL(*adapter_, RemoveObserver(&connection));
   connection.Disconnect();
 }
@@ -365,7 +367,7 @@
   StrictMock<MockBluetoothConnection> connection;
   Connect(&connection);
 
-  EXPECT_CALL(connection, SetStatusProxy(Connection::DISCONNECTED));
+  EXPECT_CALL(connection, SetStatusProxy(cryptauth::Connection::DISCONNECTED));
   EXPECT_CALL(*socket_, Disconnect(_));
   EXPECT_CALL(*adapter_, RemoveObserver(&connection));
   connection.Disconnect();
@@ -376,14 +378,14 @@
   StrictMock<MockBluetoothConnection> connection;
   device::BluetoothDevice::ConnectToServiceCallback callback;
   ON_CALL(*adapter_, GetDevice(_)).WillByDefault(Return(&device_));
-  EXPECT_CALL(connection, SetStatusProxy(Connection::IN_PROGRESS));
+  EXPECT_CALL(connection, SetStatusProxy(cryptauth::Connection::IN_PROGRESS));
   EXPECT_CALL(*adapter_, AddObserver(&connection));
   EXPECT_CALL(device_, ConnectToServiceInsecurely(uuid_, _, _))
       .WillOnce(SaveArg<1>(&callback));
   connection.Connect();
   ASSERT_FALSE(callback.is_null());
 
-  EXPECT_CALL(connection, SetStatusProxy(Connection::DISCONNECTED));
+  EXPECT_CALL(connection, SetStatusProxy(cryptauth::Connection::DISCONNECTED));
   EXPECT_CALL(*adapter_, RemoveObserver(&connection));
   connection.Disconnect();
 
@@ -449,7 +451,7 @@
 
   ASSERT_FALSE(error_callback.is_null());
   EXPECT_CALL(connection, OnDidSendMessage(Ref(*expected_wire_message), false));
-  EXPECT_CALL(connection, SetStatusProxy(Connection::DISCONNECTED));
+  EXPECT_CALL(connection, SetStatusProxy(cryptauth::Connection::DISCONNECTED));
   EXPECT_CALL(*socket_, Disconnect(_));
   EXPECT_CALL(*adapter_, RemoveObserver(&connection));
   error_callback.Run("The most helpful of error messages");
@@ -463,7 +465,7 @@
 
   // If the remote device disconnects, |connection| should also disconnect.
   ON_CALL(device_, IsConnected()).WillByDefault(Return(false));
-  EXPECT_CALL(connection, SetStatusProxy(Connection::DISCONNECTED));
+  EXPECT_CALL(connection, SetStatusProxy(cryptauth::Connection::DISCONNECTED));
   EXPECT_CALL(*socket_, Disconnect(_));
   EXPECT_CALL(*adapter_, RemoveObserver(&connection));
   connection.DeviceChanged(adapter_.get(), &device_);
diff --git a/components/proximity_auth/device_to_device_authenticator.cc b/components/proximity_auth/device_to_device_authenticator.cc
index 62a08e2..cc9ccdf6 100644
--- a/components/proximity_auth/device_to_device_authenticator.cc
+++ b/components/proximity_auth/device_to_device_authenticator.cc
@@ -9,13 +9,13 @@
 #include "base/memory/ptr_util.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
+#include "components/cryptauth/connection.h"
 #include "components/cryptauth/secure_message_delegate.h"
-#include "components/proximity_auth/connection.h"
+#include "components/cryptauth/wire_message.h"
 #include "components/proximity_auth/device_to_device_initiator_operations.h"
 #include "components/proximity_auth/device_to_device_secure_context.h"
 #include "components/proximity_auth/logging/logging.h"
 #include "components/proximity_auth/secure_context.h"
-#include "components/proximity_auth/wire_message.h"
 
 namespace proximity_auth {
 
@@ -33,7 +33,7 @@
 }  // namespace
 
 DeviceToDeviceAuthenticator::DeviceToDeviceAuthenticator(
-    Connection* connection,
+    cryptauth::Connection* connection,
     const std::string& account_id,
     std::unique_ptr<cryptauth::SecureMessageDelegate> secure_message_delegate)
     : connection_(connection),
@@ -115,7 +115,7 @@
   hello_message_ = message;
   std::string permit_id = kPermitIdPrefix + account_id_;
   connection_->SendMessage(
-      base::MakeUnique<WireMessage>(hello_message_, permit_id));
+      base::MakeUnique<cryptauth::WireMessage>(hello_message_, permit_id));
 }
 
 void DeviceToDeviceAuthenticator::OnResponderAuthTimedOut() {
@@ -154,7 +154,7 @@
   }
 
   state_ = State::SENT_INITIATOR_AUTH;
-  connection_->SendMessage(base::MakeUnique<WireMessage>(message));
+  connection_->SendMessage(base::MakeUnique<cryptauth::WireMessage>(message));
 }
 
 void DeviceToDeviceAuthenticator::Fail(const std::string& error_message) {
@@ -187,19 +187,19 @@
 }
 
 void DeviceToDeviceAuthenticator::OnConnectionStatusChanged(
-    Connection* connection,
-    Connection::Status old_status,
-    Connection::Status new_status) {
+    cryptauth::Connection* connection,
+    cryptauth::Connection::Status old_status,
+    cryptauth::Connection::Status new_status) {
   // We do not expect the connection to drop during authentication.
-  if (new_status == Connection::DISCONNECTED) {
+  if (new_status == cryptauth::Connection::DISCONNECTED) {
     Fail("Disconnected while authentication is in progress",
          Result::DISCONNECTED);
   }
 }
 
 void DeviceToDeviceAuthenticator::OnMessageReceived(
-    const Connection& connection,
-    const WireMessage& message) {
+    const cryptauth::Connection& connection,
+    const cryptauth::WireMessage& message) {
   if (state_ == State::SENT_HELLO) {
     PA_LOG(INFO) << "Received [Responder Auth] message, payload_size="
                  << message.payload().size();
@@ -222,9 +222,10 @@
   }
 }
 
-void DeviceToDeviceAuthenticator::OnSendCompleted(const Connection& connection,
-                                                  const WireMessage& message,
-                                                  bool success) {
+void DeviceToDeviceAuthenticator::OnSendCompleted(
+    const cryptauth::Connection& connection,
+    const cryptauth::WireMessage& message,
+    bool success) {
   if (state_ == State::SENT_INITIATOR_AUTH) {
     if (success)
       Succeed();
diff --git a/components/proximity_auth/device_to_device_authenticator.h b/components/proximity_auth/device_to_device_authenticator.h
index 2b2ad64..7172c7c4 100644
--- a/components/proximity_auth/device_to_device_authenticator.h
+++ b/components/proximity_auth/device_to_device_authenticator.h
@@ -8,8 +8,9 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "components/cryptauth/connection.h"
+#include "components/cryptauth/connection_observer.h"
 #include "components/proximity_auth/authenticator.h"
-#include "components/proximity_auth/connection_observer.h"
 
 namespace base {
 class Timer;
@@ -21,8 +22,6 @@
 
 namespace proximity_auth {
 
-class Connection;
-
 // Authenticator implementation using the "device to device" protocol, which is
 // in turn built on top of the SecureMessage library.
 // This protocol contains the following steps (local device is the initiator):
@@ -42,7 +41,7 @@
 // This protocol requires exclusive use of the connection. No other message
 // should be sent or received while authentication is in progress.
 class DeviceToDeviceAuthenticator : public Authenticator,
-                                    public ConnectionObserver {
+                                    public cryptauth::ConnectionObserver {
  public:
   // Creates the instance:
   // |connection|: The connection to the remote device, which must be in a
@@ -50,7 +49,7 @@
   // |account_id|: The canonical account id of the user who is the owner of both
   //     the local and remote devices.
   // |secure_message_delegate|: Handles the SecureMessage crypto operations.
-  DeviceToDeviceAuthenticator(Connection* connection,
+  DeviceToDeviceAuthenticator(cryptauth::Connection* connection,
                               const std::string& account_id,
                               std::unique_ptr<cryptauth::SecureMessageDelegate>
                                   secure_message_delegate);
@@ -108,19 +107,20 @@
   void Succeed();
 
   // ConnectionObserver:
-  void OnConnectionStatusChanged(Connection* connection,
-                                 Connection::Status old_status,
-                                 Connection::Status new_status) override;
-  void OnMessageReceived(const Connection& connection,
-                         const WireMessage& message) override;
-  void OnSendCompleted(const Connection& connection,
-                       const WireMessage& message,
+  void OnConnectionStatusChanged(
+      cryptauth::Connection* connection,
+      cryptauth::Connection::Status old_status,
+      cryptauth::Connection::Status new_status) override;
+  void OnMessageReceived(const cryptauth::Connection& connection,
+                         const cryptauth::WireMessage& message) override;
+  void OnSendCompleted(const cryptauth::Connection& connection,
+                       const cryptauth::WireMessage& message,
                        bool success) override;
 
   // The connection to the remote device. It is expected to be in the CONNECTED
   // state at all times during authentication.
   // Not owned, and must outlive this instance.
-  Connection* const connection_;
+  cryptauth::Connection* const connection_;
 
   // The account id of the user who owns the local and remote devices. This is
   // normally an email address, and should be canonicalized.
diff --git a/components/proximity_auth/device_to_device_authenticator_unittest.cc b/components/proximity_auth/device_to_device_authenticator_unittest.cc
index 5dbbe83..510d266 100644
--- a/components/proximity_auth/device_to_device_authenticator_unittest.cc
+++ b/components/proximity_auth/device_to_device_authenticator_unittest.cc
@@ -13,12 +13,12 @@
 #include "base/memory/scoped_vector.h"
 #include "base/rand_util.h"
 #include "base/timer/mock_timer.h"
+#include "components/cryptauth/connection.h"
+#include "components/cryptauth/cryptauth_test_util.h"
 #include "components/cryptauth/fake_secure_message_delegate.h"
-#include "components/proximity_auth/connection.h"
+#include "components/cryptauth/wire_message.h"
 #include "components/proximity_auth/device_to_device_responder_operations.h"
-#include "components/proximity_auth/proximity_auth_test_util.h"
 #include "components/proximity_auth/secure_context.h"
-#include "components/proximity_auth/wire_message.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -61,21 +61,27 @@
 }
 
 // Connection implementation for testing.
-class FakeConnection : public Connection {
+class FakeConnection : public cryptauth::Connection {
  public:
   FakeConnection(const cryptauth::RemoteDevice& remote_device)
-      : Connection(remote_device), connection_blocked_(false) {}
+      : cryptauth::Connection(remote_device), connection_blocked_(false) {}
   ~FakeConnection() override {}
 
   // Connection:
-  void Connect() override { SetStatus(Connection::Status::CONNECTED); }
-  void Disconnect() override { SetStatus(Connection::Status::DISCONNECTED); }
+  void Connect() override {
+    SetStatus(cryptauth::Connection::Status::CONNECTED);
+  }
+  void Disconnect() override {
+    SetStatus(cryptauth::Connection::Status::DISCONNECTED);
+  }
 
-  using Connection::OnBytesReceived;
+  using cryptauth::Connection::OnBytesReceived;
 
   void ClearMessageBuffer() { message_buffer_.clear(); }
 
-  const ScopedVector<WireMessage>& message_buffer() { return message_buffer_; }
+  const ScopedVector<cryptauth::WireMessage>& message_buffer() {
+    return message_buffer_;
+  }
 
   void set_connection_blocked(bool connection_blocked) {
     connection_blocked_ = connection_blocked;
@@ -84,15 +90,16 @@
   bool connection_blocked() { return connection_blocked_; }
 
  protected:
-  // Connection:
-  void SendMessageImpl(std::unique_ptr<WireMessage> message) override {
-    const WireMessage& message_alias = *message;
+  // cryptauth::Connection:
+  void SendMessageImpl(
+      std::unique_ptr<cryptauth::WireMessage> message) override {
+    const cryptauth::WireMessage& message_alias = *message;
     message_buffer_.push_back(std::move(message));
     OnDidSendMessage(message_alias, !connection_blocked_);
   }
 
  private:
-  ScopedVector<WireMessage> message_buffer_;
+  ScopedVector<cryptauth::WireMessage> message_buffer_;
 
   bool connection_blocked_;
 
@@ -103,7 +110,7 @@
 class DeviceToDeviceAuthenticatorForTest : public DeviceToDeviceAuthenticator {
  public:
   DeviceToDeviceAuthenticatorForTest(
-      Connection* connection,
+      cryptauth::Connection* connection,
       std::unique_ptr<cryptauth::SecureMessageDelegate> secure_message_delegate)
       : DeviceToDeviceAuthenticator(connection,
                                     kAccountId,
@@ -137,7 +144,7 @@
 class ProximityAuthDeviceToDeviceAuthenticatorTest : public testing::Test {
  public:
   ProximityAuthDeviceToDeviceAuthenticatorTest()
-      : remote_device_(CreateClassicRemoteDeviceForTest()),
+      : remote_device_(cryptauth::CreateClassicRemoteDeviceForTest()),
         connection_(remote_device_),
         secure_message_delegate_(new cryptauth::FakeSecureMessageDelegate),
         authenticator_(&connection_,
@@ -197,7 +204,7 @@
   std::string SimulateResponderAuth(const std::string& hello_message) {
     std::string remote_device_private_key =
         secure_message_delegate_->GetPrivateKeyForPublicKey(
-            kTestRemoteDevicePublicKey);
+            cryptauth::kTestRemoteDevicePublicKey);
 
     std::string responder_auth_message;
     DeviceToDeviceResponderOperations::CreateResponderAuthMessage(
@@ -207,7 +214,7 @@
         base::Bind(&SaveStringResult, &responder_auth_message));
     EXPECT_FALSE(responder_auth_message.empty());
 
-    WireMessage wire_message(responder_auth_message);
+    cryptauth::WireMessage wire_message(responder_auth_message);
     connection_.OnBytesReceived(wire_message.Serialize());
 
     return responder_auth_message;
@@ -274,7 +281,7 @@
 
   // If the responder could not validate the [Hello message], it essentially
   // sends random bytes back for privacy reasons.
-  WireMessage wire_message(base::RandBytesAsString(300u));
+  cryptauth::WireMessage wire_message(base::RandBytesAsString(300u));
   EXPECT_CALL(*this,
               OnAuthenticationResultProxy(Authenticator::Result::FAILURE));
   connection_.OnBytesReceived(wire_message.Serialize());
@@ -339,12 +346,12 @@
 
   // Test that the authenticator is properly cleaned up after authentication
   // completes.
-  WireMessage wire_message(base::RandBytesAsString(300u));
+  cryptauth::WireMessage wire_message(base::RandBytesAsString(300u));
   connection_.SendMessage(
-      base::MakeUnique<WireMessage>(base::RandBytesAsString(300u)));
+      base::MakeUnique<cryptauth::WireMessage>(base::RandBytesAsString(300u)));
   connection_.OnBytesReceived(wire_message.Serialize());
   connection_.SendMessage(
-      base::MakeUnique<WireMessage>(base::RandBytesAsString(300u)));
+      base::MakeUnique<cryptauth::WireMessage>(base::RandBytesAsString(300u)));
   connection_.OnBytesReceived(wire_message.Serialize());
 }
 
diff --git a/components/proximity_auth/messenger_impl.cc b/components/proximity_auth/messenger_impl.cc
index 897f822..200539e9 100644
--- a/components/proximity_auth/messenger_impl.cc
+++ b/components/proximity_auth/messenger_impl.cc
@@ -14,12 +14,12 @@
 #include "base/memory/ptr_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
-#include "components/proximity_auth/connection.h"
+#include "components/cryptauth/connection.h"
+#include "components/cryptauth/wire_message.h"
 #include "components/proximity_auth/logging/logging.h"
 #include "components/proximity_auth/messenger_observer.h"
 #include "components/proximity_auth/remote_status_update.h"
 #include "components/proximity_auth/secure_context.h"
-#include "components/proximity_auth/wire_message.h"
 
 namespace proximity_auth {
 namespace {
@@ -68,7 +68,7 @@
 
 }  // namespace
 
-MessengerImpl::MessengerImpl(std::unique_ptr<Connection> connection,
+MessengerImpl::MessengerImpl(std::unique_ptr<cryptauth::Connection> connection,
                              std::unique_ptr<SecureContext> secure_context)
     : connection_(std::move(connection)),
       secure_context_(std::move(secure_context)),
@@ -179,7 +179,8 @@
 }
 
 void MessengerImpl::OnMessageEncoded(const std::string& encoded_message) {
-  connection_->SendMessage(base::MakeUnique<WireMessage>(encoded_message));
+  connection_->SendMessage(
+      base::MakeUnique<cryptauth::WireMessage>(encoded_message));
 }
 
 void MessengerImpl::OnMessageDecoded(const std::string& decoded_message) {
@@ -306,11 +307,12 @@
       base::TimeDelta::FromSeconds(kIOSPollingIntervalSeconds));
 }
 
-void MessengerImpl::OnConnectionStatusChanged(Connection* connection,
-                                              Connection::Status old_status,
-                                              Connection::Status new_status) {
+void MessengerImpl::OnConnectionStatusChanged(
+    cryptauth::Connection* connection,
+    cryptauth::Connection::Status old_status,
+    cryptauth::Connection::Status new_status) {
   DCHECK_EQ(connection, connection_.get());
-  if (new_status == Connection::DISCONNECTED) {
+  if (new_status == cryptauth::Connection::DISCONNECTED) {
     PA_LOG(INFO) << "Secure channel disconnected...";
     connection_->RemoveObserver(this);
     for (auto& observer : observers_)
@@ -320,15 +322,16 @@
   }
 }
 
-void MessengerImpl::OnMessageReceived(const Connection& connection,
-                                      const WireMessage& wire_message) {
+void MessengerImpl::OnMessageReceived(
+    const cryptauth::Connection& connection,
+    const cryptauth::WireMessage& wire_message) {
   secure_context_->Decode(wire_message.payload(),
                           base::Bind(&MessengerImpl::OnMessageDecoded,
                                      weak_ptr_factory_.GetWeakPtr()));
 }
 
-void MessengerImpl::OnSendCompleted(const Connection& connection,
-                                    const WireMessage& wire_message,
+void MessengerImpl::OnSendCompleted(const cryptauth::Connection& connection,
+                                    const cryptauth::WireMessage& wire_message,
                                     bool success) {
   if (!pending_message_) {
     PA_LOG(ERROR) << "Unexpected message sent.";
diff --git a/components/proximity_auth/messenger_impl.h b/components/proximity_auth/messenger_impl.h
index 9caee5ad..b917816 100644
--- a/components/proximity_auth/messenger_impl.h
+++ b/components/proximity_auth/messenger_impl.h
@@ -11,7 +11,8 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
-#include "components/proximity_auth/connection_observer.h"
+#include "components/cryptauth/connection.h"
+#include "components/cryptauth/connection_observer.h"
 #include "components/proximity_auth/messenger.h"
 
 namespace base {
@@ -20,17 +21,16 @@
 
 namespace proximity_auth {
 
-class Connection;
 class SecureContext;
 
 // Concrete implementation of the Messenger interface.
-class MessengerImpl : public Messenger, public ConnectionObserver {
+class MessengerImpl : public Messenger, public cryptauth::ConnectionObserver {
  public:
   // Constructs a messenger that sends and receives messages over the given
   // |connection|, using the |secure_context| to encrypt and decrypt the
   // messages. The |connection| must be connected. The messenger begins
   // observing messages as soon as it is constructed.
-  MessengerImpl(std::unique_ptr<Connection> connection,
+  MessengerImpl(std::unique_ptr<cryptauth::Connection> connection,
                 std::unique_ptr<SecureContext> secure_context);
   ~MessengerImpl() override;
 
@@ -44,7 +44,7 @@
   SecureContext* GetSecureContext() const override;
 
   // Exposed for testing.
-  Connection* connection() { return connection_.get(); }
+  cryptauth::Connection* connection() { return connection_.get(); }
 
  private:
   // Internal data structure to represent a pending message that either hasn't
@@ -88,18 +88,19 @@
   // in the background. This function starts the poll loop.
   void PollScreenStateForIOS();
 
-  // ConnectionObserver:
-  void OnConnectionStatusChanged(Connection* connection,
-                                 Connection::Status old_status,
-                                 Connection::Status new_status) override;
-  void OnMessageReceived(const Connection& connection,
-                         const WireMessage& wire_message) override;
-  void OnSendCompleted(const Connection& connection,
-                       const WireMessage& wire_message,
+  // cryptauth::ConnectionObserver:
+  void OnConnectionStatusChanged(
+      cryptauth::Connection* connection,
+      cryptauth::Connection::Status old_status,
+      cryptauth::Connection::Status new_status) override;
+  void OnMessageReceived(const cryptauth::Connection& connection,
+                         const cryptauth::WireMessage& wire_message) override;
+  void OnSendCompleted(const cryptauth::Connection& connection,
+                       const cryptauth::WireMessage& wire_message,
                        bool success) override;
 
   // The connection used to send and receive events and status updates.
-  std::unique_ptr<Connection> connection_;
+  std::unique_ptr<cryptauth::Connection> connection_;
 
   // Used to encrypt and decrypt payloads sent and received over the
   // |connection_|.
diff --git a/components/proximity_auth/messenger_impl_unittest.cc b/components/proximity_auth/messenger_impl_unittest.cc
index 84a16315..2a66e8f 100644
--- a/components/proximity_auth/messenger_impl_unittest.cc
+++ b/components/proximity_auth/messenger_impl_unittest.cc
@@ -9,14 +9,14 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "components/cryptauth/connection.h"
+#include "components/cryptauth/cryptauth_test_util.h"
+#include "components/cryptauth/fake_connection.h"
 #include "components/cryptauth/remote_device.h"
-#include "components/proximity_auth/connection.h"
-#include "components/proximity_auth/fake_connection.h"
+#include "components/cryptauth/wire_message.h"
 #include "components/proximity_auth/fake_secure_context.h"
 #include "components/proximity_auth/messenger_observer.h"
-#include "components/proximity_auth/proximity_auth_test_util.h"
 #include "components/proximity_auth/remote_status_update.h"
-#include "components/proximity_auth/wire_message.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -63,14 +63,14 @@
 class TestMessenger : public MessengerImpl {
  public:
   TestMessenger()
-      : MessengerImpl(base::MakeUnique<FakeConnection>(
-                          CreateClassicRemoteDeviceForTest()),
+      : MessengerImpl(base::MakeUnique<cryptauth::FakeConnection>(
+                          cryptauth::CreateClassicRemoteDeviceForTest()),
                       base::MakeUnique<FakeSecureContext>()) {}
   ~TestMessenger() override {}
 
   // Simple getters for the mock objects owned by |this| messenger.
-  FakeConnection* GetFakeConnection() {
-    return static_cast<FakeConnection*>(connection());
+  cryptauth::FakeConnection* GetFakeConnection() {
+    return static_cast<cryptauth::FakeConnection*>(connection());
   }
   FakeSecureContext* GetFakeSecureContext() {
     return static_cast<FakeSecureContext*>(GetSecureContext());
@@ -109,7 +109,8 @@
   TestMessenger messenger;
   messenger.DispatchUnlockEvent();
 
-  WireMessage* message = messenger.GetFakeConnection()->current_message();
+  cryptauth::WireMessage* message =
+      messenger.GetFakeConnection()->current_message();
   ASSERT_TRUE(message);
   EXPECT_EQ(std::string(), message->permit_id());
   EXPECT_EQ(
@@ -151,7 +152,8 @@
   TestMessenger messenger;
   messenger.RequestDecryption(kChallenge);
 
-  WireMessage* message = messenger.GetFakeConnection()->current_message();
+  cryptauth::WireMessage* message =
+      messenger.GetFakeConnection()->current_message();
   ASSERT_TRUE(message);
   EXPECT_EQ(std::string(), message->permit_id());
   EXPECT_EQ(
@@ -167,7 +169,8 @@
   TestMessenger messenger;
   messenger.RequestDecryption("\xFF\xE6");
 
-  WireMessage* message = messenger.GetFakeConnection()->current_message();
+  cryptauth::WireMessage* message =
+      messenger.GetFakeConnection()->current_message();
   ASSERT_TRUE(message);
   EXPECT_EQ(std::string(), message->permit_id());
   EXPECT_EQ(
@@ -268,7 +271,8 @@
   TestMessenger messenger;
   messenger.RequestUnlock();
 
-  WireMessage* message = messenger.GetFakeConnection()->current_message();
+  cryptauth::WireMessage* message =
+      messenger.GetFakeConnection()->current_message();
   ASSERT_TRUE(message);
   EXPECT_EQ(std::string(), message->permit_id());
   EXPECT_EQ("{\"type\":\"unlock_request\"}, but encoded", message->payload());
diff --git a/components/proximity_auth/proximity_auth_test_util.h b/components/proximity_auth/proximity_auth_test_util.h
deleted file mode 100644
index 40a2764f..0000000
--- a/components/proximity_auth/proximity_auth_test_util.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_PROXIMITY_AUTH_PROXIMITY_AUTH_TEST_UTIL_H
-#define COMPONENTS_PROXIMITY_AUTH_PROXIMITY_AUTH_TEST_UTIL_H
-
-#include "components/cryptauth/remote_device.h"
-
-namespace proximity_auth {
-
-// Attributes of the default test remote device.
-extern const char kTestRemoteDeviceUserId[];
-extern const char kTestRemoteDeviceName[];
-extern const char kTestRemoteDevicePublicKey[];
-extern const char kTestRemoteDeviceBluetoothAddress[];
-extern const char kTestRemoteDevicePSK[];
-extern const char kTestRemoteDeviceSignInChallenge[];
-
-// Returns a BLE RemoteDevice used for tests.
-inline cryptauth::RemoteDevice CreateLERemoteDeviceForTest() {
-  return cryptauth::RemoteDevice(
-      kTestRemoteDeviceUserId, kTestRemoteDeviceName,
-      kTestRemoteDevicePublicKey, cryptauth::RemoteDevice::BLUETOOTH_LE,
-      kTestRemoteDeviceBluetoothAddress, kTestRemoteDevicePSK,
-      kTestRemoteDeviceSignInChallenge);
-}
-
-// Returns a classic Bluetooth RemoteDevice used for tests.
-inline cryptauth::RemoteDevice CreateClassicRemoteDeviceForTest() {
-  return cryptauth::RemoteDevice(
-      kTestRemoteDeviceUserId, kTestRemoteDeviceName,
-      kTestRemoteDevicePublicKey, cryptauth::RemoteDevice::BLUETOOTH_CLASSIC,
-      kTestRemoteDeviceBluetoothAddress, kTestRemoteDevicePSK,
-      kTestRemoteDeviceSignInChallenge);
-}
-
-}  // namespace proximity_auth
-
-#endif  // COMPONENTS_PROXIMITY_AUTH_PROXIMITY_AUTH_TEST_UTIL_H
diff --git a/components/proximity_auth/remote_device_life_cycle_impl.cc b/components/proximity_auth/remote_device_life_cycle_impl.cc
index 4293772..da72aea 100644
--- a/components/proximity_auth/remote_device_life_cycle_impl.cc
+++ b/components/proximity_auth/remote_device_life_cycle_impl.cc
@@ -11,12 +11,13 @@
 #include "base/memory/ptr_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/default_tick_clock.h"
+#include "components/cryptauth/bluetooth_throttler_impl.h"
+#include "components/cryptauth/connection_finder.h"
 #include "components/cryptauth/secure_message_delegate.h"
 #include "components/proximity_auth/ble/bluetooth_low_energy_connection.h"
 #include "components/proximity_auth/ble/bluetooth_low_energy_connection_finder.h"
 #include "components/proximity_auth/bluetooth_connection.h"
 #include "components/proximity_auth/bluetooth_connection_finder.h"
-#include "components/proximity_auth/bluetooth_throttler_impl.h"
 #include "components/proximity_auth/device_to_device_authenticator.h"
 #include "components/proximity_auth/logging/logging.h"
 #include "components/proximity_auth/messenger_impl.h"
@@ -47,7 +48,7 @@
       proximity_auth_client_(proximity_auth_client),
       state_(RemoteDeviceLifeCycle::State::STOPPED),
       observers_(base::ObserverList<Observer>::NOTIFY_EXISTING_ONLY),
-      bluetooth_throttler_(new BluetoothThrottlerImpl(
+      bluetooth_throttler_(new cryptauth::BluetoothThrottlerImpl(
           base::WrapUnique(new base::DefaultTickClock()))),
       weak_ptr_factory_(this) {}
 
@@ -80,7 +81,7 @@
   observers_.RemoveObserver(observer);
 }
 
-std::unique_ptr<ConnectionFinder>
+std::unique_ptr<cryptauth::ConnectionFinder>
 RemoteDeviceLifeCycleImpl::CreateConnectionFinder() {
   if (remote_device_.bluetooth_type == cryptauth::RemoteDevice::BLUETOOTH_LE) {
     return base::MakeUnique<BluetoothLowEnergyConnectionFinder>(
@@ -120,7 +121,7 @@
 }
 
 void RemoteDeviceLifeCycleImpl::OnConnectionFound(
-    std::unique_ptr<Connection> connection) {
+    std::unique_ptr<cryptauth::Connection> connection) {
   DCHECK(state_ == RemoteDeviceLifeCycle::State::FINDING_CONNECTION);
   connection_ = std::move(connection);
   authenticator_ = CreateAuthenticator();
diff --git a/components/proximity_auth/remote_device_life_cycle_impl.h b/components/proximity_auth/remote_device_life_cycle_impl.h
index c1649eb..a7265fc 100644
--- a/components/proximity_auth/remote_device_life_cycle_impl.h
+++ b/components/proximity_auth/remote_device_life_cycle_impl.h
@@ -11,6 +11,9 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/timer/timer.h"
+#include "components/cryptauth/bluetooth_throttler.h"
+#include "components/cryptauth/connection.h"
+#include "components/cryptauth/connection_finder.h"
 #include "components/cryptauth/remote_device.h"
 #include "components/proximity_auth/authenticator.h"
 #include "components/proximity_auth/messenger_observer.h"
@@ -18,10 +21,7 @@
 
 namespace proximity_auth {
 
-class BluetoothThrottler;
 class Messenger;
-class Connection;
-class ConnectionFinder;
 class ProximityAuthClient;
 class SecureContext;
 
@@ -44,9 +44,10 @@
   void RemoveObserver(Observer* observer) override;
 
  protected:
-  // Creates and returns a ConnectionFinder instance for |remote_device_|.
+  // Creates and returns a cryptauth::ConnectionFinder instance for
+  // |remote_device_|.
   // Exposed for testing.
-  virtual std::unique_ptr<ConnectionFinder> CreateConnectionFinder();
+  virtual std::unique_ptr<cryptauth::ConnectionFinder> CreateConnectionFinder();
 
   // Creates and returns an Authenticator instance for |connection_|.
   // Exposed for testing.
@@ -61,7 +62,7 @@
   void FindConnection();
 
   // Called when |connection_finder_| finds a connection.
-  void OnConnectionFound(std::unique_ptr<Connection> connection);
+  void OnConnectionFound(std::unique_ptr<cryptauth::Connection> connection);
 
   // Callback when |authenticator_| completes authentication.
   void OnAuthenticationResult(Authenticator::Result result,
@@ -86,7 +87,7 @@
   base::ObserverList<Observer> observers_;
 
   // The connection that is established by |connection_finder_|.
-  std::unique_ptr<Connection> connection_;
+  std::unique_ptr<cryptauth::Connection> connection_;
 
   // Context for encrypting and decrypting messages. Created after
   // authentication succeeds. Ownership is eventually passed to |messenger_|.
@@ -102,11 +103,11 @@
 
   // Used in the FINDING_CONNECTION state to establish a connection to the
   // remote device.
-  std::unique_ptr<ConnectionFinder> connection_finder_;
+  std::unique_ptr<cryptauth::ConnectionFinder> connection_finder_;
 
   // Rate limits Bluetooth connections to the same device. Used to in the
-  // created ConnectionFinder.
-  std::unique_ptr<BluetoothThrottler> bluetooth_throttler_;
+  // created cryptauth::ConnectionFinder.
+  std::unique_ptr<cryptauth::BluetoothThrottler> bluetooth_throttler_;
 
   // After authentication fails, this timer waits for a period of time before
   // retrying the connection.
diff --git a/components/proximity_auth/remote_device_life_cycle_impl_unittest.cc b/components/proximity_auth/remote_device_life_cycle_impl_unittest.cc
index 913c9efc..9abc9b2 100644
--- a/components/proximity_auth/remote_device_life_cycle_impl_unittest.cc
+++ b/components/proximity_auth/remote_device_life_cycle_impl_unittest.cc
@@ -13,13 +13,13 @@
 #include "base/macros.h"
 #include "base/test/test_simple_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "components/cryptauth/connection_finder.h"
+#include "components/cryptauth/cryptauth_test_util.h"
+#include "components/cryptauth/fake_connection.h"
+#include "components/cryptauth/wire_message.h"
 #include "components/proximity_auth/authenticator.h"
-#include "components/proximity_auth/connection_finder.h"
-#include "components/proximity_auth/fake_connection.h"
 #include "components/proximity_auth/messenger.h"
-#include "components/proximity_auth/proximity_auth_test_util.h"
 #include "components/proximity_auth/secure_context.h"
-#include "components/proximity_auth/wire_message.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -59,7 +59,7 @@
   DISALLOW_COPY_AND_ASSIGN(StubSecureContext);
 };
 
-class FakeConnectionFinder : public ConnectionFinder {
+class FakeConnectionFinder : public cryptauth::ConnectionFinder {
  public:
   FakeConnectionFinder(const cryptauth::RemoteDevice& remote_device)
       : remote_device_(remote_device), connection_(nullptr) {}
@@ -67,38 +67,40 @@
 
   void OnConnectionFound() {
     ASSERT_FALSE(connection_callback_.is_null());
-    std::unique_ptr<FakeConnection> scoped_connection_(
-        new FakeConnection(remote_device_));
+    std::unique_ptr<cryptauth::FakeConnection> scoped_connection_(
+        new cryptauth::FakeConnection(remote_device_));
     connection_ = scoped_connection_.get();
     connection_callback_.Run(std::move(scoped_connection_));
   }
 
-  FakeConnection* connection() { return connection_; }
+  cryptauth::FakeConnection* connection() { return connection_; }
 
  private:
-  // ConnectionFinder:
-  void Find(const ConnectionCallback& connection_callback) override {
+  // cryptauth::ConnectionFinder:
+  void Find(const cryptauth::ConnectionFinder::ConnectionCallback&
+                connection_callback) override {
     ASSERT_TRUE(connection_callback_.is_null());
     connection_callback_ = connection_callback;
   }
 
   const cryptauth::RemoteDevice remote_device_;
 
-  FakeConnection* connection_;
+  cryptauth::FakeConnection* connection_;
 
-  ConnectionCallback connection_callback_;
+  cryptauth::ConnectionFinder::ConnectionCallback connection_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeConnectionFinder);
 };
 
 class FakeAuthenticator : public Authenticator {
  public:
-  FakeAuthenticator(Connection* connection) : connection_(connection) {}
+  FakeAuthenticator(cryptauth::Connection* connection)
+      : connection_(connection) {}
   ~FakeAuthenticator() override {
     // This object should be destroyed immediately after authentication is
     // complete in order not to outlive the underlying connection.
     EXPECT_FALSE(callback_.is_null());
-    EXPECT_EQ(kTestRemoteDevicePublicKey,
+    EXPECT_EQ(cryptauth::kTestRemoteDevicePublicKey,
               connection_->remote_device().public_key);
   }
 
@@ -117,7 +119,7 @@
     callback_ = callback;
   }
 
-  Connection* connection_;
+  cryptauth::Connection* connection_;
 
   AuthenticationCallback callback_;
 
@@ -138,7 +140,8 @@
   FakeAuthenticator* authenticator() { return authenticator_; }
 
  private:
-  std::unique_ptr<ConnectionFinder> CreateConnectionFinder() override {
+  std::unique_ptr<cryptauth::ConnectionFinder> CreateConnectionFinder()
+      override {
     std::unique_ptr<FakeConnectionFinder> scoped_connection_finder(
         new FakeConnectionFinder(remote_device_));
     connection_finder_ = scoped_connection_finder.get();
@@ -167,7 +170,7 @@
       public RemoteDeviceLifeCycle::Observer {
  protected:
   ProximityAuthRemoteDeviceLifeCycleImplTest()
-      : life_cycle_(CreateClassicRemoteDeviceForTest()),
+      : life_cycle_(cryptauth::CreateClassicRemoteDeviceForTest()),
         task_runner_(new base::TestSimpleTaskRunner()),
         thread_task_runner_handle_(task_runner_) {}
 
@@ -190,7 +193,7 @@
               life_cycle_.GetState());
   }
 
-  FakeConnection* OnConnectionFound() {
+  cryptauth::FakeConnection* OnConnectionFound() {
     EXPECT_EQ(RemoteDeviceLifeCycle::State::FINDING_CONNECTION,
               life_cycle_.GetState());
 
@@ -241,7 +244,7 @@
 
 TEST_F(ProximityAuthRemoteDeviceLifeCycleImplTest, GetRemoteDevice) {
   cryptauth::RemoteDevice expected_remote_device =
-      CreateClassicRemoteDeviceForTest();
+      cryptauth::CreateClassicRemoteDeviceForTest();
   cryptauth::RemoteDevice remote_device = life_cycle_.GetRemoteDevice();
   EXPECT_EQ(expected_remote_device.user_id, remote_device.user_id);
   EXPECT_EQ(expected_remote_device.name, remote_device.name);
@@ -255,7 +258,7 @@
 TEST_F(ProximityAuthRemoteDeviceLifeCycleImplTest, AuthenticateAndDisconnect) {
   StartLifeCycle();
   for (size_t i = 0; i < 3; ++i) {
-    Connection* connection = OnConnectionFound();
+    cryptauth::Connection* connection = OnConnectionFound();
     Authenticate(Authenticator::Result::SUCCESS);
     EXPECT_TRUE(life_cycle_.GetMessenger());
 
@@ -308,7 +311,7 @@
   task_runner_->RunUntilIdle();
 
   // Authentication succeeds on second pass.
-  Connection* connection = OnConnectionFound();
+  cryptauth::Connection* connection = OnConnectionFound();
   Authenticate(Authenticator::Result::SUCCESS);
   EXPECT_TRUE(life_cycle_.GetMessenger());
   EXPECT_CALL(*this, OnLifeCycleStateChanged(_, _));
diff --git a/components/proximity_auth/throttled_bluetooth_connection_finder.cc b/components/proximity_auth/throttled_bluetooth_connection_finder.cc
index a025259..d70669b 100644
--- a/components/proximity_auth/throttled_bluetooth_connection_finder.cc
+++ b/components/proximity_auth/throttled_bluetooth_connection_finder.cc
@@ -10,15 +10,16 @@
 #include "base/location.h"
 #include "base/task_runner.h"
 #include "base/time/time.h"
+#include "components/cryptauth/bluetooth_throttler.h"
+#include "components/cryptauth/connection.h"
 #include "components/proximity_auth/bluetooth_connection_finder.h"
-#include "components/proximity_auth/bluetooth_throttler.h"
 
 namespace proximity_auth {
 
 ThrottledBluetoothConnectionFinder::ThrottledBluetoothConnectionFinder(
     std::unique_ptr<BluetoothConnectionFinder> connection_finder,
     scoped_refptr<base::TaskRunner> task_runner,
-    BluetoothThrottler* throttler)
+    cryptauth::BluetoothThrottler* throttler)
     : connection_finder_(std::move(connection_finder)),
       task_runner_(task_runner),
       throttler_(throttler),
@@ -28,7 +29,8 @@
 }
 
 void ThrottledBluetoothConnectionFinder::Find(
-    const ConnectionCallback& connection_callback) {
+    const cryptauth::ConnectionFinder::ConnectionCallback&
+        connection_callback) {
   const base::TimeDelta delay = throttler_->GetDelay();
 
   // Wait, if needed.
@@ -47,8 +49,8 @@
 }
 
 void ThrottledBluetoothConnectionFinder::OnConnection(
-    const ConnectionCallback& connection_callback,
-    std::unique_ptr<Connection> connection) {
+    const cryptauth::ConnectionFinder::ConnectionCallback& connection_callback,
+    std::unique_ptr<cryptauth::Connection> connection) {
   throttler_->OnConnection(connection.get());
   connection_callback.Run(std::move(connection));
 }
diff --git a/components/proximity_auth/throttled_bluetooth_connection_finder.h b/components/proximity_auth/throttled_bluetooth_connection_finder.h
index 89c92e3..6af73619 100644
--- a/components/proximity_auth/throttled_bluetooth_connection_finder.h
+++ b/components/proximity_auth/throttled_bluetooth_connection_finder.h
@@ -10,7 +10,9 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "components/proximity_auth/connection_finder.h"
+#include "components/cryptauth/bluetooth_throttler.h"
+#include "components/cryptauth/connection.h"
+#include "components/cryptauth/connection_finder.h"
 
 namespace base {
 class TaskRunner;
@@ -19,27 +21,27 @@
 namespace proximity_auth {
 
 class BluetoothConnectionFinder;
-class BluetoothThrottler;
-class Connection;
 
 // A Bluetooth connection finder that delays Find() requests according to the
 // throttler's cooldown period.
-class ThrottledBluetoothConnectionFinder : public ConnectionFinder {
+class ThrottledBluetoothConnectionFinder : public cryptauth::ConnectionFinder {
  public:
   // Note: The |throttler| is not owned, and must outlive |this| instance.
   ThrottledBluetoothConnectionFinder(
       std::unique_ptr<BluetoothConnectionFinder> connection_finder,
       scoped_refptr<base::TaskRunner> task_runner,
-      BluetoothThrottler* throttler);
+      cryptauth::BluetoothThrottler* throttler);
   ~ThrottledBluetoothConnectionFinder() override;
 
-  // ConnectionFinder:
-  void Find(const ConnectionCallback& connection_callback) override;
+  // cryptauth::ConnectionFinder:
+  void Find(const cryptauth::ConnectionFinder::ConnectionCallback&
+                connection_callback) override;
 
  private:
   // Callback to be called when a connection is found.
-  void OnConnection(const ConnectionCallback& connection_callback,
-                    std::unique_ptr<Connection> connection);
+  void OnConnection(const cryptauth::ConnectionFinder::ConnectionCallback&
+                        connection_callback,
+                    std::unique_ptr<cryptauth::Connection> connection);
 
   // The underlying connection finder.
   std::unique_ptr<BluetoothConnectionFinder> connection_finder_;
@@ -49,7 +51,7 @@
 
   // The throttler managing this connection finder. The throttler is not owned,
   // and must outlive |this| instance.
-  BluetoothThrottler* throttler_;
+  cryptauth::BluetoothThrottler* throttler_;
 
   base::WeakPtrFactory<ThrottledBluetoothConnectionFinder> weak_ptr_factory_;
 
diff --git a/components/proximity_auth/throttled_bluetooth_connection_finder_unittest.cc b/components/proximity_auth/throttled_bluetooth_connection_finder_unittest.cc
index fb747863..91e4e88 100644
--- a/components/proximity_auth/throttled_bluetooth_connection_finder_unittest.cc
+++ b/components/proximity_auth/throttled_bluetooth_connection_finder_unittest.cc
@@ -11,11 +11,11 @@
 #include "base/memory/ptr_util.h"
 #include "base/test/test_simple_task_runner.h"
 #include "base/time/time.h"
+#include "components/cryptauth/bluetooth_throttler.h"
+#include "components/cryptauth/fake_connection.h"
 #include "components/cryptauth/remote_device.h"
+#include "components/cryptauth/wire_message.h"
 #include "components/proximity_auth/bluetooth_connection_finder.h"
-#include "components/proximity_auth/bluetooth_throttler.h"
-#include "components/proximity_auth/fake_connection.h"
-#include "components/proximity_auth/wire_message.h"
 #include "device/bluetooth/bluetooth_uuid.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -31,18 +31,18 @@
 const char kUuid[] = "DEADBEEF-CAFE-FEED-FOOD-D15EA5EBEEF";
 
 // A callback that stores a found |connection| into |out|.
-void SaveConnection(std::unique_ptr<Connection>* out,
-                    std::unique_ptr<Connection> connection) {
+void SaveConnection(std::unique_ptr<cryptauth::Connection>* out,
+                    std::unique_ptr<cryptauth::Connection> connection) {
   *out = std::move(connection);
 }
 
-class MockBluetoothThrottler : public BluetoothThrottler {
+class MockBluetoothThrottler : public cryptauth::BluetoothThrottler {
  public:
   MockBluetoothThrottler() {}
   ~MockBluetoothThrottler() override {}
 
   MOCK_CONST_METHOD0(GetDelay, base::TimeDelta());
-  MOCK_METHOD1(OnConnection, void(Connection* connection));
+  MOCK_METHOD1(OnConnection, void(cryptauth::Connection* connection));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockBluetoothThrottler);
@@ -57,9 +57,10 @@
             base::TimeDelta::FromSeconds(kPollingIntervalSeconds)) {}
   ~FakeBluetoothConnectionFinder() override {}
 
-  void Find(const ConnectionCallback& connection_callback) override {
+  void Find(const cryptauth::ConnectionFinder::ConnectionCallback&
+                connection_callback) override {
     connection_callback.Run(
-        base::MakeUnique<FakeConnection>(cryptauth::RemoteDevice()));
+        base::MakeUnique<cryptauth::FakeConnection>(cryptauth::RemoteDevice()));
   }
 
  private:
@@ -86,7 +87,7 @@
   ThrottledBluetoothConnectionFinder connection_finder(
       base::WrapUnique(new FakeBluetoothConnectionFinder), task_runner_,
       &throttler_);
-  std::unique_ptr<Connection> connection;
+  std::unique_ptr<cryptauth::Connection> connection;
   connection_finder.Find(base::Bind(&SaveConnection, &connection));
   EXPECT_TRUE(connection);
 }
@@ -99,7 +100,7 @@
   ThrottledBluetoothConnectionFinder connection_finder(
       base::WrapUnique(new FakeBluetoothConnectionFinder), task_runner_,
       &throttler_);
-  std::unique_ptr<Connection> connection;
+  std::unique_ptr<cryptauth::Connection> connection;
   connection_finder.Find(base::Bind(&SaveConnection, &connection));
   EXPECT_FALSE(connection);
 
@@ -116,7 +117,7 @@
   ThrottledBluetoothConnectionFinder connection_finder(
       base::WrapUnique(new FakeBluetoothConnectionFinder), task_runner_,
       &throttler_);
-  std::unique_ptr<Connection> connection;
+  std::unique_ptr<cryptauth::Connection> connection;
   EXPECT_CALL(throttler_, OnConnection(_));
   connection_finder.Find(base::Bind(&SaveConnection, &connection));
   EXPECT_TRUE(connection);
diff --git a/components/proximity_auth/unlock_manager_unittest.cc b/components/proximity_auth/unlock_manager_unittest.cc
index cf6645f9..d502265 100644
--- a/components/proximity_auth/unlock_manager_unittest.cc
+++ b/components/proximity_auth/unlock_manager_unittest.cc
@@ -12,11 +12,11 @@
 #include "base/test/test_simple_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
+#include "components/cryptauth/cryptauth_test_util.h"
 #include "components/proximity_auth/fake_secure_context.h"
 #include "components/proximity_auth/logging/logging.h"
 #include "components/proximity_auth/messenger.h"
 #include "components/proximity_auth/mock_proximity_auth_client.h"
-#include "components/proximity_auth/proximity_auth_test_util.h"
 #include "components/proximity_auth/proximity_monitor.h"
 #include "components/proximity_auth/remote_device_life_cycle.h"
 #include "components/proximity_auth/remote_status_update.h"
@@ -160,7 +160,7 @@
  private:
   std::unique_ptr<ProximityMonitor> CreateProximityMonitor(
       const cryptauth::RemoteDevice& remote_device) override {
-    EXPECT_EQ(kTestRemoteDevicePublicKey, remote_device.public_key);
+    EXPECT_EQ(cryptauth::kTestRemoteDevicePublicKey, remote_device.public_key);
     std::unique_ptr<MockProximityMonitor> proximity_monitor(
         new NiceMock<MockProximityMonitor>());
     proximity_monitor_ = proximity_monitor.get();
@@ -188,7 +188,7 @@
 class ProximityAuthUnlockManagerTest : public testing::Test {
  public:
   ProximityAuthUnlockManagerTest()
-      : remote_device_(CreateClassicRemoteDeviceForTest()),
+      : remote_device_(cryptauth::CreateClassicRemoteDeviceForTest()),
         bluetooth_adapter_(CreateAndRegisterMockBluetoothAdapter()),
         task_runner_(new base::TestSimpleTaskRunner()),
         thread_task_runner_handle_(task_runner_) {
diff --git a/components/proximity_auth/webui/proximity_auth_webui_handler.h b/components/proximity_auth/webui/proximity_auth_webui_handler.h
index 3a05795..2f8e1069 100644
--- a/components/proximity_auth/webui/proximity_auth_webui_handler.h
+++ b/components/proximity_auth/webui/proximity_auth_webui_handler.h
@@ -8,12 +8,12 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/values.h"
+#include "components/cryptauth/connection_observer.h"
 #include "components/cryptauth/cryptauth_client.h"
 #include "components/cryptauth/cryptauth_device_manager.h"
 #include "components/cryptauth/cryptauth_enrollment_manager.h"
 #include "components/cryptauth/cryptauth_gcm_manager.h"
 #include "components/proximity_auth/authenticator.h"
-#include "components/proximity_auth/connection_observer.h"
 #include "components/proximity_auth/logging/log_buffer.h"
 #include "components/proximity_auth/messenger_observer.h"
 #include "components/proximity_auth/proximity_auth_client.h"
diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc
index 28e8c88..0e7e53e 100644
--- a/content/browser/android/content_view_core_impl.cc
+++ b/content/browser/android/content_view_core_impl.cc
@@ -230,12 +230,6 @@
       dpi_scale_(dpi_scale),
       device_orientation_(0),
       accessibility_enabled_(false) {
-  GetViewAndroid()->SetLayer(cc::Layer::Create());
-  gfx::Size physical_size(
-      Java_ContentViewCore_getPhysicalBackingWidthPix(env, obj),
-      Java_ContentViewCore_getPhysicalBackingHeightPix(env, obj));
-  GetViewAndroid()->GetLayer()->SetBounds(physical_size);
-
   // Currently, the only use case we have for overriding a user agent involves
   // spoofing a desktop Linux user agent for "Request desktop site".
   // Automatically set it for all WebContents so that it is available when a
@@ -735,16 +729,6 @@
   return size;
 }
 
-gfx::Size ContentViewCoreImpl::GetPhysicalBackingSize() const {
-  JNIEnv* env = AttachCurrentThread();
-  ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
-  if (j_obj.is_null())
-    return gfx::Size();
-  return gfx::Size(
-      Java_ContentViewCore_getPhysicalBackingWidthPix(env, j_obj),
-      Java_ContentViewCore_getPhysicalBackingHeightPix(env, j_obj));
-}
-
 gfx::Size ContentViewCoreImpl::GetViewportSizePix() const {
   JNIEnv* env = AttachCurrentThread();
   ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
@@ -1268,11 +1252,6 @@
 
 void ContentViewCoreImpl::WasResized(JNIEnv* env,
                                      const JavaParamRef<jobject>& obj) {
-  gfx::Size physical_size(
-      Java_ContentViewCore_getPhysicalBackingWidthPix(env, obj),
-      Java_ContentViewCore_getPhysicalBackingHeightPix(env, obj));
-  GetViewAndroid()->GetLayer()->SetBounds(physical_size);
-
   SendScreenRectsAndResizeWidget();
 }
 
@@ -1562,6 +1541,7 @@
       "A ContentViewCoreImpl should be created with a valid WebContents.";
   ui::ViewAndroid* view_android = web_contents->GetView()->GetNativeView();
   view_android->SetDelegate(jview_android_delegate);
+  view_android->SetLayer(cc::Layer::Create());
 
   ui::WindowAndroid* window_android =
         reinterpret_cast<ui::WindowAndroid*>(jwindow_android);
diff --git a/content/browser/android/content_view_core_impl.h b/content/browser/android/content_view_core_impl.h
index f76b041..7252ca6 100644
--- a/content/browser/android/content_view_core_impl.h
+++ b/content/browser/android/content_view_core_impl.h
@@ -378,7 +378,6 @@
   // Methods called from native code
   // --------------------------------------------------------------------------
 
-  gfx::Size GetPhysicalBackingSize() const;
   gfx::Size GetViewportSizeDip() const;
   bool DoBrowserControlsShrinkBlinkSize() const;
   float GetTopControlsHeightDip() const;
diff --git a/content/browser/bluetooth/bluetooth_device_chooser_controller.cc b/content/browser/bluetooth/bluetooth_device_chooser_controller.cc
index 6a0e22a8..65c13c2 100644
--- a/content/browser/bluetooth/bluetooth_device_chooser_controller.cc
+++ b/content/browser/bluetooth/bluetooth_device_chooser_controller.cc
@@ -429,8 +429,10 @@
         MatchesFilters(device_name ? &device_name.value() : nullptr,
                        device.GetUUIDs(), options_->filters)) {
       base::Optional<int8_t> rssi = device.GetInquiryRSSI();
+      std::string device_id = device.GetAddress();
+      device_ids_.insert(device_id);
       chooser_->AddOrUpdateDevice(
-          device.GetAddress(), !!device.GetName() /* should_update_name */,
+          device_id, !!device.GetName() /* should_update_name */,
           device.GetNameForDisplay(), device.IsGattConnected(),
           web_bluetooth_service_->IsDevicePaired(device.GetAddress()),
           rssi ? CalculateSignalStrengthLevel(rssi.value()) : -1);
@@ -501,6 +503,8 @@
     return;
   }
 
+  device_ids_.clear();
+
   scanning_start_time_ = base::TimeTicks::Now();
 
   chooser_->ShowDiscoveryState(BluetoothChooser::DiscoveryState::DISCOVERING);
@@ -588,6 +592,7 @@
       PostErrorCallback(blink::mojom::WebBluetoothResult::CHOOSER_CANCELLED);
       break;
     case BluetoothChooser::Event::SELECTED:
+      RecordNumOfDevices(options_->accept_all_devices, device_ids_.size());
       // RecordRequestDeviceOutcome is called in the callback, because the
       // device may have vanished.
       PostSuccessCallback(device_address);
diff --git a/content/browser/bluetooth/bluetooth_device_chooser_controller.h b/content/browser/bluetooth/bluetooth_device_chooser_controller.h
index 500d31b..a054d6b 100644
--- a/content/browser/bluetooth/bluetooth_device_chooser_controller.h
+++ b/content/browser/bluetooth/bluetooth_device_chooser_controller.h
@@ -6,6 +6,7 @@
 #define CONTENT_BROWSER_BLUETOOTH_BLUETOOTH_DEVICE_CHOOSER_CONTROLLER_H_
 
 #include <string>
+#include <unordered_set>
 
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
@@ -149,6 +150,9 @@
   // The time when scanning starts.
   base::Optional<base::TimeTicks> scanning_start_time_;
 
+  // The device ids that are currently shown in the chooser.
+  std::unordered_set<std::string> device_ids_;
+
   // Weak pointer factory for generating 'this' pointers that might live longer
   // than we do.
   // Note: This should remain the last member so it'll be destroyed and
diff --git a/content/browser/bluetooth/bluetooth_metrics.cc b/content/browser/bluetooth/bluetooth_metrics.cc
index 7a0b4722..6ae9700 100644
--- a/content/browser/bluetooth/bluetooth_metrics.cc
+++ b/content/browser/bluetooth/bluetooth_metrics.cc
@@ -6,6 +6,7 @@
 
 #include <stdint.h>
 
+#include <algorithm>
 #include <map>
 #include <set>
 #include <unordered_set>
@@ -42,6 +43,9 @@
   return uuid ? HashUUID(uuid->canonical_value()) : 0;
 }
 
+// The maximum number of devices that needs to be recorded.
+const size_t kMaxNumOfDevices = 100;
+
 }  // namespace
 
 namespace content {
@@ -353,4 +357,13 @@
       static_cast<int>(UMARSSISignalStrengthLevel::COUNT));
 }
 
+void RecordNumOfDevices(bool accept_all_devices, size_t num_of_devices) {
+  if (accept_all_devices) {
+    UMA_HISTOGRAM_SPARSE_SLOWLY(
+        "Bluetooth.Web.RequestDevice."
+        "NumOfDevicesInChooserWhenNotAcceptingAllDevices",
+        std::min(num_of_devices, kMaxNumOfDevices));
+  }
+}
+
 }  // namespace content
diff --git a/content/browser/bluetooth/bluetooth_metrics.h b/content/browser/bluetooth/bluetooth_metrics.h
index 76e63572..b15bb35 100644
--- a/content/browser/bluetooth/bluetooth_metrics.h
+++ b/content/browser/bluetooth/bluetooth_metrics.h
@@ -294,6 +294,11 @@
 void RecordRSSISignalStrength(int rssi);
 void RecordRSSISignalStrengthLevel(UMARSSISignalStrengthLevel level);
 
+// In the case of not accepting all devices in the options that are given
+// to WebBluetooth requestDevice(), records the number of devices in the
+// chooser when a device is paired.
+void RecordNumOfDevices(bool accept_all_devices, size_t num_of_devices);
+
 }  // namespace content
 
 #endif  // CONTENT_BROWSER_BLUETOOTH_BLUETOOTH_METRICS_H_
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index 522246c..cc06aa8 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -129,6 +129,8 @@
   std::vector<std::pair<int, std::string>> pending_messages_;
   // <call_id> -> PendingMessage
   std::map<int, PendingMessage> sent_messages_;
+  // These are sent messages for which we got a reply while suspended.
+  std::map<int, PendingMessage> sent_messages_whose_reply_came_while_suspended_;
 };
 
 RenderFrameDevToolsAgentHost::FrameHostHolder::FrameHostHolder(
@@ -164,6 +166,13 @@
       host_->GetRoutingID(), agent_->GetId(), agent_->session()->session_id(),
       chunk_processor_.state_cookie()));
   if (old) {
+    if (IsBrowserSideNavigationEnabled()) {
+      for (const auto& pair :
+               old->sent_messages_whose_reply_came_while_suspended_) {
+        DispatchProtocolMessage(pair.second.session_id, pair.first,
+                                pair.second.method, pair.second.message);
+      }
+    }
     for (const auto& pair : old->sent_messages_) {
       DispatchProtocolMessage(pair.second.session_id, pair.first,
                               pair.second.method, pair.second.message);
@@ -232,11 +241,14 @@
 void RenderFrameDevToolsAgentHost::FrameHostHolder::SendMessageToClient(
     int session_id,
     const std::string& message) {
-  sent_messages_.erase(chunk_processor_.last_call_id());
-  if (suspended_)
+  int id = chunk_processor_.last_call_id();
+  if (suspended_) {
+    sent_messages_whose_reply_came_while_suspended_[id] = sent_messages_[id];
     pending_messages_.push_back(std::make_pair(session_id, message));
-  else
+  } else {
     agent_->SendMessageToClient(session_id, message);
+  }
+  sent_messages_.erase(id);
 }
 
 void RenderFrameDevToolsAgentHost::FrameHostHolder::Suspend() {
@@ -249,6 +261,7 @@
     agent_->SendMessageToClient(pair.first, pair.second);
   std::vector<std::pair<int, std::string>> empty;
   pending_messages_.swap(empty);
+  sent_messages_whose_reply_came_while_suspended_.clear();
 }
 
 // RenderFrameDevToolsAgentHost ------------------------------------------------
@@ -692,6 +705,8 @@
       DiscardPending();
     }
     pending_handle_ = nullptr;
+  } else if (navigating_handles_.empty()) {
+    current_->Resume();
   }
   DispatchBufferedProtocolMessagesIfNecessary();
 
@@ -733,6 +748,7 @@
     return;
   DCHECK(current_);
   navigating_handles_.insert(navigation_handle);
+  current_->Suspend();
   DCHECK(CheckConsistency());
 }
 
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index f3026d0b..4a0a6e4 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -140,7 +140,6 @@
     switches::kLoggingLevel,
     switches::kEnableLowEndDeviceMode,
     switches::kDisableLowEndDeviceMode,
-    switches::kEnableMemoryBenchmarking,
     switches::kNoSandbox,
     switches::kProfilerTiming,
     switches::kTestGLLib,
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 6fee0a3..932aaa9 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1717,7 +1717,6 @@
     switches::kEnableInbandTextTracks,
     switches::kEnableLCDText,
     switches::kEnableLogging,
-    switches::kEnableMemoryBenchmarking,
     switches::kEnableNetworkInformation,
     switches::kEnableOverlayScrollbar,
     switches::kEnablePinch,
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc
index 0888528..a8f20b0c 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -440,6 +440,7 @@
       content_view_core_(nullptr),
       ime_adapter_android_(this),
       cached_background_color_(SK_ColorWHITE),
+      view_(this),
       last_compositor_frame_sink_id_(kUndefinedCompositorFrameSinkId),
       gesture_provider_(ui::GetGestureProviderConfig(
                             ui::GestureProviderConfigType::CURRENT_PLATFORM),
@@ -718,7 +719,7 @@
         * ui::GetScaleFactorForNativeView(GetNativeView()));
   }
 
-  return content_view_core_->GetPhysicalBackingSize();
+  return view_.GetPhysicalBackingSize();
 }
 
 bool RenderWidgetHostViewAndroid::DoBrowserControlsShrinkBlinkSize() const {
@@ -803,6 +804,11 @@
     outstanding_vsync_requests_ &= ~PERSISTENT_BEGIN_FRAME;
 }
 
+void RenderWidgetHostViewAndroid::OnPhysicalBackingSizeChanged(int width,
+                                                               int height) {
+  WasResized();
+}
+
 void RenderWidgetHostViewAndroid::OnStartContentIntent(
     const GURL& content_url, bool is_main_frame) {
   if (content_view_core_)
diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h
index d29a0a9..84ce109 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.h
+++ b/content/browser/renderer_host/render_widget_host_view_android.h
@@ -32,6 +32,7 @@
 #include "gpu/command_buffer/common/mailbox.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/android/view_android.h"
+#include "ui/android/view_client.h"
 #include "ui/android/window_android_observer.h"
 #include "ui/events/android/motion_event_android.h"
 #include "ui/events/gesture_detection/filtered_gesture_provider.h"
@@ -65,6 +66,7 @@
 class CONTENT_EXPORT RenderWidgetHostViewAndroid
     : public RenderWidgetHostViewBase,
       public ui::GestureProviderClient,
+      public ui::ViewClient,
       public ui::WindowAndroidObserver,
       public DelegatedFrameEvictorClient,
       public StylusTextSelectorClient,
@@ -157,6 +159,9 @@
   void OnDidNavigateMainFrameToNewPage() override;
   void SetNeedsBeginFrames(bool needs_begin_frames) override;
 
+  // ui::ViewClient implementation.
+  void OnPhysicalBackingSizeChanged(int width, int height) override;
+
   // ui::GestureProviderClient implementation.
   void OnGestureEvent(const ui::GestureEventData& gesture) override;
 
diff --git a/content/browser/web_contents/web_contents_view_android.cc b/content/browser/web_contents/web_contents_view_android.cc
index 748b610..bd42f3c 100644
--- a/content/browser/web_contents/web_contents_view_android.cc
+++ b/content/browser/web_contents/web_contents_view_android.cc
@@ -84,6 +84,7 @@
     : web_contents_(web_contents),
       content_view_core_(NULL),
       delegate_(delegate),
+      view_(this),
       synchronous_compositor_client_(nullptr) {
 }
 
@@ -263,6 +264,12 @@
 void WebContentsViewAndroid::SetOverscrollControllerEnabled(bool enabled) {
 }
 
+void WebContentsViewAndroid::OnPhysicalBackingSizeChanged(int width,
+                                                          int height) {
+  // |SendScreenRects()| indirectly calls GetViewSize() that asks Java layer.
+  web_contents_->SendScreenRects();
+}
+
 void WebContentsViewAndroid::ShowContextMenu(
     RenderFrameHost* render_frame_host, const ContextMenuParams& params) {
   if (delegate_)
diff --git a/content/browser/web_contents/web_contents_view_android.h b/content/browser/web_contents/web_contents_view_android.h
index c1ad8dc..350bb0f 100644
--- a/content/browser/web_contents/web_contents_view_android.h
+++ b/content/browser/web_contents/web_contents_view_android.h
@@ -15,6 +15,7 @@
 #include "content/public/common/drop_data.h"
 #include "ui/android/overscroll_refresh.h"
 #include "ui/android/view_android.h"
+#include "ui/android/view_client.h"
 #include "ui/gfx/geometry/rect_f.h"
 
 namespace content {
@@ -24,7 +25,8 @@
 
 // Android-specific implementation of the WebContentsView.
 class WebContentsViewAndroid : public WebContentsView,
-                               public RenderViewHostDelegateView {
+                               public RenderViewHostDelegateView,
+                               public ui::ViewClient {
  public:
   WebContentsViewAndroid(WebContentsImpl* web_contents,
                          WebContentsViewDelegate* delegate);
@@ -71,6 +73,9 @@
   void RenderViewSwappedIn(RenderViewHost* host) override;
   void SetOverscrollControllerEnabled(bool enabled) override;
 
+  // ui::ViewClient implementation.
+  void OnPhysicalBackingSizeChanged(int width, int height) override;
+
   // Backend implementation of RenderViewHostDelegateView.
   void ShowContextMenu(RenderFrameHost* render_frame_host,
                        const ContextMenuParams& params) override;
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
index 6f3295f7c..d51e32f 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
@@ -87,6 +87,9 @@
  * Provides a Java-side 'wrapper' around a WebContent (native) instance.
  * Contains all the major functionality necessary to manage the lifecycle of a ContentView without
  * being tied to the view system.
+ *
+ * WARNING: ContentViewCore is in the process of being broken up. Please do not add new stuff.
+ * See https://crbug.com/598880.
  */
 @JNINamespace("content")
 public class ContentViewCore implements AccessibilityStateChangeListener, DisplayAndroidObserver,
@@ -299,8 +302,6 @@
     // Size of the viewport in physical pixels as set from onSizeChanged.
     private int mViewportWidthPix;
     private int mViewportHeightPix;
-    private int mPhysicalBackingWidthPix;
-    private int mPhysicalBackingHeightPix;
     private int mTopControlsHeightPix;
     private int mBottomControlsHeightPix;
     private boolean mTopControlsShrinkBlinkSize;
@@ -878,22 +879,6 @@
     }
 
     /**
-     * @return Width of underlying physical surface.
-     */
-    @CalledByNative
-    private int getPhysicalBackingWidthPix() {
-        return mPhysicalBackingWidthPix;
-    }
-
-    /**
-     * @return Height of underlying physical surface.
-     */
-    @CalledByNative
-    private int getPhysicalBackingHeightPix() {
-        return mPhysicalBackingHeightPix;
-    }
-
-    /**
      * @return The amount that the viewport size given to Blink is shrunk by the URL-bar..
      */
     @CalledByNative
@@ -1437,21 +1422,6 @@
         updateAfterSizeChanged();
     }
 
-    /**
-     * Called when the underlying surface the compositor draws to changes size.
-     * This may be larger than the viewport size.
-     */
-    public void onPhysicalBackingSizeChanged(int wPix, int hPix) {
-        if (mPhysicalBackingWidthPix == wPix && mPhysicalBackingHeightPix == hPix) return;
-
-        mPhysicalBackingWidthPix = wPix;
-        mPhysicalBackingHeightPix = hPix;
-
-        if (mNativeContentViewCore != 0) {
-            nativeWasResized(mNativeContentViewCore);
-        }
-    }
-
     private void updateAfterSizeChanged() {
         mPopupZoomer.hide(false);
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java
index 7721135..80b3593f 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java
@@ -15,6 +15,7 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.ui.base.ViewRoot;
 import org.chromium.ui.base.WindowAndroid;
 
 /***
@@ -71,8 +72,7 @@
                 nativeSurfaceChanged(mNativeContentViewRenderView,
                         format, width, height, holder.getSurface());
                 if (mContentViewCore != null) {
-                    mContentViewCore.onPhysicalBackingSizeChanged(
-                            width, height);
+                    getViewRoot().onPhysicalBackingSizeChanged(width, height);
                 }
             }
 
@@ -94,6 +94,10 @@
         mSurfaceView.setVisibility(VISIBLE);
     }
 
+    private ViewRoot getViewRoot() {
+        return mContentViewCore.getWindowAndroid().getViewRoot();
+    }
+
     /**
      * Sets the background color of the surface view.  This method is necessary because the
      * background color of ContentViewRenderView itself is covered by the background of
@@ -128,7 +132,7 @@
         mContentViewCore = contentViewCore;
 
         if (mContentViewCore != null) {
-            mContentViewCore.onPhysicalBackingSizeChanged(getWidth(), getHeight());
+            getViewRoot().onPhysicalBackingSizeChanged(getWidth(), getHeight());
             nativeSetCurrentWebContents(
                     mNativeContentViewRenderView, mContentViewCore.getWebContents());
         } else {
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 4a1424a..40c49cb 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -417,9 +417,6 @@
 // builds.
 const char kEnableLogging[]                 = "enable-logging";
 
-// Enables the memory benchmarking extension
-const char kEnableMemoryBenchmarking[]      = "enable-memory-benchmarking";
-
 // Enables the network information API.
 const char kEnableNetworkInformation[]      = "enable-network-information";
 
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 71ff89b3..b03955ca 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -135,7 +135,6 @@
 CONTENT_EXPORT extern const char kEnableLowResTiling[];
 CONTENT_EXPORT extern const char kEnableLCDText[];
 CONTENT_EXPORT extern const char kEnableLogging[];
-extern const char kEnableMemoryBenchmarking[];
 CONTENT_EXPORT extern const char kEnableNetworkInformation[];
 CONTENT_EXPORT extern const char kDisableNv12DxgiVideo[];
 CONTENT_EXPORT extern const char kEnablePinch[];
diff --git a/content/test/data/web_ui_mojo.js b/content/test/data/web_ui_mojo.js
index 3591135..adafb064 100644
--- a/content/test/data/web_ui_mojo.js
+++ b/content/test/data/web_ui_mojo.js
@@ -3,16 +3,15 @@
 // found in the LICENSE file.
 
 define('main', [
-    'mojo/public/js/router',
-    'content/test/data/web_ui_test_mojo_bindings.mojom',
     'content/public/renderer/frame_interfaces',
-], function (router, bindings, interfaceProvider) {
+    'content/test/data/web_ui_test_mojo_bindings.mojom',
+    'mojo/public/js/bindings',
+], function (interfaceProvider, webUITest, bindings) {
   var browserTarget;
 
   return function() {
-    browserTarget = new bindings.BrowserTarget.proxyClass(
-        new router.Router(
-            interfaceProvider.getInterface(bindings.BrowserTarget.name)));
+    browserTarget = new webUITest.BrowserTargetPtr(
+        interfaceProvider.getInterface(webUITest.BrowserTarget.name));
 
     browserTarget.start().then(function() {
       browserTarget.stop();
diff --git a/content/test/gpu/generate_buildbot_json.py b/content/test/gpu/generate_buildbot_json.py
index 96f122ca..32929e89 100755
--- a/content/test/gpu/generate_buildbot_json.py
+++ b/content/test/gpu/generate_buildbot_json.py
@@ -1105,6 +1105,13 @@
       'tab_capture_end2end_tests_run',
     ],
   },
+  'video_decode_accelerator_unittest': {
+    'tester_configs': [
+      {
+        'os_types': ['win']
+      },
+    ],
+  },
 }
 
 # This requires a hack because the isolate's name is different than
@@ -1648,7 +1655,7 @@
   tests['AAAAA1 AUTOGENERATED FILE DO NOT EDIT'] = {}
   tests['AAAAA2 See generate_buildbot_json.py to make changes'] = {}
   filename = 'chromium.gpu.fyi.json' if is_fyi else 'chromium.gpu.json'
-  with open(os.path.join(SRC_DIR, 'testing', 'buildbot', filename), 'w') as fp:
+  with open(os.path.join(SRC_DIR, 'testing', 'buildbot', filename), 'wb') as fp:
     json.dump(tests, fp, indent=2, separators=(',', ': '), sort_keys=True)
     fp.write('\n')
 
diff --git a/extensions/browser/api/audio/OWNERS b/extensions/browser/api/audio/OWNERS
index 3ed331b..c55e14c 100644
--- a/extensions/browser/api/audio/OWNERS
+++ b/extensions/browser/api/audio/OWNERS
@@ -1 +1,2 @@
+tbarzic@chromium.org
 steel@chromium.org
diff --git a/extensions/renderer/resources/media_router_bindings.js b/extensions/renderer/resources/media_router_bindings.js
index 40ebfab8..0373e036 100644
--- a/extensions/renderer/resources/media_router_bindings.js
+++ b/extensions/renderer/resources/media_router_bindings.js
@@ -5,22 +5,16 @@
 var mediaRouter;
 
 define('media_router_bindings', [
-    'mojo/public/js/bindings',
-    'mojo/public/js/core',
     'content/public/renderer/frame_interfaces',
     'chrome/browser/media/router/mojo/media_router.mojom',
     'extensions/common/mojo/keep_alive.mojom',
     'mojo/common/time.mojom',
-    'mojo/public/js/connection',
-    'mojo/public/js/router',
-], function(bindings,
-            core,
-            frameInterfaces,
+    'mojo/public/js/bindings',
+], function(frameInterfaces,
             mediaRouterMojom,
             keepAliveMojom,
             timeMojom,
-            connector,
-            routerModule) {
+            bindings) {
   'use strict';
 
   /**
@@ -187,14 +181,14 @@
   /**
    * Creates a new MediaRouter.
    * Converts a route struct to its Mojo form.
-   * @param {!MediaRouterService} service
+   * @param {!mediaRouterMojom.MediaRouterPtr} service
    * @constructor
    */
   function MediaRouter(service) {
     /**
      * The Mojo service proxy. Allows extension code to call methods that reside
      * in the browser.
-     * @type {!MediaRouterService}
+     * @type {!mediaRouterMojom.MediaRouterPtr}
      */
     this.service_ = service;
 
@@ -287,10 +281,10 @@
    */
   MediaRouter.prototype.setKeepAlive = function(keepAlive) {
     if (keepAlive === false && this.keepAlive_) {
-      this.keepAlive_.close();
+      this.keepAlive_.ptr.reset();
       this.keepAlive_ = null;
     } else if (keepAlive === true && !this.keepAlive_) {
-      this.keepAlive_ = new routerModule.Router(
+      this.keepAlive_ = new keepAliveMojom.KeepAlivePtr(
           frameInterfaces.getInterface(keepAliveMojom.KeepAlive.name));
     }
   };
@@ -498,8 +492,6 @@
    * @constructor
    */
   function MediaRouteProvider(mediaRouter) {
-    mediaRouterMojom.MediaRouteProvider.stubClass.call(this);
-
     /**
      * Object containing JS callbacks into Provider Manager code.
      * @type {!MediaRouterHandlers}
@@ -512,8 +504,6 @@
      */
     this.mediaRouter_ = mediaRouter;
   }
-  MediaRouteProvider.prototype = Object.create(
-      mediaRouterMojom.MediaRouteProvider.stubClass.prototype);
 
   /*
    * Sets the callback handler used to invoke methods in the provider manager.
@@ -813,9 +803,8 @@
     });
   };
 
-  mediaRouter = new MediaRouter(connector.bindHandleToProxy(
-      frameInterfaces.getInterface(mediaRouterMojom.MediaRouter.name),
-      mediaRouterMojom.MediaRouter));
+  mediaRouter = new MediaRouter(new mediaRouterMojom.MediaRouterPtr(
+      frameInterfaces.getInterface(mediaRouterMojom.MediaRouter.name)));
 
   return mediaRouter;
 });
diff --git a/extensions/renderer/resources/mime_handler_private_custom_bindings.js b/extensions/renderer/resources/mime_handler_private_custom_bindings.js
index 4a515394..1fa03663 100644
--- a/extensions/renderer/resources/mime_handler_private_custom_bindings.js
+++ b/extensions/renderer/resources/mime_handler_private_custom_bindings.js
@@ -15,13 +15,11 @@
 var servicePromise = Promise.all([
     requireAsync('content/public/renderer/frame_interfaces'),
     requireAsync('extensions/common/api/mime_handler.mojom'),
-    requireAsync('mojo/public/js/router'),
 ]).then(function(modules) {
   var frameInterfaces = modules[0];
   var mojom = modules[1];
-  var routerModule = modules[2];
-  return new mojom.MimeHandlerService.proxyClass(new routerModule.Router(
-      frameInterfaces.getInterface(mojom.MimeHandlerService.name)));
+  return new mojom.MimeHandlerServicePtr(
+      frameInterfaces.getInterface(mojom.MimeHandlerService.name));
 });
 
 // Stores a promise to the GetStreamInfo() result to avoid making additional
diff --git a/extensions/test/data/api_test_base_unittest.js b/extensions/test/data/api_test_base_unittest.js
index 6aa8b78..094a623 100644
--- a/extensions/test/data/api_test_base_unittest.js
+++ b/extensions/test/data/api_test_base_unittest.js
@@ -36,14 +36,14 @@
   },
   function testMojoModulesAreAvailable() {
     Promise.all([
-      requireAsync('mojo/public/js/connection'),
+      requireAsync('mojo/public/js/bindings'),
       requireAsync('mojo/public/js/core'),
       requireAsync('content/public/renderer/frame_interfaces'),
     ]).then(test.callback(function(modules) {
-      var connection = modules[0];
+      var bindings = modules[0];
       var core = modules[1];
       var frameInterfaces = modules[2];
-      test.assertTrue(!!connection.Connection);
+      test.assertTrue(!!bindings.Binding);
       test.assertTrue(!!core.createMessagePipe);
       test.assertTrue(!!frameInterfaces.getInterface);
     }));
diff --git a/headless/lib/embedder_mojo_browsertest.cc b/headless/lib/embedder_mojo_browsertest.cc
index 3fb4ed1..0ae117b33 100644
--- a/headless/lib/embedder_mojo_browsertest.cc
+++ b/headless/lib/embedder_mojo_browsertest.cc
@@ -152,16 +152,12 @@
         "// fires after the requested modules have been loaded.              \n"
         "define([                                                            \n"
         "    'headless/lib/embedder_test.mojom',                             \n"
-        "    'mojo/public/js/core',                                          \n"
-        "    'mojo/public/js/router',                                        \n"
         "    'content/public/renderer/frame_interfaces',                     \n"
-        "    ], function(embedderMojom, mojoCore, routerModule,              \n"
-        "                frameInterfaces) {                                  \n"
+        "    ], function(embedderMojom, frameInterfaces) {                   \n"
         "  var testEmbedderService =                                         \n"
-        "      new embedderMojom.TestEmbedderService.proxyClass(             \n"
-        "          new routerModule.Router(                                  \n"
-        "              frameInterfaces.getInterface(                         \n"
-        "                  embedderMojom.TestEmbedderService.name)));        \n"
+        "      new embedderMojom.TestEmbedderServicePtr(                     \n"
+        "          frameInterfaces.getInterface(                             \n"
+        "              embedderMojom.TestEmbedderService.name));             \n"
         "                                                                    \n"
         "  // Send a message to the embedder!                                \n"
         "  testEmbedderService.returnTestResult('hello world');              \n"
diff --git a/headless/test/data/page_one.html b/headless/test/data/page_one.html
index 469b95ac..a29176e 100644
--- a/headless/test/data/page_one.html
+++ b/headless/test/data/page_one.html
@@ -6,16 +6,10 @@
 // fires after the requested modules have been loaded.
 define([
     'headless/lib/embedder_test.mojom',
-    'mojo/public/js/core',
-    'mojo/public/js/router',
     'content/public/renderer/frame_interfaces',
-    ], function(embedderMojom, mojoCore, routerModule,
-                frameInterfaces) {
-  var testEmbedderService =
-      new embedderMojom.TestEmbedderService.proxyClass(
-          new routerModule.Router(
-              frameInterfaces.getInterface(
-                  embedderMojom.TestEmbedderService.name)));
+    ], function(embedderMojom, frameInterfaces) {
+  var testEmbedderService = new embedderMojom.TestEmbedderServicePtr(
+      frameInterfaces.getInterface(embedderMojom.TestEmbedderService.name));
 
   // Send a message to the embedder!
   testEmbedderService.returnTestResult('page one');
diff --git a/headless/test/data/page_two.html b/headless/test/data/page_two.html
index 7cf22d4e..47edec7 100644
--- a/headless/test/data/page_two.html
+++ b/headless/test/data/page_two.html
@@ -6,16 +6,10 @@
 // fires after the requested modules have been loaded.
 define([
     'headless/lib/embedder_test.mojom',
-    'mojo/public/js/core',
-    'mojo/public/js/router',
     'content/public/renderer/frame_interfaces',
-    ], function(embedderMojom, mojoCore, routerModule,
-                frameInterfaces) {
-  var testEmbedderService =
-      new embedderMojom.TestEmbedderService.proxyClass(
-          new routerModule.Router(
-              frameInterfaces.getInterface(
-                  embedderMojom.TestEmbedderService.name)));
+    ], function(embedderMojom, frameInterfaces) {
+  var testEmbedderService = new embedderMojom.TestEmbedderServicePtr(
+      frameInterfaces.getInterface(embedderMojom.TestEmbedderService.name));
 
   // Send a message to the embedder!
   testEmbedderService.returnTestResult('page two');
diff --git a/ios/BUILD.gn b/ios/BUILD.gn
index bed47ee..feff75ce 100644
--- a/ios/BUILD.gn
+++ b/ios/BUILD.gn
@@ -27,6 +27,8 @@
   } else {
     deps = [
       # List all the targets that need to be build on iOS by default.
+      "//ios/chrome/app:chrome",
+      "//ios/chrome/app:chrome_clean_skeleton",
       "//ios/web/shell:ios_web_shell",
 
       # List all the test targets that need to be build on iOS by default.
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn
index 8f522fc..c94edae 100644
--- a/ios/chrome/app/BUILD.gn
+++ b/ios/chrome/app/BUILD.gn
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import("//build/config/ios/rules.gni")
+import("//build/config/mac/base_rules.gni")
 import("//build/mac/tweak_info_plist.gni")
 import("//ios/build/chrome_build.gni")
 import("//ios/public/provider/chrome/browser/build_config.gni")
@@ -29,14 +30,28 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
+    "chrome_app_startup_parameters_unittest.mm",
+    "chrome_overlay_window_testing.h",
     "deferred_initialization_runner_unittest.mm",
+    "main_application_delegate_unittest.mm",
+    "main_controller_unittest.mm",
     "safe_mode_util_unittest.cc",
   ]
   deps = [
     ":app",
+    ":app_internal",
     "//base",
     "//base/test:test_support",
+    "//ios/chrome/app/application_delegate:application_delegate_internal",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/common/app_group",
+    "//ios/chrome/test/base",
+    "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser/distribution",
     "//testing/gtest",
+    "//third_party/ocmock",
+    "//url",
   ]
 }
 
@@ -96,3 +111,297 @@
   substitutions = [ "IOS_BUNDLE_ID_PREFIX=$ios_app_bundle_id_prefix" ]
   output_name = "$target_gen_dir/$chromium_short_name.entitlements"
 }
+
+source_set("app_internal") {
+  sources = [
+    "application_mode.h",
+    "chrome_app_startup_parameters.h",
+    "chrome_app_startup_parameters.mm",
+    "chrome_overlay_window.h",
+    "chrome_overlay_window.mm",
+    "main_application_delegate.h",
+    "main_application_delegate.mm",
+    "main_application_delegate_testing.h",
+    "main_controller.h",
+    "main_controller.mm",
+    "main_controller_private.h",
+    "memory_monitor.h",
+    "memory_monitor.mm",
+    "startup_tasks.h",
+    "startup_tasks.mm",
+  ]
+
+  deps = [
+    "//base",
+    "//components/bookmarks/browser",
+    "//components/browser_sync",
+    "//components/browsing_data/core",
+    "//components/component_updater",
+    "//components/content_settings/core/browser",
+    "//components/crash/core/common",
+    "//components/favicon/core",
+    "//components/favicon_base",
+    "//components/handoff",
+    "//components/history/core/browser",
+    "//components/infobars/core",
+    "//components/keyed_service/core",
+    "//components/keyed_service/ios",
+    "//components/metrics",
+    "//components/prefs",
+    "//components/proxy_config",
+    "//components/reading_list/core",
+    "//components/signin/core/browser",
+    "//components/suggestions",
+    "//components/sync",
+    "//components/url_formatter",
+    "//components/web_resource",
+    "//ios/chrome/app",
+    "//ios/chrome/app:tests_hook",
+    "//ios/chrome/app/application_delegate",
+    "//ios/chrome/app/application_delegate:application_delegate_internal",
+    "//ios/chrome/app/safe_mode",
+    "//ios/chrome/app/spotlight",
+    "//ios/chrome/app/startup",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser:browser_internal",
+    "//ios/chrome/browser/bookmarks",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/browser_state:browser_state_impl",
+    "//ios/chrome/browser/browsing_data",
+    "//ios/chrome/browser/browsing_data:browsing_data_internal",
+    "//ios/chrome/browser/content_settings",
+    "//ios/chrome/browser/crash_report",
+    "//ios/chrome/browser/crash_report:crash_report_internal",
+    "//ios/chrome/browser/favicon",
+    "//ios/chrome/browser/first_run",
+    "//ios/chrome/browser/geolocation",
+    "//ios/chrome/browser/geolocation:geolocation_internal",
+    "//ios/chrome/browser/history",
+    "//ios/chrome/browser/memory",
+    "//ios/chrome/browser/metrics",
+    "//ios/chrome/browser/metrics:metrics_internal",
+    "//ios/chrome/browser/native_app_launcher:native_app_launcher_internal",
+    "//ios/chrome/browser/net",
+    "//ios/chrome/browser/omaha",
+    "//ios/chrome/browser/prefs",
+    "//ios/chrome/browser/reading_list",
+    "//ios/chrome/browser/search_engines",
+    "//ios/chrome/browser/share_extension",
+    "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/snapshots",
+    "//ios/chrome/browser/suggestions",
+    "//ios/chrome/browser/sync",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui:ui_internal",
+    "//ios/chrome/browser/ui/authentication",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/contextual_search",
+    "//ios/chrome/browser/ui/downloads",
+    "//ios/chrome/browser/ui/first_run",
+    "//ios/chrome/browser/ui/history",
+    "//ios/chrome/browser/ui/main",
+    "//ios/chrome/browser/ui/promos",
+    "//ios/chrome/browser/ui/settings",
+    "//ios/chrome/browser/ui/stack_view",
+    "//ios/chrome/browser/ui/tab_switcher",
+    "//ios/chrome/browser/ui/tabs",
+    "//ios/chrome/browser/ui/util",
+    "//ios/chrome/browser/ui/webui:webui_internal",
+    "//ios/chrome/browser/upgrade",
+    "//ios/chrome/browser/variations:ios_chrome_ui_string_overrider_factory",
+    "//ios/chrome/browser/voice",
+    "//ios/chrome/browser/web:web_internal",
+    "//ios/chrome/common",
+    "//ios/chrome/common/app_group",
+    "//ios/chrome/common/app_group:main_app",
+    "//ios/net",
+    "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser/distribution",
+    "//ios/public/provider/chrome/browser/native_app_launcher",
+    "//ios/public/provider/chrome/browser/signin",
+    "//ios/public/provider/chrome/browser/user_feedback",
+    "//ios/third_party/material_roboto_font_loader_ios",
+    "//ios/web",
+    "//ios/web/public/app",
+    "//mojo/edk/system",
+    "//net",
+    "//skia",
+    "//ui/base",
+    "//ui/gfx",
+    "//ui/resources",
+    "//ui/strings:ui_strings",
+  ]
+
+  libs = [
+    "CoreSpotlight.framework",
+    "MediaPlayer.framework",
+  ]
+
+  allow_circular_includes_from =
+      [ "//ios/chrome/app/application_delegate:application_delegate_internal" ]
+}
+
+source_set("main") {
+  sources = [
+    "chrome_exe_main.mm",
+  ]
+
+  deps = [
+    ":app_internal",
+    "//base",
+    "//components/crash/core/common",
+    "//ios/chrome/app/startup",
+    "//ios/chrome/browser:browser_internal",
+    "//ios/chrome/browser/crash_report",
+    "//ios/chrome/common",
+    "//third_party/google_toolbox_for_mac",
+  ]
+}
+
+ios_app_bundle("chrome") {
+  output_name = chromium_short_name
+
+  entitlements_target = ":entitlements"
+  info_plist_target = ":info_plist"
+
+  deps = [
+    ":main",
+    "//ios/chrome/app:tests_fake_hook",
+  ]
+
+  bundle_deps = [ "//ios/chrome/app/resources" ]
+
+  if (ios_enable_today_extension && current_toolchain == default_toolchain) {
+    deps += [ ":today_extension_bundle" ]
+  }
+
+  if (ios_enable_share_extension && current_toolchain == default_toolchain) {
+    deps += [ ":share_extension_bundle" ]
+  }
+
+  extra_substitutions = [
+    "CHROMIUM_BUNDLE_ID=$chromium_bundle_id",
+    "CHROMIUM_HANDOFF_ID=$chromium_handoff_id",
+    "CHROMIUM_SHORT_NAME=$chromium_short_name",
+    "CHROMIUM_URL_SCHEME_1=$url_unsecure_scheme",
+    "CHROMIUM_URL_SCHEME_2=$url_secure_scheme",
+    "CHROMIUM_URL_SCHEME_3=$url_x_callback_scheme",
+    "CHROMIUM_URL_SCHEME_4=$url_channel_scheme",
+    "SSOAUTH_URL_SCHEME=$url_ssoauth_scheme",
+  ]
+
+  if (ios_encryption_export_compliance_code != "") {
+    extra_substitutions += [ "ENCRYPTION_EXPORT_COMPLIANCE_CODE=" +
+                             ios_encryption_export_compliance_code ]
+  }
+}
+
+if (ios_enable_today_extension && current_toolchain == default_toolchain) {
+  bundle_data("today_extension_bundle") {
+    public_deps = [
+      "//ios/chrome/today_extension",
+    ]
+    sources = [
+      "$root_out_dir/today_extension.appex",
+    ]
+    outputs = [
+      "{{bundle_plugins_dir}}/{{source_file_part}}",
+    ]
+  }
+}
+
+if (ios_enable_share_extension && current_toolchain == default_toolchain) {
+  bundle_data("share_extension_bundle") {
+    public_deps = [
+      "//ios/chrome/share_extension",
+    ]
+    sources = [
+      "$root_out_dir/share_extension.appex",
+    ]
+    outputs = [
+      "{{bundle_plugins_dir}}/{{source_file_part}}",
+    ]
+  }
+}
+
+# Clean Skeleton targets.
+ios_app_bundle("chrome_clean_skeleton") {
+  output_name = "CSChromium"
+
+  entitlements_path = "//ios/chrome/app/resources/Chrome.entitlements"
+  info_plist_target = ":info_plist"
+
+  deps = [
+    ":main_clean_skeleton",
+    "//ios/chrome/app:tests_fake_hook",
+  ]
+
+  bundle_deps = [ "//ios/chrome/app/resources" ]
+
+  extra_substitutions = [
+    "CHROMIUM_BUNDLE_ID=$chromium_bundle_id",
+    "CHROMIUM_SHORT_NAME=$chromium_short_name",
+    "CHROMIUM_URL_SCHEME_1=$url_unsecure_scheme",
+    "CHROMIUM_URL_SCHEME_2=$url_secure_scheme",
+    "CHROMIUM_URL_SCHEME_3=$url_x_callback_scheme",
+    "CHROMIUM_URL_SCHEME_4=$url_channel_scheme",
+  ]
+
+  if (ios_encryption_export_compliance_code != "") {
+    extra_substitutions += [ "ENCRYPTION_EXPORT_COMPLIANCE_CODE=" +
+                             ios_encryption_export_compliance_code ]
+  }
+}
+
+source_set("main_clean_skeleton") {
+  sources = [
+    "main.mm",
+  ]
+
+  deps = [
+    ":app_clean_skeleton",
+    "//base",
+    "//components/crash/core/common",
+    "//ios/chrome/app:app_internal",
+    "//ios/chrome/app/startup",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser:browser_internal",
+    "//ios/chrome/browser/crash_report",
+    "//ios/chrome/common",
+    "//third_party/google_toolbox_for_mac",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+}
+
+source_set("application_state_clean_skeleton") {
+  sources = [
+    "application_phase.h",
+    "application_state.h",
+    "application_state.mm",
+    "application_step.h",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+
+  deps = [
+    "//base",
+    "//ios/chrome/browser:browser_clean_skeleton",
+  ]
+}
+
+source_set("app_clean_skeleton") {
+  sources = [
+    "app_delegate.h",
+    "app_delegate.mm",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+
+  deps = [
+    ":application_state_clean_skeleton",
+    "//ios/chrome/app/steps",
+  ]
+}
diff --git a/ios/chrome/app/application_delegate/BUILD.gn b/ios/chrome/app/application_delegate/BUILD.gn
index adea24c..c56736b 100644
--- a/ios/chrome/app/application_delegate/BUILD.gn
+++ b/ios/chrome/app/application_delegate/BUILD.gn
@@ -20,12 +20,136 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
+    "app_state_unittest.mm",
+    "background_activity_unittest.mm",
     "memory_warning_helper_unittest.mm",
+    "metrics_mediator_unittest.mm",
+    "url_opener_unittest.mm",
+    "user_activity_handler_unittest.mm",
   ]
   deps = [
     ":application_delegate",
+    ":application_delegate_internal",
+    ":test_support",
     "//base",
+    "//base/test:test_support",
+    "//breakpad:client",
+    "//components/handoff",
+    "//components/metrics",
+    "//ios/chrome/app",
+    "//ios/chrome/app:app_internal",
+    "//ios/chrome/app/application_delegate",
+    "//ios/chrome/app/safe_mode",
+    "//ios/chrome/app/spotlight",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/crash_report",
+    "//ios/chrome/browser/device_sharing",
+    "//ios/chrome/browser/geolocation",
     "//ios/chrome/browser/metrics",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/u2f",
+    "//ios/chrome/browser/ui:ui_internal",
+    "//ios/chrome/browser/ui/main",
+    "//ios/chrome/browser/ui/settings",
+    "//ios/chrome/test:test_support",
+    "//ios/chrome/test/base",
+    "//ios/chrome/test/ocmock",
+    "//ios/public/provider/chrome/browser:test_support",
+    "//ios/public/provider/chrome/browser/distribution",
+    "//ios/public/provider/chrome/browser/user_feedback:test_support",
+    "//ios/testing:ocmock_support",
+    "//ios/web",
+    "//ios/web:test_support",
+    "//net:test_support",
     "//testing/gtest",
+    "//third_party/ocmock",
+    "//ui/base",
+    "//url",
   ]
+  libs = [
+    "CoreSpotlight.framework",
+    "QuartzCore.framework",
+  ]
+}
+
+source_set("application_delegate_internal") {
+  sources = [
+    "app_navigation.h",
+    "app_state.h",
+    "app_state.mm",
+    "background_activity.h",
+    "background_activity.mm",
+    "browser_launcher.h",
+    "metrics_mediator.h",
+    "metrics_mediator.mm",
+    "startup_information.h",
+    "tab_opening.h",
+    "tab_switching.h",
+    "url_opener.h",
+    "url_opener.mm",
+    "user_activity_handler.h",
+    "user_activity_handler.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/crash/core/common",
+    "//components/handoff",
+    "//components/metrics",
+    "//components/prefs",
+    "//ios/chrome/app",
+    "//ios/chrome/app/application_delegate",
+    "//ios/chrome/app/safe_mode",
+    "//ios/chrome/app/spotlight",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/crash_report",
+    "//ios/chrome/browser/device_sharing",
+    "//ios/chrome/browser/geolocation",
+    "//ios/chrome/browser/metrics",
+    "//ios/chrome/browser/metrics:metrics_internal",
+    "//ios/chrome/browser/net",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/u2f",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui:ui_internal",
+    "//ios/chrome/browser/ui/authentication",
+    "//ios/chrome/browser/ui/main",
+    "//ios/chrome/common/app_group:main_app",
+    "//ios/net",
+    "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser/distribution",
+    "//ios/public/provider/chrome/browser/user_feedback",
+    "//ios/web",
+    "//net",
+    "//ui/base",
+    "//url",
+  ]
+  libs = [
+    "CoreSpotlight.framework",
+    "UIKit.framework",
+  ]
+}
+
+source_set("test_support") {
+  testonly = true
+  sources = [
+    "app_state_testing.h",
+    "fake_startup_information.h",
+    "fake_startup_information.mm",
+    "metrics_mediator_testing.h",
+    "mock_tab_opener.h",
+    "mock_tab_opener.mm",
+  ]
+  deps = [
+    ":application_delegate_internal",
+    "//base",
+    "//base/test:test_support",
+    "//ios/chrome/app:app_internal",
+    "//ios/chrome/browser",
+    "//net",
+    "//ui/base",
+    "//url",
+  ]
+  libs = [ "UIKit.framework" ]
 }
diff --git a/ios/chrome/app/safe_mode/BUILD.gn b/ios/chrome/app/safe_mode/BUILD.gn
index 17b18e6b..947affb 100644
--- a/ios/chrome/app/safe_mode/BUILD.gn
+++ b/ios/chrome/app/safe_mode/BUILD.gn
@@ -12,3 +12,62 @@
     "{{bundle_resources_dir}}/{{source_file_part}}",
   ]
 }
+
+source_set("safe_mode") {
+  sources = [
+    "safe_mode_coordinator.h",
+    "safe_mode_coordinator.mm",
+    "safe_mode_view_controller.h",
+    "safe_mode_view_controller.mm",
+  ]
+
+  deps = [
+    "//base",
+    "//ios/chrome/app",
+    "//ios/chrome/app/safe_mode:resources",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/crash_report",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/fancy_ui",
+    "//ui/gfx",
+  ]
+
+  libs = [ "UIKit.framework" ]
+}
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "safe_mode_egtest.mm",
+  ]
+  deps = [
+    ":safe_mode",
+    "//base",
+    "//ios/chrome/app:app_internal",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui/main",
+    "//ios/chrome/test/base",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/third_party/earl_grey",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "safe_mode_coordinator_unittest.mm",
+    "safe_mode_view_controller_unittest.mm",
+  ]
+  deps = [
+    ":safe_mode",
+    "//base",
+    "//breakpad:client",
+    "//ios/chrome/browser/crash_report",
+    "//ios/chrome/test/base",
+    "//ios/chrome/test/ocmock",
+    "//testing/gtest",
+    "//third_party/ocmock",
+  ]
+  libs = [ "UIKit.framework" ]
+}
diff --git a/ios/chrome/app/spotlight/BUILD.gn b/ios/chrome/app/spotlight/BUILD.gn
new file mode 100644
index 0000000..89c8853
--- /dev/null
+++ b/ios/chrome/app/spotlight/BUILD.gn
@@ -0,0 +1,70 @@
+# 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.
+
+source_set("spotlight") {
+  sources = [
+    "actions_spotlight_manager.h",
+    "actions_spotlight_manager.mm",
+    "base_spotlight_manager.h",
+    "base_spotlight_manager.mm",
+    "bookmarks_spotlight_manager.h",
+    "bookmarks_spotlight_manager.mm",
+    "spotlight_manager.h",
+    "spotlight_manager.mm",
+    "spotlight_util.h",
+    "spotlight_util.mm",
+    "topsites_spotlight_manager.h",
+    "topsites_spotlight_manager.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/bookmarks/browser",
+    "//components/browser_sync",
+    "//components/favicon/core",
+    "//components/favicon_base",
+    "//components/history/core/browser",
+    "//components/suggestions",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/bookmarks",
+    "//ios/chrome/browser/favicon",
+    "//ios/chrome/browser/history",
+    "//ios/chrome/browser/suggestions",
+    "//ios/chrome/browser/sync",
+    "//ios/chrome/browser/ui/ntp:ntp_internal",
+    "//ios/chrome/common/app_group",
+    "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser/spotlight",
+    "//ios/third_party/material_components_ios",
+    "//net",
+    "//skia",
+    "//ui/base",
+    "//url",
+  ]
+  libs = [
+    "CoreSpotlight.framework",
+    "UIKit.framework",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "spotlight_manager_unittest.mm",
+  ]
+  deps = [
+    ":spotlight",
+    "//base",
+    "//components/bookmarks/browser",
+    "//components/bookmarks/test",
+    "//components/favicon/core",
+    "//components/favicon_base",
+    "//ios/chrome/browser/bookmarks",
+    "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser/spotlight",
+    "//net",
+    "//testing/gtest",
+  ]
+  libs = [ "CoreSpotlight.framework" ]
+}
diff --git a/ios/chrome/app/startup/BUILD.gn b/ios/chrome/app/startup/BUILD.gn
new file mode 100644
index 0000000..f99be35
--- /dev/null
+++ b/ios/chrome/app/startup/BUILD.gn
@@ -0,0 +1,41 @@
+# 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.
+
+import("//ios/public/provider/chrome/browser/build_config.gni")
+
+source_set("startup") {
+  sources = [
+    "chrome_main_starter.h",
+    "chrome_main_starter.mm",
+    "client_registration.h",
+    "client_registration.mm",
+    "ios_chrome_main.h",
+    "ios_chrome_main.mm",
+    "ios_chrome_main_delegate.h",
+    "ios_chrome_main_delegate.mm",
+    "network_stack_setup.h",
+    "network_stack_setup.mm",
+    "provider_registration.h",
+    "provider_registration.mm",
+    "register_experimental_settings.h",
+    "register_experimental_settings.mm",
+    "setup_debugging.h",
+    "setup_debugging.mm",
+  ]
+
+  deps = [
+    "//base",
+    "//components/crash/core/common",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser:browser_internal",
+    "//ios/chrome/browser/web",
+    "//ios/chrome/browser/web:web_internal",
+    "//ios/net",
+    "//ios/public/provider/chrome/browser",
+    "//ios/web",
+    "//ios/web/public/app",
+    "//skia",
+    ios_provider_target,
+  ]
+}
diff --git a/ios/chrome/app/steps/BUILD.gn b/ios/chrome/app/steps/BUILD.gn
new file mode 100644
index 0000000..5d44d5c
--- /dev/null
+++ b/ios/chrome/app/steps/BUILD.gn
@@ -0,0 +1,36 @@
+# 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.
+
+source_set("steps") {
+  sources = [
+    "launch_to_background.h",
+    "launch_to_background.mm",
+    "launch_to_basic.h",
+    "launch_to_basic.mm",
+    "launch_to_foreground.h",
+    "launch_to_foreground.mm",
+    "tab_grid_coordinator+application_step.h",
+    "tab_grid_coordinator+application_step.mm",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+
+  deps = [
+    "//base",
+    "//components/content_settings/core/browser",
+    "//ios/chrome/app:app_internal",
+    "//ios/chrome/app:application_state_clean_skeleton",
+    "//ios/chrome/app/startup",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser:browser_clean_skeleton",
+    "//ios/chrome/browser:browser_internal",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/browser_state:browser_state_impl",
+    "//ios/chrome/browser/content_settings",
+    "//ios/chrome/browser/ui/tab_grid",
+    "//ios/chrome/browser/web:web_internal",
+    "//ios/net",
+    "//ios/web:web_arc",
+  ]
+}
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn
index bcea0d6f..81b92b1 100644
--- a/ios/chrome/browser/BUILD.gn
+++ b/ios/chrome/browser/BUILD.gn
@@ -221,6 +221,7 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
+    "callback_counter_unittest.mm",
     "chrome_url_util_unittest.mm",
     "crash_loop_detection_util_unittest.mm",
     "install_time_util_unittest.mm",
@@ -230,6 +231,7 @@
   ]
   deps = [
     ":browser",
+    ":browser_internal",
     "//base",
     "//base/test:test_support",
     "//components/prefs",
@@ -244,3 +246,72 @@
     "//url",
   ]
 }
+
+source_set("browser_internal") {
+  sources = [
+    "callback_counter.h",
+    "callback_counter.mm",
+  ]
+  deps = [
+    "//base",
+  ]
+}
+
+source_set("downstream_provider") {
+  sources = [
+    "downstream_chromium_browser_provider.h",
+    "downstream_chromium_browser_provider.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/handoff",
+    "//components/pref_registry",
+    "//components/prefs",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/autofill:autofill_internal",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/browser_state:browser_state_impl",
+    "//ios/chrome/browser/providers",
+    "//ios/chrome/browser/sessions:sessions_internal",
+    "//ios/chrome/browser/sync/glue",
+    "//ios/chrome/browser/sync/sessions",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/tabs:tabs_internal",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui:browser_list",
+    "//ios/chrome/browser/ui/autofill:autofill_internal",
+    "//ios/chrome/browser/ui/bookmarks",
+    "//ios/chrome/browser/ui/infobars",
+    "//ios/chrome/browser/ui/webui:webui_internal",
+    "//ios/chrome/common",
+  ]
+}
+
+source_set("downstream_provider_factory") {
+  sources = [
+    "downstream_chromium_browser_provider_factory.mm",
+  ]
+  deps = [
+    ":downstream_provider",
+    "//base",
+    "//ios/public/provider/chrome/browser",
+  ]
+}
+
+# Clean Skeleton targets
+source_set("browser_clean_skeleton") {
+  sources = [
+    "browser_coordinator+internal.h",
+    "browser_coordinator.h",
+    "browser_coordinator.mm",
+    "url_opening.h",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+
+  deps = [
+    "//base",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state",
+  ]
+}
diff --git a/ios/chrome/browser/autofill/BUILD.gn b/ios/chrome/browser/autofill/BUILD.gn
index 2c35bce9..21bd1b6 100644
--- a/ios/chrome/browser/autofill/BUILD.gn
+++ b/ios/chrome/browser/autofill/BUILD.gn
@@ -40,3 +40,92 @@
   ]
   libs = [ "QuartzCore.framework" ]
 }
+
+source_set("autofill_internal") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [
+    "autofill_agent.h",
+    "autofill_agent.mm",
+    "autofill_controller.h",
+    "autofill_controller.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/autofill/core/browser",
+    "//components/autofill/core/common",
+    "//components/autofill/ios/browser",
+    "//components/infobars/core",
+    "//components/pref_registry",
+    "//components/prefs",
+    "//components/signin/core/browser",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/autofill",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/infobars",
+    "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/ui/autofill",
+    "//ios/web",
+    "//ui/gfx/geometry",
+    "//url",
+  ]
+  libs = [ "UIKit.framework" ]
+}
+
+source_set("unit_tests") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  testonly = true
+  sources = [
+    "autofill_controller_js_unittest.mm",
+    "autofill_controller_unittest.mm",
+    "form_structure_browsertest.mm",
+    "form_suggestion_controller_unittest.mm",
+    "js_autofill_manager_unittest.mm",
+    "js_suggestion_manager_unittest.mm",
+  ]
+  deps = [
+    ":autofill_internal",
+    "//base",
+    "//base/test:test_support",
+    "//components/autofill/core/browser",
+    "//components/autofill/core/browser:test_support",
+    "//components/autofill/core/common",
+    "//components/autofill/ios/browser",
+    "//components/infobars/core",
+    "//components/keyed_service/core",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/autofill",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/infobars",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/autofill",
+    "//ios/chrome/browser/web:test_support",
+    "//ios/chrome/test/base",
+    "//ios/web",
+    "//ios/web:test_support",
+    "//testing/gtest",
+    "//third_party/ocmock",
+    "//ui/base:test_support",
+  ]
+}
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "form_input_egtest.mm",
+  ]
+  deps = [
+    "//base",
+    "//base/test:test_support",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/autofill",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/testing:ios_test_support",
+    "//ios/testing/earl_grey:earl_grey_support",
+    "//ios/third_party/earl_grey",
+    "//ios/web:earl_grey_test_support",
+    "//ios/web:test_support",
+  ]
+}
diff --git a/ios/chrome/browser/browser_state/BUILD.gn b/ios/chrome/browser/browser_state/BUILD.gn
index ff04e6ea..f4cb360a 100644
--- a/ios/chrome/browser/browser_state/BUILD.gn
+++ b/ios/chrome/browser/browser_state/BUILD.gn
@@ -93,6 +93,7 @@
     "//ios/chrome/browser/reading_list",
     "//ios/chrome/browser/search_engines",
     "//ios/chrome/browser/services/gcm",
+    "//ios/chrome/browser/sessions:sessions_internal",
     "//ios/chrome/browser/signin",
     "//ios/chrome/browser/suggestions",
     "//ios/chrome/browser/sync",
diff --git a/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm b/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm
index 441bd71..68a3cc3d 100644
--- a/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm
+++ b/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm
@@ -28,6 +28,7 @@
 #include "ios/chrome/browser/reading_list/reading_list_model_factory.h"
 #include "ios/chrome/browser/search_engines/template_url_service_factory.h"
 #include "ios/chrome/browser/services/gcm/ios_chrome_gcm_profile_service_factory.h"
+#include "ios/chrome/browser/sessions/tab_restore_service_delegate_impl_ios_factory.h"
 #include "ios/chrome/browser/signin/about_signin_internals_factory.h"
 #include "ios/chrome/browser/signin/account_consistency_service_factory.h"
 #include "ios/chrome/browser/signin/account_fetcher_service_factory.h"
@@ -98,5 +99,6 @@
   SigninClientFactory::GetInstance();
   suggestions::SuggestionsServiceFactory::GetInstance();
   SyncSetupServiceFactory::GetInstance();
+  TabRestoreServiceDelegateImplIOSFactory::GetInstance();
   TranslateAcceptLanguagesFactory::GetInstance();
 }
diff --git a/ios/chrome/browser/browsing_data/BUILD.gn b/ios/chrome/browser/browsing_data/BUILD.gn
index d8aaa48..6985aa83 100644
--- a/ios/chrome/browser/browsing_data/BUILD.gn
+++ b/ios/chrome/browser/browsing_data/BUILD.gn
@@ -53,17 +53,48 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
+    "browsing_data_removal_controller_unittest.mm",
     "cache_counter_unittest.cc",
   ]
   deps = [
     ":browsing_data",
+    ":browsing_data_internal",
     "//base",
+    "//base/test:test_support",
     "//components/browsing_data/core",
     "//components/prefs",
     "//components/prefs:test_support",
+    "//ios/chrome/browser/browser_state:test_support",
     "//ios/web",
     "//ios/web:test_support",
     "//net",
     "//testing/gtest",
+    "//third_party/ocmock",
   ]
 }
+
+source_set("browsing_data_internal") {
+  sources = [
+    "browsing_data_removal_controller.h",
+    "browsing_data_removal_controller.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/browsing_data/core",
+    "//components/open_from_clipboard",
+    "//components/signin/ios/browser",
+    "//ios/chrome/browser:browser_internal",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/browsing_data",
+    "//ios/chrome/browser/native_app_launcher:native_app_launcher_internal",
+    "//ios/chrome/browser/sessions:sessions_internal",
+    "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/snapshots",
+    "//ios/chrome/browser/ui:ui_internal",
+    "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser/native_app_launcher",
+    "//ios/web",
+    "//net",
+  ]
+  libs = [ "WebKit.framework" ]
+}
diff --git a/ios/chrome/browser/context_menu/BUILD.gn b/ios/chrome/browser/context_menu/BUILD.gn
new file mode 100644
index 0000000..aa2ccd23
--- /dev/null
+++ b/ios/chrome/browser/context_menu/BUILD.gn
@@ -0,0 +1,26 @@
+# 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.
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "context_menu_egtest.mm",
+  ]
+  deps = [
+    "//base",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/testing:ios_test_support",
+    "//ios/third_party/earl_grey",
+    "//ios/web:earl_grey_test_support",
+    "//ios/web:test_support",
+    "//url",
+  ]
+  libs = [
+    "UIKit.framework",
+    "XCTest.framework",
+  ]
+}
diff --git a/ios/chrome/browser/crash_report/BUILD.gn b/ios/chrome/browser/crash_report/BUILD.gn
index 68085844..9b69033 100644
--- a/ios/chrome/browser/crash_report/BUILD.gn
+++ b/ios/chrome/browser/crash_report/BUILD.gn
@@ -29,3 +29,52 @@
     "//ios/web",
   ]
 }
+
+source_set("crash_report_internal") {
+  sources = [
+    "crash_report_helper.h",
+    "crash_report_helper.mm",
+    "crash_restore_helper.h",
+    "crash_restore_helper.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/infobars/core",
+    "//components/sessions",
+    "//components/strings",
+    "//components/upload_list",
+    "//ios/chrome/app/theme",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/crash_report",
+    "//ios/chrome/browser/sessions",
+    "//ios/chrome/browser/sessions:sessions_internal",
+    "//ios/chrome/browser/tabs",
+    "//ios/web",
+    "//net",
+    "//ui/base",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "breakpad_helper_unittest.mm",
+    "crash_restore_helper_unittest.mm",
+  ]
+  deps = [
+    ":crash_report_internal",
+    "//base",
+    "//breakpad:client",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/crash_report",
+    "//ios/chrome/browser/sessions:sessions_internal",
+    "//ios/chrome/test/base",
+    "//ios/chrome/test/ocmock",
+    "//ios/web:test_support",
+    "//testing/gmock",
+    "//testing/gtest",
+    "//third_party/ocmock",
+  ]
+}
diff --git a/ios/chrome/browser/device_sharing/BUILD.gn b/ios/chrome/browser/device_sharing/BUILD.gn
index ef719c3f..ab5c388b 100644
--- a/ios/chrome/browser/device_sharing/BUILD.gn
+++ b/ios/chrome/browser/device_sharing/BUILD.gn
@@ -36,3 +36,22 @@
     "//url",
   ]
 }
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "handoff_manager_egtest.mm",
+  ]
+  deps = [
+    "//components/handoff",
+    "//ios/chrome/browser/device_sharing",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/third_party/earl_grey",
+    "//ios/web:test_support",
+    "//net",
+    "//url",
+  ]
+  libs = [ "XCTest.framework" ]
+}
diff --git a/ios/chrome/browser/geolocation/BUILD.gn b/ios/chrome/browser/geolocation/BUILD.gn
index d386fa59..57c5fa44f 100644
--- a/ios/chrome/browser/geolocation/BUILD.gn
+++ b/ios/chrome/browser/geolocation/BUILD.gn
@@ -64,3 +64,26 @@
     "//third_party/ocmock",
   ]
 }
+
+source_set("geolocation_internal") {
+  sources = [
+    "omnibox_geolocation_controller+Testing.h",
+    "omnibox_geolocation_controller.h",
+    "omnibox_geolocation_controller.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/google/core/browser",
+    "//components/version_info",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/geolocation",
+    "//ios/chrome/browser/tabs",
+    "//ios/web",
+    "//ui/base",
+    "//url",
+  ]
+  libs = [
+    "CoreLocation.framework",
+    "UIKit.framework",
+  ]
+}
diff --git a/ios/chrome/browser/metrics/BUILD.gn b/ios/chrome/browser/metrics/BUILD.gn
index e9a7abf..a103be6 100644
--- a/ios/chrome/browser/metrics/BUILD.gn
+++ b/ios/chrome/browser/metrics/BUILD.gn
@@ -79,3 +79,80 @@
     "//testing/gtest",
   ]
 }
+
+source_set("metrics_internal") {
+  sources = [
+    "first_user_action_recorder.cc",
+    "first_user_action_recorder.h",
+    "new_tab_page_uma.h",
+    "new_tab_page_uma.mm",
+    "size_class_recorder.h",
+    "size_class_recorder.mm",
+    "size_class_recorder_private.h",
+    "tab_usage_recorder.h",
+    "tab_usage_recorder.mm",
+    "tab_usage_recorder_delegate.h",
+  ]
+  deps = [
+    "//base",
+    "//components/google/core/browser",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/metrics",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui:browser_list",
+    "//ios/web",
+    "//ui/base:base",
+    "//url",
+  ]
+  libs = [ "UIKit.framework" ]
+}
+
+source_set("unit_tests_internal") {
+  testonly = true
+  sources = [
+    "first_user_action_recorder_unittest.cc",
+    "size_class_recorder_unittest.mm",
+    "tab_usage_recorder_unittest.mm",
+  ]
+  deps = [
+    ":metrics_internal",
+    "//base",
+    "//base/test:test_support",
+    "//ios/chrome/browser/metrics",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui",
+    "//ios/testing:ocmock_support",
+    "//ios/web",
+    "//ios/web:test_support",
+    "//testing/gtest",
+    "//third_party/ocmock",
+  ]
+}
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "tab_usage_recorder_egtest.mm",
+  ]
+  deps = [
+    "//base",
+    "//base/test:test_support",
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/metrics:metrics_internal",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/settings",
+    "//ios/chrome/browser/ui/toolbar",
+    "//ios/chrome/browser/ui/tools_menu",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/testing:ios_test_support",
+    "//ios/third_party/earl_grey",
+    "//ios/web:test_support",
+    "//ui/base",
+  ]
+  libs = [ "XCTest.framework" ]
+}
diff --git a/ios/chrome/browser/native_app_launcher/BUILD.gn b/ios/chrome/browser/native_app_launcher/BUILD.gn
index 0bac471d..a4de503 100644
--- a/ios/chrome/browser/native_app_launcher/BUILD.gn
+++ b/ios/chrome/browser/native_app_launcher/BUILD.gn
@@ -50,3 +50,54 @@
     "//url",
   ]
 }
+
+source_set("native_app_launcher_internal") {
+  sources = [
+    "native_app_navigation_controller.h",
+    "native_app_navigation_controller.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/infobars/core",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/infobars",
+    "//ios/chrome/browser/native_app_launcher",
+    "//ios/chrome/browser/net",
+    "//ios/chrome/browser/tabs",
+    "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser/native_app_launcher",
+    "//ios/public/provider/chrome/browser/signin",
+    "//ios/public/provider/chrome/browser/ui",
+    "//ios/web",
+    "//net",
+    "//ui/base",
+    "//url",
+  ]
+  libs = [ "StoreKit.framework" ]
+}
+
+source_set("unit_tests_internal") {
+  testonly = true
+  sources = [
+    "native_app_navigation_controller_unittest.mm",
+  ]
+  deps = [
+    ":native_app_launcher_internal",
+    "//base",
+    "//base/test:test_support",
+    "//components/infobars/core",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/native_app_launcher",
+    "//ios/chrome/test:test_support",
+    "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser:test_support",
+    "//ios/public/provider/chrome/browser/native_app_launcher:test_support",
+    "//ios/public/provider/chrome/browser/signin:test_support",
+    "//ios/web",
+    "//ios/web:test_support",
+    "//net:test_support",
+    "//testing/gmock",
+    "//testing/gtest",
+    "//url",
+  ]
+}
diff --git a/ios/chrome/browser/net/BUILD.gn b/ios/chrome/browser/net/BUILD.gn
index ad7fb27..b628ccce 100644
--- a/ios/chrome/browser/net/BUILD.gn
+++ b/ios/chrome/browser/net/BUILD.gn
@@ -72,3 +72,19 @@
     "//testing/gtest",
   ]
 }
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "cookies_egtest.mm",
+  ]
+  deps = [
+    "//base",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/third_party/earl_grey",
+    "//ios/web:test_support",
+    "//url",
+  ]
+  libs = [ "XCTest.framework" ]
+}
diff --git a/ios/chrome/browser/passwords/BUILD.gn b/ios/chrome/browser/passwords/BUILD.gn
index 8aea29c..d0bd285 100644
--- a/ios/chrome/browser/passwords/BUILD.gn
+++ b/ios/chrome/browser/passwords/BUILD.gn
@@ -139,3 +139,27 @@
     "resources/password_controller.js",
   ]
 }
+
+source_set("passwords_internal") {
+  sources = [
+    "password_generation_prompt_view.h",
+    "password_generation_prompt_view.mm",
+    "password_generation_prompt_view_controller.h",
+    "password_generation_prompt_view_controller.mm",
+    "passwords_ui_delegate_impl.h",
+    "passwords_ui_delegate_impl.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/app/theme",
+    "//ios/chrome/browser/passwords",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/common",
+    "//ios/third_party/material_components_ios",
+    "//ios/third_party/material_roboto_font_loader_ios",
+    "//ui/base",
+  ]
+  libs = [ "UIKit.framework" ]
+}
diff --git a/ios/chrome/browser/payments/BUILD.gn b/ios/chrome/browser/payments/BUILD.gn
index 3055b88c..bbfbeb1f 100644
--- a/ios/chrome/browser/payments/BUILD.gn
+++ b/ios/chrome/browser/payments/BUILD.gn
@@ -9,3 +9,77 @@
     "resources/payment_request_manager.js",
   ]
 }
+
+source_set("payments") {
+  sources = [
+    "js_payment_request_manager.h",
+    "js_payment_request_manager.mm",
+    "payment_items_display_coordinator.h",
+    "payment_items_display_coordinator.mm",
+    "payment_items_display_view_controller.h",
+    "payment_items_display_view_controller.mm",
+    "payment_method_selection_coordinator.h",
+    "payment_method_selection_coordinator.mm",
+    "payment_method_selection_view_controller.h",
+    "payment_method_selection_view_controller.mm",
+    "payment_request_coordinator.h",
+    "payment_request_coordinator.mm",
+    "payment_request_manager.h",
+    "payment_request_manager.mm",
+    "payment_request_utils.h",
+    "payment_request_utils.mm",
+    "payment_request_view_controller.h",
+    "payment_request_view_controller.mm",
+    "payment_request_web_state_observer.h",
+    "payment_request_web_state_observer.mm",
+    "shipping_address_selection_coordinator.h",
+    "shipping_address_selection_coordinator.mm",
+    "shipping_address_selection_view_controller.h",
+    "shipping_address_selection_view_controller.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/autofill/core/browser",
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/autofill",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/payments:injected_js",
+    "//ios/chrome/browser/payments/cells",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/collection_view",
+    "//ios/chrome/browser/ui/collection_view/cells",
+    "//ios/chrome/browser/ui/colors",
+    "//ios/chrome/browser/ui/icons",
+    "//ios/third_party/material_components_ios",
+    "//ios/third_party/material_roboto_font_loader_ios",
+    "//ios/web",
+    "//ui/base",
+  ]
+  libs = [ "UIKit.framework" ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "payment_items_display_coordinator_unittest.mm",
+    "payment_items_display_view_controller_unittest.mm",
+    "shipping_address_selection_coordinator_unittest.mm",
+    "shipping_address_selection_view_controller_unittest.mm",
+  ]
+  deps = [
+    ":payments",
+    "//base",
+    "//base/test:test_support",
+    "//components/autofill/core/browser",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui/collection_view:test_support",
+    "//ios/chrome/browser/ui/collection_view/cells",
+    "//ios/chrome/browser/ui/collection_view/cells:test_support",
+    "//ios/chrome/test:test_support",
+    "//ios/third_party/material_components_ios",
+    "//ios/web",
+    "//testing/gtest",
+  ]
+}
diff --git a/ios/chrome/browser/payments/cells/BUILD.gn b/ios/chrome/browser/payments/cells/BUILD.gn
new file mode 100644
index 0000000..1671ba3
--- /dev/null
+++ b/ios/chrome/browser/payments/cells/BUILD.gn
@@ -0,0 +1,43 @@
+# 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.
+
+source_set("cells") {
+  sources = [
+    "order_summary_line_item.h",
+    "order_summary_line_item.mm",
+    "order_summary_total_item.h",
+    "order_summary_total_item.mm",
+    "page_info_item.h",
+    "page_info_item.mm",
+    "payment_method_item.h",
+    "payment_method_item.mm",
+    "shipping_address_item.h",
+    "shipping_address_item.mm",
+  ]
+
+  deps = [
+    "//ios/chrome/browser/ui/collection_view/cells",
+    "//ios/third_party/material_components_ios",
+    "//ios/third_party/material_roboto_font_loader_ios",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "page_info_item_unittest.mm",
+    "payment_method_item_unittest.mm",
+  ]
+
+  deps = [
+    ":cells",
+    "//ios/chrome/browser/ui/collection_view/cells:test_support",
+    "//ios/third_party/material_components_ios",
+    "//testing/gtest",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+}
diff --git a/ios/chrome/browser/sessions/BUILD.gn b/ios/chrome/browser/sessions/BUILD.gn
index a64f3a8..5e7154f5 100644
--- a/ios/chrome/browser/sessions/BUILD.gn
+++ b/ios/chrome/browser/sessions/BUILD.gn
@@ -24,3 +24,76 @@
     "//url",
   ]
 }
+
+source_set("sessions_internal") {
+  sources = [
+    "NSCoder+Compatibility.h",
+    "NSCoder+Compatibility.mm",
+    "session_service.h",
+    "session_service.mm",
+    "session_util.h",
+    "session_util.mm",
+    "session_window.h",
+    "session_window.mm",
+    "tab_restore_service_delegate_impl_ios.h",
+    "tab_restore_service_delegate_impl_ios.mm",
+    "tab_restore_service_delegate_impl_ios_factory.h",
+    "tab_restore_service_delegate_impl_ios_factory.mm",
+    "tab_restore_service_delegate_provider_impl.h",
+    "tab_restore_service_delegate_provider_impl.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/keyed_service/core",
+    "//components/keyed_service/ios",
+    "//components/sessions",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui:browser_list",
+    "//ios/public/provider/chrome/browser/sessions",
+    "//ios/web",
+    "//net",
+  ]
+  libs = [ "UIKit.framework" ]
+}
+
+source_set("test_support") {
+  testonly = true
+  sources = [
+    "test_session_service.h",
+    "test_session_service.mm",
+  ]
+  deps = [
+    ":sessions_internal",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "session_service_unittest.mm",
+    "session_window_unittest.mm",
+  ]
+  deps = [
+    ":resources_unit_tests",
+    ":sessions_internal",
+    "//base",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/web",
+    "//ios/web:test_support",
+    "//testing/gtest",
+    "//third_party/ocmock",
+  ]
+}
+
+bundle_data("resources_unit_tests") {
+  visibility = [ ":unit_tests" ]
+  testonly = true
+  sources = [
+    "//ios/chrome/test/data/sessions/corrupted.plist",
+  ]
+  outputs = [
+    "{{bundle_resources_dir}}/ios/chrome/test/data/sessions/{{source_file_part}}",
+  ]
+}
diff --git a/ios/chrome/browser/signin/BUILD.gn b/ios/chrome/browser/signin/BUILD.gn
index c31264b..8e7b805f 100644
--- a/ios/chrome/browser/signin/BUILD.gn
+++ b/ios/chrome/browser/signin/BUILD.gn
@@ -134,3 +134,16 @@
     "//third_party/ocmock",
   ]
 }
+
+source_set("signin_internal") {
+  sources = [
+    "signin_capability.cc",
+    "signin_capability.h",
+  ]
+  deps = [
+    "//base",
+    "//components/signin/core/browser",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/signin",
+  ]
+}
diff --git a/ios/chrome/browser/snapshots/BUILD.gn b/ios/chrome/browser/snapshots/BUILD.gn
index cfda2e7..3a7d0968 100644
--- a/ios/chrome/browser/snapshots/BUILD.gn
+++ b/ios/chrome/browser/snapshots/BUILD.gn
@@ -41,3 +41,19 @@
     "//testing/gtest",
   ]
 }
+
+source_set("snapshots_internal") {
+  sources = [
+    "snapshot_overlay_provider.h",
+    "web_controller_snapshot_helper.h",
+    "web_controller_snapshot_helper.mm",
+  ]
+  deps = [
+    "//base",
+    "//ios/chrome/browser/snapshots",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui",
+    "//ios/web",
+  ]
+  libs = [ "UIKit.framework" ]
+}
diff --git a/ios/chrome/browser/tabs/BUILD.gn b/ios/chrome/browser/tabs/BUILD.gn
new file mode 100644
index 0000000..be04f826
--- /dev/null
+++ b/ios/chrome/browser/tabs/BUILD.gn
@@ -0,0 +1,144 @@
+# 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.
+
+source_set("tabs") {
+  sources = [
+    "tab.h",
+    "tab_delegate.h",
+    "tab_dialog_delegate.h",
+    "tab_model.h",
+    "tab_model_observer.h",
+    "tab_private.h",
+    "tab_snapshotting_delegate.h",
+  ]
+  deps = [
+    "//components/signin/ios/browser",
+    "//ios/net",
+    "//ios/web",
+    "//ui/base",
+  ]
+  libs = [ "UIKit.framework" ]
+}
+
+source_set("tabs_internal") {
+  sources = [
+    "tab.mm",
+    "tab_model.mm",
+    "tab_model_order_controller.h",
+    "tab_model_order_controller.mm",
+    "tab_model_synced_window_delegate.h",
+    "tab_model_synced_window_delegate.mm",
+    "tab_model_synced_window_delegate_getter.h",
+    "tab_model_synced_window_delegate_getter.mm",
+  ]
+  deps = [
+    ":tabs",
+    "//base",
+    "//components/content_settings/core/browser",
+    "//components/favicon/core",
+    "//components/favicon/ios",
+    "//components/google/core/browser",
+    "//components/history/core/browser",
+    "//components/history/ios/browser",
+    "//components/infobars/core",
+    "//components/keyed_service/core",
+    "//components/metrics_services_manager",
+    "//components/navigation_metrics",
+    "//components/prefs",
+    "//components/search_engines",
+    "//components/sessions",
+    "//components/signin/core/browser",
+    "//components/signin/ios/browser",
+    "//components/strings",
+    "//components/sync_sessions",
+    "//components/url_formatter",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/autofill",
+    "//ios/chrome/browser/autofill:autofill_internal",
+    "//ios/chrome/browser/bookmarks",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/content_settings",
+    "//ios/chrome/browser/favicon",
+    "//ios/chrome/browser/find_in_page",
+    "//ios/chrome/browser/geolocation:geolocation_internal",
+    "//ios/chrome/browser/history",
+    "//ios/chrome/browser/infobars",
+    "//ios/chrome/browser/metrics",
+    "//ios/chrome/browser/metrics:metrics_internal",
+    "//ios/chrome/browser/native_app_launcher:native_app_launcher_internal",
+    "//ios/chrome/browser/net",
+    "//ios/chrome/browser/passwords",
+    "//ios/chrome/browser/passwords:passwords_internal",
+    "//ios/chrome/browser/search_engines",
+    "//ios/chrome/browser/sessions",
+    "//ios/chrome/browser/sessions:sessions_internal",
+    "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/signin:signin_internal",
+    "//ios/chrome/browser/snapshots",
+    "//ios/chrome/browser/snapshots:snapshots_internal",
+    "//ios/chrome/browser/ssl",
+    "//ios/chrome/browser/sync",
+    "//ios/chrome/browser/translate",
+    "//ios/chrome/browser/u2f",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui:browser_list",
+    "//ios/chrome/browser/ui:ui_internal",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/downloads",
+    "//ios/chrome/browser/ui/overscroll_actions",
+    "//ios/chrome/browser/ui/reader_mode",
+    "//ios/chrome/browser/ui/sad_tab",
+    "//ios/chrome/browser/ui/toolbar",
+    "//ios/chrome/browser/web",
+    "//ios/chrome/browser/web:web_internal",
+    "//ios/net",
+    "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser/native_app_launcher",
+    "//ios/web",
+    "//net",
+    "//ui/base",
+    "//url",
+  ]
+  libs = [
+    "CoreLocation.framework",
+    "UIKit.framework",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "tab_model_order_controller_unittest.mm",
+    "tab_model_unittest.mm",
+    "tab_unittest.mm",
+  ]
+  deps = [
+    ":tabs",
+    ":tabs_internal",
+    "//base",
+    "//components/bookmarks/test",
+    "//components/history/core/browser",
+    "//components/keyed_service/core",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/bookmarks",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/history",
+    "//ios/chrome/browser/infobars",
+    "//ios/chrome/browser/sessions:sessions_internal",
+    "//ios/chrome/browser/sessions:test_support",
+    "//ios/chrome/browser/ui:ui_internal",
+    "//ios/chrome/browser/web:web_internal",
+    "//ios/chrome/test:test_support",
+    "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser:test_support",
+    "//ios/public/provider/chrome/browser/native_app_launcher:test_support",
+    "//ios/testing:ocmock_support",
+    "//ios/web",
+    "//ios/web:test_support",
+    "//net",
+    "//testing/gtest",
+    "//third_party/ocmock",
+  ]
+}
diff --git a/ios/chrome/browser/test/BUILD.gn b/ios/chrome/browser/test/BUILD.gn
new file mode 100644
index 0000000..f80eac2
--- /dev/null
+++ b/ios/chrome/browser/test/BUILD.gn
@@ -0,0 +1,34 @@
+# 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.
+
+import("//ios/public/provider/chrome/browser/build_config.gni")
+
+source_set("perf_test_support") {
+  testonly = true
+  sources = [
+    "perf_test_with_bvc_ios.h",
+    "perf_test_with_bvc_ios.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/bookmarks/test",
+    "//ios/chrome/browser/autocomplete",
+    "//ios/chrome/browser/bookmarks",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/search_engines",
+    "//ios/chrome/browser/sessions:sessions_internal",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui:ui_internal",
+    "//ios/chrome/browser/web:web_internal",
+    "//ios/chrome/test:test_support",
+    "//ios/chrome/test/base:perf_test_support",
+    "//ios/public/provider/chrome/browser",
+    "//ios/web:test_support",
+
+    # Perf tests can run with any provider, but the resulting numbers will only
+    # be meaningful if ChromeBrowserProviderImpl is used.
+    ios_provider_target,
+  ]
+  libs = [ "UIKit.framework" ]
+}
diff --git a/ios/chrome/browser/translate/BUILD.gn b/ios/chrome/browser/translate/BUILD.gn
index c2eb31f..46432c0 100644
--- a/ios/chrome/browser/translate/BUILD.gn
+++ b/ios/chrome/browser/translate/BUILD.gn
@@ -49,13 +49,45 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
+    "js_language_detection_manager_unittest.mm",
     "translate_service_ios_unittest.cc",
   ]
   deps = [
     ":translate",
+    "//base",
+    "//base/test:test_support",
+    "//components/translate/ios/browser",
     "//ios/chrome/browser",
+    "//ios/chrome/browser/web:test_support",
+    "//ios/chrome/common",
     "//ios/public/provider/chrome/browser:test_support",
+    "//ios/web",
+    "//ios/web:test_support",
     "//testing/gtest",
     "//url",
   ]
 }
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "translate_egtest.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/strings",
+    "//components/translate/core/browser",
+    "//components/translate/core/common",
+    "//components/translate/ios/browser",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/translate",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/testing:ios_test_support",
+    "//ios/third_party/earl_grey",
+    "//ios/web:test_support",
+    "//net",
+    "//ui/base",
+  ]
+  libs = [ "XCTest.framework" ]
+}
diff --git a/ios/chrome/browser/ui/BUILD.gn b/ios/chrome/browser/ui/BUILD.gn
index 0a78411..91f2f65 100644
--- a/ios/chrome/browser/ui/BUILD.gn
+++ b/ios/chrome/browser/ui/BUILD.gn
@@ -81,17 +81,61 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
+    "browser_container_view_unittest.mm",
+    "browser_view_controller_unittest.mm",
+    "chrome_web_view_factory_unittest.mm",
+    "file_locations_unittest.mm",
+    "fullscreen_controller_unittest.mm",
+    "key_commands_provider_unittest.mm",
     "native_content_controller_unittest.mm",
     "network_activity_indicator_manager_unittest.mm",
+    "open_in_controller_unittest.mm",
+    "open_in_toolbar_unittest.mm",
+    "page_not_available_controller_unittest.mm",
+    "preload_controller_unittest.mm",
     "ui_util_unittest.mm",
     "uikit_ui_util_unittest.mm",
   ]
   deps = [
     ":native_content_controller_test_xib",
+    ":resources_unit_tests",
+    ":test_support",
     ":ui",
+    ":ui_internal",
     "//base",
+    "//base/test:test_support",
+    "//components/bookmarks/test",
+    "//components/prefs:test_support",
+    "//components/search_engines",
+    "//components/sessions",
+    "//components/toolbar:test_support",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/bookmarks",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/find_in_page",
+    "//ios/chrome/browser/search_engines",
+    "//ios/chrome/browser/sessions",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/activity_services",
+    "//ios/chrome/browser/ui/alert_coordinator",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/ntp:ntp_internal",
+    "//ios/chrome/browser/ui/toolbar",
+    "//ios/chrome/browser/ui/toolbar:test_support",
+    "//ios/chrome/browser/web:web_internal",
+    "//ios/chrome/test:test_support",
+    "//ios/testing:ocmock_support",
+    "//ios/web",
+    "//ios/web:test_support",
+    "//net",
+    "//net:test_support",
+    "//testing/gmock",
     "//testing/gtest",
     "//third_party/ocmock",
+    "//ui/base",
     "//url",
   ]
 }
@@ -174,3 +218,251 @@
     "{{bundle_resources_dir}}/{{source_file_part}}",
   ]
 }
+
+source_set("ui_internal") {
+  sources = [
+    "browser_container_view.h",
+    "browser_container_view.mm",
+    "browser_view_controller.h",
+    "browser_view_controller.mm",
+    "browser_view_controller_dependency_factory.h",
+    "browser_view_controller_dependency_factory.mm",
+    "chrome_web_view_factory.h",
+    "chrome_web_view_factory.mm",
+    "external_file_controller.h",
+    "external_file_controller.mm",
+    "external_file_remover.h",
+    "external_file_remover.mm",
+    "fade_truncated_label.h",
+    "fade_truncated_label.mm",
+    "fullscreen_controller.h",
+    "fullscreen_controller.mm",
+    "key_commands_provider.h",
+    "key_commands_provider.mm",
+    "open_in_controller.h",
+    "open_in_controller.mm",
+    "open_in_controller_testing.h",
+    "open_in_toolbar.h",
+    "open_in_toolbar.mm",
+    "page_not_available_controller.h",
+    "page_not_available_controller.mm",
+    "preload_controller.h",
+    "preload_controller.mm",
+    "preload_controller_delegate.h",
+    "prerender_delegate.h",
+  ]
+  deps = [
+    ":browser_list",
+    "//base",
+    "//base:i18n",
+    "//components/bookmarks/browser",
+    "//components/infobars/core",
+    "//components/prefs",
+    "//components/reading_list/core",
+    "//components/reading_list/ios",
+    "//components/search_engines",
+    "//components/sessions",
+    "//components/strings",
+    "//components/toolbar",
+    "//components/url_formatter",
+    "//ios/chrome/app:tests_hook",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/bookmarks",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/favicon",
+    "//ios/chrome/browser/find_in_page",
+    "//ios/chrome/browser/first_run",
+    "//ios/chrome/browser/geolocation:geolocation_internal",
+    "//ios/chrome/browser/infobars",
+    "//ios/chrome/browser/metrics:metrics_internal",
+    "//ios/chrome/browser/native_app_launcher:native_app_launcher_internal",
+    "//ios/chrome/browser/net",
+    "//ios/chrome/browser/passwords",
+    "//ios/chrome/browser/payments",
+    "//ios/chrome/browser/prefs",
+    "//ios/chrome/browser/reading_list",
+    "//ios/chrome/browser/search_engines",
+    "//ios/chrome/browser/sessions",
+    "//ios/chrome/browser/sessions:sessions_internal",
+    "//ios/chrome/browser/snapshots",
+    "//ios/chrome/browser/snapshots:snapshots_internal",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui:resources",
+    "//ios/chrome/browser/ui/activity_services",
+    "//ios/chrome/browser/ui/alert_coordinator",
+    "//ios/chrome/browser/ui/authentication",
+    "//ios/chrome/browser/ui/bookmarks",
+    "//ios/chrome/browser/ui/colors",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/context_menu",
+    "//ios/chrome/browser/ui/contextual_search",
+    "//ios/chrome/browser/ui/dialogs:dialogs_internal",
+    "//ios/chrome/browser/ui/elements:elements_internal",
+    "//ios/chrome/browser/ui/find_bar",
+    "//ios/chrome/browser/ui/first_run",
+    "//ios/chrome/browser/ui/history",
+    "//ios/chrome/browser/ui/keyboard",
+    "//ios/chrome/browser/ui/no_tabs",
+    "//ios/chrome/browser/ui/ntp",
+    "//ios/chrome/browser/ui/ntp:ntp_internal",
+    "//ios/chrome/browser/ui/ntp/recent_tabs",
+    "//ios/chrome/browser/ui/omnibox:omnibox_internal",
+    "//ios/chrome/browser/ui/overscroll_actions",
+    "//ios/chrome/browser/ui/print",
+    "//ios/chrome/browser/ui/qr_scanner",
+    "//ios/chrome/browser/ui/reading_list",
+    "//ios/chrome/browser/ui/stack_view",
+    "//ios/chrome/browser/ui/static_content",
+    "//ios/chrome/browser/ui/sync",
+    "//ios/chrome/browser/ui/tab_switcher",
+    "//ios/chrome/browser/ui/tabs",
+    "//ios/chrome/browser/ui/tools_menu",
+    "//ios/chrome/browser/ui/voice",
+    "//ios/chrome/browser/upgrade",
+    "//ios/chrome/browser/web:web_internal",
+    "//ios/chrome/common",
+    "//ios/net",
+    "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser/ui",
+    "//ios/public/provider/chrome/browser/voice",
+    "//ios/third_party/material_components_ios",
+    "//ios/web",
+    "//ios/web/public/image_fetcher",
+    "//net",
+    "//third_party/google_toolbox_for_mac",
+    "//ui/base",
+    "//ui/gfx",
+    "//url",
+  ]
+  public_deps = [
+    "//ios/chrome/browser/ui/side_swipe",
+    "//ios/chrome/browser/ui/toolbar",
+  ]
+  allow_circular_includes_from = [
+    "//ios/chrome/browser/ui/tabs",
+    "//ios/chrome/browser/ui/tab_switcher",
+    "//ios/chrome/browser/ui/toolbar",
+    "//ios/chrome/browser/ui/overscroll_actions",
+    "//ios/chrome/browser/snapshots:snapshots_internal",
+    "//ios/chrome/browser/web:web_internal",
+    "//ios/chrome/browser/ui/ntp:ntp_internal",
+    "//ios/chrome/browser/ui/stack_view",
+  ]
+  libs = [
+    "AssetsLibrary.framework",
+    "MessageUI.framework",
+    "MobileCoreServices.framework",
+    "PassKit.framework",
+    "Photos.framework",
+    "QuartzCore.framework",
+    "StoreKit.framework",
+    "UIKit.framework",
+    "WebKit.framework",
+  ]
+}
+
+source_set("browser_list") {
+  sources = [
+    "browser_ios.h",
+    "browser_list_ios.h",
+    "browser_list_ios.mm",
+  ]
+  deps = [
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/tabs",
+  ]
+}
+
+source_set("test_support") {
+  testonly = true
+  sources = [
+    "browser_view_controller_testing.h",
+    "browser_view_controller_testing.mm",
+  ]
+  deps = [
+    ":ui_internal",
+    "//ios/chrome/browser/ui/toolbar",
+    "//ios/chrome/browser/ui/toolbar:test_support",
+  ]
+}
+
+bundle_data("resources_unit_tests") {
+  visibility = [ ":unit_tests" ]
+  testonly = true
+  sources = [
+    "//ios/chrome/test/data/testbadpass.pkpass",
+    "//ios/chrome/test/data/testpass.pkpass",
+  ]
+  outputs = [
+    "{{bundle_resources_dir}}/ios/chrome/test/data/{{source_file_part}}",
+  ]
+}
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "browser_view_controller_egtest.mm",
+    "error_page_egtest.mm",
+    "fullscreen_egtest.mm",
+    "keyboard_commands_egtest.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui:ui_internal",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/ntp:ntp_internal",
+    "//ios/chrome/browser/ui/toolbar",
+    "//ios/chrome/browser/ui/tools_menu",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/testing:ios_test_support",
+    "//ios/third_party/earl_grey",
+    "//ios/web:earl_grey_test_support",
+    "//ios/web:test_support",
+    "//ui/base",
+    "//url",
+  ]
+  libs = [
+    "UIKit.framework",
+    "WebKit.framework",
+    "XCTest.framework",
+  ]
+}
+
+source_set("perf_tests") {
+  testonly = true
+  sources = [
+    "omnibox_perftest.mm",
+  ]
+  deps = [
+    "//base",
+    "//base/test:test_support",
+    "//components/toolbar:test_support",
+    "//ios/chrome/browser/autocomplete",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/search_engines",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/tabs:tabs_internal",
+    "//ios/chrome/browser/ui/omnibox:omnibox_internal",
+    "//ios/chrome/browser/ui/toolbar",
+    "//ios/chrome/test/base:perf_test_support",
+    "//testing/gtest",
+    "//third_party/ocmock",
+    "//ui/base:test_support",
+  ]
+  libs = [ "UIKit.framework" ]
+}
+
+# Clean skeleton targets
+source_set("ui_clean_skeleton") {
+  sources = [
+    "ui_types.h",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+}
diff --git a/ios/chrome/browser/ui/actions/BUILD.gn b/ios/chrome/browser/ui/actions/BUILD.gn
new file mode 100644
index 0000000..361b2424
--- /dev/null
+++ b/ios/chrome/browser/ui/actions/BUILD.gn
@@ -0,0 +1,13 @@
+# 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.
+
+source_set("actions") {
+  sources = [
+    "settings_actions.h",
+    "tab_grid_actions.h",
+    "tools_menu_actions.h",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+}
diff --git a/ios/chrome/browser/ui/activity_services/BUILD.gn b/ios/chrome/browser/ui/activity_services/BUILD.gn
index bbc602f..53b8977 100644
--- a/ios/chrome/browser/ui/activity_services/BUILD.gn
+++ b/ios/chrome/browser/ui/activity_services/BUILD.gn
@@ -26,3 +26,80 @@
     "{{bundle_resources_dir}}/{{source_file_part}}",
   ]
 }
+
+source_set("activity_services") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [
+    "activity_service_controller.h",
+    "activity_service_controller.mm",
+    "activity_type_util.h",
+    "activity_type_util.mm",
+    "appex_constants.h",
+    "appex_constants.mm",
+    "chrome_activity_item_source.h",
+    "chrome_activity_item_source.mm",
+    "print_activity.h",
+    "print_activity.mm",
+    "reading_list_activity.h",
+    "reading_list_activity.mm",
+    "share_protocol.h",
+    "share_to_data.h",
+    "share_to_data.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/reading_list/core",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/activity_services:assets",
+    "//ios/chrome/browser/ui/activity_services:resources",
+    "//ios/chrome/browser/ui/commands",
+    "//net",
+    "//ui/base",
+    "//url",
+  ]
+  libs = [
+    "MobileCoreServices.framework",
+    "UIKit.framework",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "activity_service_controller_unittest.mm",
+    "activity_type_util_unittest.mm",
+  ]
+  deps = [
+    ":activity_services",
+    "//base",
+    "//base/test:test_support",
+    "//components/reading_list/core",
+    "//ios/chrome/app/strings",
+    "//ios/web:test_support",
+    "//testing/gtest",
+    "//third_party/ocmock",
+    "//ui/base",
+  ]
+}
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "activity_service_controller_egtest.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui:ui_internal",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/third_party/material_components_ios",
+    "//ios/web:test_support",
+    "//ui/base",
+  ]
+  libs = [ "XCTest.framework" ]
+}
diff --git a/ios/chrome/browser/ui/alert_coordinator/BUILD.gn b/ios/chrome/browser/ui/alert_coordinator/BUILD.gn
index ba5bab4..78049b0f 100644
--- a/ios/chrome/browser/ui/alert_coordinator/BUILD.gn
+++ b/ios/chrome/browser/ui/alert_coordinator/BUILD.gn
@@ -37,3 +37,40 @@
     "//ui/strings",
   ]
 }
+
+source_set("alert_coordinator_internal") {
+  sources = [
+    "loading_alert_coordinator.h",
+    "loading_alert_coordinator.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/material_components",
+    "//ios/third_party/material_components_ios",
+    "//ios/third_party/material_roboto_font_loader_ios",
+    "//ui/base",
+  ]
+  libs = [ "UIKit.framework" ]
+}
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "alert_coordinator_egtest.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/strings",
+    "//ios/chrome/browser/ui/alert_coordinator",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/testing/earl_grey:earl_grey_support",
+    "//ios/third_party/earl_grey",
+  ]
+  libs = [
+    "UIKit.framework",
+    "XCTest.framework",
+  ]
+}
diff --git a/ios/chrome/browser/ui/animators/BUILD.gn b/ios/chrome/browser/ui/animators/BUILD.gn
new file mode 100644
index 0000000..32c610a
--- /dev/null
+++ b/ios/chrome/browser/ui/animators/BUILD.gn
@@ -0,0 +1,17 @@
+# 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.
+
+source_set("animators") {
+  sources = [
+    "zoom_transition_animator.h",
+    "zoom_transition_animator.mm",
+    "zoom_transition_delegate.h",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+
+  deps = [
+    "//base",
+  ]
+}
diff --git a/ios/chrome/browser/ui/authentication/BUILD.gn b/ios/chrome/browser/ui/authentication/BUILD.gn
index 96c2912..718a53d 100644
--- a/ios/chrome/browser/ui/authentication/BUILD.gn
+++ b/ios/chrome/browser/ui/authentication/BUILD.gn
@@ -12,3 +12,126 @@
     "{{bundle_resources_dir}}/{{source_file_part}}",
   ]
 }
+
+source_set("authentication") {
+  sources = [
+    "authentication_flow.h",
+    "authentication_flow.mm",
+    "authentication_flow_performer.h",
+    "authentication_flow_performer.mm",
+    "authentication_flow_performer_delegate.h",
+    "authentication_ui_util.h",
+    "authentication_ui_util.mm",
+    "chrome_signin_view_controller.h",
+    "chrome_signin_view_controller.mm",
+    "re_signin_infobar_delegate.h",
+    "re_signin_infobar_delegate.mm",
+    "signed_in_accounts_view_controller.h",
+    "signed_in_accounts_view_controller.mm",
+    "signin_account_selector_view_controller.h",
+    "signin_account_selector_view_controller.mm",
+    "signin_confirmation_view_controller.h",
+    "signin_confirmation_view_controller.mm",
+    "signin_interaction_controller.h",
+    "signin_interaction_controller.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/google/core/browser",
+    "//components/infobars/core",
+    "//components/prefs",
+    "//components/signin/core/browser",
+    "//components/signin/core/common",
+    "//components/signin/ios/browser",
+    "//components/strings",
+    "//google_apis",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/app/theme",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/browsing_data",
+    "//ios/chrome/browser/infobars",
+    "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/sync",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/alert_coordinator",
+    "//ios/chrome/browser/ui/authentication:resources",
+    "//ios/chrome/browser/ui/collection_view",
+    "//ios/chrome/browser/ui/collection_view/cells",
+    "//ios/chrome/browser/ui/colors",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/settings/cells",
+    "//ios/chrome/browser/ui/settings/utils",
+    "//ios/chrome/browser/ui/util",
+    "//ios/chrome/common",
+    "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser/images",
+    "//ios/public/provider/chrome/browser/signin",
+    "//ios/third_party/material_components_ios",
+    "//ios/third_party/material_roboto_font_loader_ios",
+    "//ui/base",
+    "//ui/gfx",
+    "//url",
+  ]
+  libs = [
+    "CoreGraphics.framework",
+    "QuartzCore.framework",
+    "UIKit.framework",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "authentication_flow_unittest.mm",
+    "re_signin_infobar_delegate_unittest.mm",
+    "signed_in_accounts_view_controller_unittest.mm",
+  ]
+  deps = [
+    ":authentication",
+    "//base",
+    "//base/test:test_support",
+    "//components/pref_registry",
+    "//components/sync_preferences",
+    "//components/sync_preferences:test_support",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/infobars",
+    "//ios/chrome/browser/prefs:browser_prefs",
+    "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/signin:test_support",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/test:test_support",
+    "//ios/public/provider/chrome/browser/signin:test_support",
+    "//ios/web:test_support",
+    "//testing/gtest",
+    "//third_party/ocmock",
+    "//ui/base",
+  ]
+}
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "signin_interaction_controller_egtest.mm",
+  ]
+  deps = [
+    "//base",
+    "//base/test:test_support",
+    "//components/signin/core/browser",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/settings",
+    "//ios/chrome/browser/ui/tools_menu",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/public/provider/chrome/browser/signin:test_support",
+    "//ios/testing:ios_test_support",
+    "//ios/testing/earl_grey:earl_grey_support",
+    "//ios/third_party/earl_grey",
+  ]
+  libs = [ "XCTest.framework" ]
+}
diff --git a/ios/chrome/browser/ui/autofill/BUILD.gn b/ios/chrome/browser/ui/autofill/BUILD.gn
index 9b3f89f..0f2627a 100644
--- a/ios/chrome/browser/ui/autofill/BUILD.gn
+++ b/ios/chrome/browser/ui/autofill/BUILD.gn
@@ -25,3 +25,28 @@
     "//ios/public/provider/chrome/browser",
   ]
 }
+
+source_set("autofill_internal") {
+  sources = [
+    "card_unmask_prompt_view_bridge.h",
+    "card_unmask_prompt_view_bridge.mm",
+    "storage_switch_tooltip.h",
+    "storage_switch_tooltip.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/autofill/core/browser",
+    "//components/strings",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/autofill/cells",
+    "//ios/chrome/browser/ui/collection_view/cells",
+    "//ios/chrome/browser/ui/colors",
+    "//ios/third_party/material_components_ios",
+    "//ios/third_party/material_roboto_font_loader_ios",
+    "//ui/base",
+  ]
+  public_deps = [
+    "//ios/chrome/browser/ui/collection_view",
+  ]
+  libs = [ "UIKit.framework" ]
+}
diff --git a/ios/chrome/browser/ui/autofill/cells/BUILD.gn b/ios/chrome/browser/ui/autofill/cells/BUILD.gn
new file mode 100644
index 0000000..8bd7c3e
--- /dev/null
+++ b/ios/chrome/browser/ui/autofill/cells/BUILD.gn
@@ -0,0 +1,50 @@
+# 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.
+
+source_set("cells") {
+  sources = [
+    "cvc_item.h",
+    "cvc_item.mm",
+    "status_item.h",
+    "status_item.mm",
+    "storage_switch_item.h",
+    "storage_switch_item.mm",
+  ]
+
+  deps = [
+    "//components/resources",
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/app/theme",
+    "//ios/chrome/browser/ui/collection_view/cells",
+    "//ios/chrome/browser/ui/colors",
+    "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser/ui",
+    "//ios/third_party/material_components_ios",
+    "//ios/third_party/material_roboto_font_loader_ios",
+    "//ui/base",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "cvc_item_unittest.mm",
+    "status_item_unittest.mm",
+    "storage_switch_item_unittest.mm",
+  ]
+
+  deps = [
+    ":cells",
+    "//base",
+    "//components/resources",
+    "//ios/chrome/browser/ui/collection_view/cells",
+    "//ios/third_party/material_components_ios",
+    "//testing/gtest",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+}
diff --git a/ios/chrome/browser/ui/bookmarks/BUILD.gn b/ios/chrome/browser/ui/bookmarks/BUILD.gn
index 4f2fb6b..627dca3 100644
--- a/ios/chrome/browser/ui/bookmarks/BUILD.gn
+++ b/ios/chrome/browser/ui/bookmarks/BUILD.gn
@@ -78,3 +78,180 @@
     "{{bundle_resources_dir}}/{{source_file_part}}",
   ]
 }
+
+source_set("bookmarks") {
+  sources = [
+    "bookmark_all_collection_view.h",
+    "bookmark_all_collection_view.mm",
+    "bookmark_collection_cells.h",
+    "bookmark_collection_cells.mm",
+    "bookmark_collection_view.h",
+    "bookmark_collection_view.mm",
+    "bookmark_collection_view_background.h",
+    "bookmark_collection_view_background.mm",
+    "bookmark_controller_factory.h",
+    "bookmark_controller_factory.mm",
+    "bookmark_edit_view_controller.h",
+    "bookmark_edit_view_controller.mm",
+    "bookmark_elevated_toolbar.h",
+    "bookmark_elevated_toolbar.mm",
+    "bookmark_extended_button.h",
+    "bookmark_extended_button.mm",
+    "bookmark_folder_collection_view.h",
+    "bookmark_folder_collection_view.mm",
+    "bookmark_folder_editor_view_controller.h",
+    "bookmark_folder_editor_view_controller.mm",
+    "bookmark_folder_table_view_cell.h",
+    "bookmark_folder_table_view_cell.mm",
+    "bookmark_folder_view_controller.h",
+    "bookmark_folder_view_controller.mm",
+    "bookmark_home_handset_view_controller.h",
+    "bookmark_home_handset_view_controller.mm",
+    "bookmark_home_primary_view.h",
+    "bookmark_home_tablet_ntp_controller.h",
+    "bookmark_home_tablet_ntp_controller.mm",
+    "bookmark_home_view_controller.h",
+    "bookmark_home_view_controller.mm",
+    "bookmark_home_waiting_view.h",
+    "bookmark_home_waiting_view.mm",
+    "bookmark_interaction_controller.h",
+    "bookmark_interaction_controller.mm",
+    "bookmark_menu_cell.h",
+    "bookmark_menu_cell.mm",
+    "bookmark_menu_item.h",
+    "bookmark_menu_item.mm",
+    "bookmark_menu_view.h",
+    "bookmark_menu_view.mm",
+    "bookmark_model_bridge_observer.h",
+    "bookmark_model_bridge_observer.mm",
+    "bookmark_navigation_controller.h",
+    "bookmark_navigation_controller.mm",
+    "bookmark_panel_view.h",
+    "bookmark_panel_view.mm",
+    "bookmark_position_cache.h",
+    "bookmark_position_cache.mm",
+    "bookmark_promo_cell.h",
+    "bookmark_promo_cell.mm",
+    "bookmark_promo_controller.h",
+    "bookmark_promo_controller.mm",
+    "bookmark_utils_ios.h",
+    "bookmark_utils_ios.mm",
+    "undo_manager_bridge_observer.h",
+    "undo_manager_bridge_observer.mm",
+    "undo_manager_wrapper.h",
+    "undo_manager_wrapper.mm",
+  ]
+  deps = [
+    "//base",
+    "//base:i18n",
+    "//components/bookmarks/browser",
+    "//components/favicon/core",
+    "//components/favicon_base",
+    "//components/pref_registry",
+    "//components/prefs",
+    "//components/query_parser",
+    "//components/signin/core/browser",
+    "//components/strings",
+    "//components/undo",
+    "//components/url_formatter",
+    "//google_apis",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/app/theme",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/bookmarks",
+    "//ios/chrome/browser/bookmarks:bookmarks_utils",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/favicon",
+    "//ios/chrome/browser/metrics:metrics_internal",
+    "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/alert_coordinator",
+    "//ios/chrome/browser/ui/bookmarks:resources",
+    "//ios/chrome/browser/ui/bookmarks/bars",
+    "//ios/chrome/browser/ui/bookmarks/cells",
+    "//ios/chrome/browser/ui/collection_view",
+    "//ios/chrome/browser/ui/collection_view/cells",
+    "//ios/chrome/browser/ui/colors",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/icons",
+    "//ios/chrome/browser/ui/keyboard",
+    "//ios/chrome/browser/ui/material_components",
+    "//ios/chrome/browser/ui/ntp",
+    "//ios/chrome/browser/undo",
+    "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser/ui",
+    "//ios/third_party/material_components_ios",
+    "//ios/third_party/material_roboto_font_loader_ios",
+    "//ios/web",
+    "//skia",
+    "//ui/base",
+    "//ui/gfx",
+    "//url",
+  ]
+  allow_circular_includes_from = [
+    "//ios/chrome/browser/ui/bookmarks/bars",
+    "//ios/chrome/browser/ui/bookmarks/cells",
+  ]
+  libs = [
+    "CoreGraphics.framework",
+    "QuartzCore.framework",
+    "UIKit.framework",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "bookmark_home_view_controller_unittest.mm",
+    "bookmark_ios_unittest.mm",
+    "bookmark_position_cache_unittest.mm",
+    "bookmark_utils_ios_unittest.mm",
+  ]
+  deps = [
+    ":bookmarks",
+    "//base",
+    "//components/bookmarks/browser",
+    "//components/bookmarks/test",
+    "//components/sync_preferences:test_support",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/bookmarks",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/web:test_support",
+    "//testing/gtest",
+  ]
+}
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "bookmarks_egtest.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/bookmarks/browser",
+    "//components/prefs",
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/bookmarks",
+    "//ios/chrome/browser/bookmarks:bookmarks_utils",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/toolbar",
+    "//ios/chrome/browser/ui/tools_menu",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/public/provider/chrome/browser/signin:test_support",
+    "//ios/testing:ios_test_support",
+    "//ios/third_party/earl_grey",
+    "//ios/web:test_support",
+    "//ui/base",
+    "//url",
+  ]
+  libs = [
+    "UIKit.framework",
+    "XCTest.framework",
+  ]
+}
diff --git a/ios/chrome/browser/ui/bookmarks/bars/BUILD.gn b/ios/chrome/browser/ui/bookmarks/bars/BUILD.gn
new file mode 100644
index 0000000..47c8cfe
--- /dev/null
+++ b/ios/chrome/browser/ui/bookmarks/bars/BUILD.gn
@@ -0,0 +1,25 @@
+# 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.
+
+source_set("bars") {
+  sources = [
+    "bookmark_editing_bar.h",
+    "bookmark_editing_bar.mm",
+    "bookmark_navigation_bar.h",
+    "bookmark_navigation_bar.mm",
+    "bookmark_top_bar.h",
+    "bookmark_top_bar.mm",
+  ]
+  deps = [
+    "//base",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui",
+    "//ios/third_party/material_components_ios",
+    "//ui/base",
+  ]
+  libs = [
+    "QuartzCore.framework",
+    "UIKit.framework",
+  ]
+}
diff --git a/ios/chrome/browser/ui/bookmarks/cells/BUILD.gn b/ios/chrome/browser/ui/bookmarks/cells/BUILD.gn
new file mode 100644
index 0000000..13996b5
--- /dev/null
+++ b/ios/chrome/browser/ui/bookmarks/cells/BUILD.gn
@@ -0,0 +1,45 @@
+# 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.
+
+source_set("cells") {
+  sources = [
+    "bookmark_parent_folder_item.h",
+    "bookmark_parent_folder_item.mm",
+    "bookmark_text_field_item.h",
+    "bookmark_text_field_item.mm",
+  ]
+
+  deps = [
+    "//base",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/collection_view/cells",
+    "//ios/chrome/browser/ui/icons",
+    "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser/ui",
+    "//ios/third_party/material_components_ios",
+    "//ios/third_party/material_roboto_font_loader_ios",
+    "//ui/base",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "bookmark_parent_folder_item_unittest.mm",
+    "bookmark_text_field_item_unittest.mm",
+  ]
+
+  deps = [
+    ":cells",
+    "//ios/chrome/browser/ui/collection_view/cells",
+    "//ios/third_party/material_components_ios",
+    "//testing/gtest",
+    "//third_party/ocmock",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+}
diff --git a/ios/chrome/browser/ui/collection_view/BUILD.gn b/ios/chrome/browser/ui/collection_view/BUILD.gn
new file mode 100644
index 0000000..0aafb01
--- /dev/null
+++ b/ios/chrome/browser/ui/collection_view/BUILD.gn
@@ -0,0 +1,54 @@
+# 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.
+
+source_set("collection_view") {
+  sources = [
+    "collection_view_controller.h",
+    "collection_view_controller.mm",
+    "collection_view_model.h",
+    "collection_view_model.mm",
+  ]
+  deps = [
+    "//base",
+    "//ios/chrome/browser/ui/material_components",
+  ]
+  public_deps = [
+    "//ios/chrome/browser/ui/collection_view/cells",
+    "//ios/third_party/material_components_ios",
+  ]
+}
+
+source_set("test_support") {
+  testonly = true
+  sources = [
+    "collection_view_controller_test.h",
+    "collection_view_controller_test.mm",
+  ]
+  deps = [
+    ":collection_view",
+    "//base",
+    "//ios/chrome/browser/ui/collection_view/cells",
+    "//ios/chrome/test:test_support",
+    "//ios/third_party/material_components_ios",
+    "//testing/gtest",
+    "//ui/base",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "collection_view_controller_unittest.mm",
+    "collection_view_model_unittest.mm",
+  ]
+  deps = [
+    ":collection_view",
+    "//base",
+    "//ios/chrome/browser/ui/collection_view/cells",
+    "//ios/chrome/test:test_support",
+    "//ios/chrome/test/base",
+    "//ios/third_party/material_components_ios",
+    "//testing/gtest",
+  ]
+}
diff --git a/ios/chrome/browser/ui/collection_view/cells/BUILD.gn b/ios/chrome/browser/ui/collection_view/cells/BUILD.gn
new file mode 100644
index 0000000..e6e8c32
--- /dev/null
+++ b/ios/chrome/browser/ui/collection_view/cells/BUILD.gn
@@ -0,0 +1,72 @@
+# 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.
+
+source_set("cells") {
+  sources = [
+    "MDCCollectionViewCell+Chrome.h",
+    "MDCCollectionViewCell+Chrome.mm",
+    "activity_indicator_cell.h",
+    "activity_indicator_cell.mm",
+    "collection_view_account_item.h",
+    "collection_view_account_item.mm",
+    "collection_view_detail_item.h",
+    "collection_view_detail_item.mm",
+    "collection_view_footer_item.h",
+    "collection_view_footer_item.mm",
+    "collection_view_item.h",
+    "collection_view_item.mm",
+    "collection_view_switch_item.h",
+    "collection_view_switch_item.mm",
+    "collection_view_text_item.h",
+    "collection_view_text_item.mm",
+  ]
+
+  deps = [
+    "//base",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui/colors",
+    "//ios/chrome/browser/ui/material_components",
+    "//ios/chrome/browser/ui/util",
+    "//ios/chrome/common",
+    "//ios/third_party/material_roboto_font_loader_ios",
+    "//ui/base",
+    "//url",
+  ]
+  public_deps = [
+    "//ios/third_party/material_components_ios",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+}
+
+source_set("test_support") {
+  testonly = true
+  sources = [
+    "test_utils.h",
+    "test_utils.mm",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "MDCCollectionViewCell+Chrome_unittest.mm",
+    "activity_indicator_cell_unittest.mm",
+    "collection_view_account_item_unittest.mm",
+    "collection_view_detail_item_unittest.mm",
+    "collection_view_footer_item_unittest.mm",
+    "collection_view_item_unittest.mm",
+    "collection_view_switch_item_unittest.mm",
+    "collection_view_text_item_unittest.mm",
+  ]
+
+  deps = [
+    ":cells",
+    ":test_support",
+    "//ios/third_party/material_components_ios",
+    "//testing/gtest",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+}
diff --git a/ios/chrome/browser/ui/colors/BUILD.gn b/ios/chrome/browser/ui/colors/BUILD.gn
new file mode 100644
index 0000000..f49ba7b
--- /dev/null
+++ b/ios/chrome/browser/ui/colors/BUILD.gn
@@ -0,0 +1,14 @@
+# 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.
+
+source_set("colors") {
+  sources = [
+    "MDCPalette+CrAdditions.h",
+    "MDCPalette+CrAdditions.mm",
+  ]
+  deps = [
+    "//ios/third_party/material_components_ios",
+    "//ios/web",
+  ]
+}
diff --git a/ios/chrome/browser/ui/contextual_search/BUILD.gn b/ios/chrome/browser/ui/contextual_search/BUILD.gn
index 40e83396..6d1813a 100644
--- a/ios/chrome/browser/ui/contextual_search/BUILD.gn
+++ b/ios/chrome/browser/ui/contextual_search/BUILD.gn
@@ -30,3 +30,113 @@
     "{{bundle_resources_dir}}/{{source_file_part}}",
   ]
 }
+
+source_set("contextual_search") {
+  sources = [
+    "contextual_search_context.cc",
+    "contextual_search_context.h",
+    "contextual_search_controller.h",
+    "contextual_search_controller.mm",
+    "contextual_search_delegate.cc",
+    "contextual_search_delegate.h",
+    "contextual_search_header_view.h",
+    "contextual_search_header_view.mm",
+    "contextual_search_highlighter_view.h",
+    "contextual_search_highlighter_view.mm",
+    "contextual_search_mask_view.h",
+    "contextual_search_mask_view.mm",
+    "contextual_search_metrics.h",
+    "contextual_search_metrics.mm",
+    "contextual_search_panel_protocols.h",
+    "contextual_search_panel_view.h",
+    "contextual_search_panel_view.mm",
+    "contextual_search_promo_view.h",
+    "contextual_search_promo_view.mm",
+    "contextual_search_results_view.h",
+    "contextual_search_results_view.mm",
+    "contextual_search_web_state_observer.h",
+    "contextual_search_web_state_observer.mm",
+    "js_contextual_search_manager.h",
+    "js_contextual_search_manager.mm",
+    "panel_configuration.h",
+    "panel_configuration.mm",
+    "touch_to_search_permissions_mediator.h",
+    "touch_to_search_permissions_mediator.mm",
+    "window_gesture_observer.h",
+    "window_gesture_observer.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/google/core/browser",
+    "//components/prefs",
+    "//components/search_engines",
+    "//components/variations",
+    "//components/variations/net",
+    "//ios/chrome/app:tests_hook",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/prefs",
+    "//ios/chrome/browser/search_engines",
+    "//ios/chrome/browser/sync",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/colors",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/contextual_search:injected_js",
+    "//ios/chrome/browser/ui/contextual_search:resources",
+    "//ios/chrome/browser/ui/contextual_search/protos",
+    "//ios/chrome/browser/ui/util",
+    "//ios/chrome/browser/web",
+    "//ios/chrome/common",
+    "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser/images",
+    "//ios/third_party/material_components_ios",
+    "//ios/third_party/material_roboto_font_loader_ios",
+    "//ios/web",
+    "//net",
+    "//ui/base",
+    "//url",
+  ]
+  libs = [ "UIKit.framework" ]
+}
+
+source_set("test_support") {
+  testonly = true
+  sources = [
+    "touch_to_search_permissions_mediator+testing.h",
+    "touch_to_search_permissions_mediator+testing.mm",
+  ]
+  deps = [
+    ":contextual_search",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "contextual_search_js_unittest.mm",
+    "touch_to_search_permissions_mediator_unittest.mm",
+  ]
+  deps = [
+    ":contextual_search",
+    ":test_support",
+    "//base",
+    "//base/test:test_support",
+    "//components/pref_registry",
+    "//components/prefs",
+    "//components/search_engines",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/search_engines",
+    "//ios/chrome/browser/sync",
+    "//ios/chrome/browser/sync:test_support",
+    "//ios/chrome/browser/ui/contextual_search:resources_unit_tests",
+    "//ios/chrome/browser/web:test_support",
+    "//ios/web",
+    "//ios/web:test_support",
+    "//net",
+    "//testing/gtest",
+    "//third_party/ocmock",
+  ]
+}
diff --git a/ios/chrome/browser/ui/contextual_search/protos/BUILD.gn b/ios/chrome/browser/ui/contextual_search/protos/BUILD.gn
new file mode 100644
index 0000000..a882a06
--- /dev/null
+++ b/ios/chrome/browser/ui/contextual_search/protos/BUILD.gn
@@ -0,0 +1,11 @@
+# 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.
+
+import("//third_party/protobuf/proto_library.gni")
+
+proto_library("protos") {
+  sources = [
+    "client_discourse_context.proto",
+  ]
+}
diff --git a/ios/chrome/browser/ui/dialogs/BUILD.gn b/ios/chrome/browser/ui/dialogs/BUILD.gn
index 506aa95..6f7f557 100644
--- a/ios/chrome/browser/ui/dialogs/BUILD.gn
+++ b/ios/chrome/browser/ui/dialogs/BUILD.gn
@@ -32,3 +32,76 @@
 
   configs += [ "//build/config/compiler:enable_arc" ]
 }
+
+source_set("dialogs_internal") {
+  sources = [
+    "dialog_presenter.h",
+    "dialog_presenter.mm",
+    "java_script_dialog_presenter_impl.h",
+    "java_script_dialog_presenter_impl.mm",
+    "nsurl_protection_space_util.h",
+    "nsurl_protection_space_util.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/strings",
+    "//components/url_formatter",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/alert_coordinator",
+    "//ios/chrome/browser/ui/dialogs",
+    "//ios/web",
+    "//ui/base",
+    "//url",
+  ]
+  libs = [ "UIKit.framework" ]
+}
+
+source_set("unit_tests_internal") {
+  testonly = true
+  sources = [
+    "dialog_presenter_unittest.mm",
+    "nsurl_protection_space_util_unittest.mm",
+  ]
+  deps = [
+    ":dialogs_internal",
+    "//base",
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui/alert_coordinator",
+    "//ios/web:test_support",
+    "//ios/web:web",
+    "//testing/gtest",
+    "//ui/base",
+    "//url",
+  ]
+}
+
+source_set("eg_tests") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  testonly = true
+  sources = [
+    "javascript_dialog_egtest.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/dialogs:dialogs_internal",
+    "//ios/chrome/browser/ui/tools_menu",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/testing:ios_test_support",
+    "//ios/testing/earl_grey:earl_grey_support",
+    "//ios/third_party/earl_grey",
+    "//ios/web",
+    "//ios/web:test_support",
+    "//ui/base",
+    "//url",
+  ]
+  libs = [
+    "UIKit.framework",
+    "XCTest.framework",
+  ]
+}
diff --git a/ios/chrome/browser/ui/downloads/BUILD.gn b/ios/chrome/browser/ui/downloads/BUILD.gn
index 033ec0c..eafa4b4 100644
--- a/ios/chrome/browser/ui/downloads/BUILD.gn
+++ b/ios/chrome/browser/ui/downloads/BUILD.gn
@@ -32,3 +32,49 @@
 bundle_data_ib_file("download_manager_controller_xib") {
   source = "resources/DownloadManagerController.xib"
 }
+
+source_set("downloads") {
+  sources = [
+    "download_manager_controller.h",
+    "download_manager_controller.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/native_app_launcher",
+    "//ios/chrome/browser/native_app_launcher:native_app_launcher_internal",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/alert_coordinator",
+    "//ios/chrome/browser/ui/colors",
+    "//ios/chrome/browser/ui/downloads:assets",
+    "//ios/chrome/browser/ui/downloads:download_manager_controller_xib",
+    "//ios/chrome/browser/web:web_internal",
+    "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser/native_app_launcher",
+    "//ios/third_party/material_components_ios",
+    "//ios/third_party/material_roboto_font_loader_ios",
+    "//ios/web",
+    "//ios/web:core",
+    "//net",
+    "//ui/base",
+    "//ui/gfx",
+  ]
+  libs = [ "UIKit.framework" ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "download_manager_controller_unittest.mm",
+  ]
+  deps = [
+    ":downloads",
+    "//base",
+    "//ios/chrome/browser",
+    "//ios/web:test_support",
+    "//net:test_support",
+    "//testing/gtest",
+  ]
+}
diff --git a/ios/chrome/browser/ui/elements/BUILD.gn b/ios/chrome/browser/ui/elements/BUILD.gn
index 4a287e8..2eb19d6 100644
--- a/ios/chrome/browser/ui/elements/BUILD.gn
+++ b/ios/chrome/browser/ui/elements/BUILD.gn
@@ -22,14 +22,33 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
+    "activity_overlay_coordinator_unittest.mm",
     "selector_coordinator_unittest.mm",
     "selector_picker_view_controller_unittest.mm",
   ]
   deps = [
     ":elements",
+    ":elements_internal",
     "//base",
     "//base/test:test_support",
     "//testing/gtest",
     "//third_party/ocmock",
   ]
 }
+
+source_set("elements_internal") {
+  sources = [
+    "activity_overlay_coordinator.h",
+    "activity_overlay_coordinator.mm",
+    "activity_overlay_view_controller.h",
+    "activity_overlay_view_controller.mm",
+  ]
+  deps = [
+    "//base",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/material_components",
+    "//ios/third_party/material_components_ios",
+  ]
+  libs = [ "UIKit.framework" ]
+}
diff --git a/ios/chrome/browser/ui/fancy_ui/BUILD.gn b/ios/chrome/browser/ui/fancy_ui/BUILD.gn
new file mode 100644
index 0000000..7af8ee0e
--- /dev/null
+++ b/ios/chrome/browser/ui/fancy_ui/BUILD.gn
@@ -0,0 +1,36 @@
+# 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.
+
+source_set("fancy_ui") {
+  sources = [
+    "bidi_container_view.h",
+    "bidi_container_view.mm",
+    "primary_action_button.h",
+    "primary_action_button.mm",
+    "tinted_button.h",
+    "tinted_button.mm",
+  ]
+  deps = [
+    "//base",
+    "//base:i18n",
+    "//ios/chrome/browser/ui/colors",
+  ]
+  public_deps = [
+    "//ios/third_party/material_components_ios",
+  ]
+  libs = [ "UIKit.framework" ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "bidi_container_view_unittest.mm",
+  ]
+  deps = [
+    ":fancy_ui",
+    "//base",
+    "//base:i18n",
+    "//testing/gtest",
+  ]
+}
diff --git a/ios/chrome/browser/ui/find_bar/BUILD.gn b/ios/chrome/browser/ui/find_bar/BUILD.gn
index ae4b3e8..1d2280e 100644
--- a/ios/chrome/browser/ui/find_bar/BUILD.gn
+++ b/ios/chrome/browser/ui/find_bar/BUILD.gn
@@ -56,3 +56,49 @@
     "{{bundle_resources_dir}}/{{source_file_part}}",
   ]
 }
+
+source_set("find_bar") {
+  sources = [
+    "find_bar_controller_ios.h",
+    "find_bar_controller_ios.mm",
+    "find_bar_touch_forwarding_view.h",
+    "find_bar_touch_forwarding_view.mm",
+    "find_bar_view.h",
+    "find_bar_view.mm",
+  ]
+  deps = [
+    "//base",
+    "//base:i18n",
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/find_in_page",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/find_bar:resources",
+    "//ios/third_party/material_components_ios",
+    "//ui/base",
+    "//ui/gfx",
+  ]
+  libs = [ "UIKit.framework" ]
+}
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "find_in_page_egtest.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/find_in_page",
+    "//ios/chrome/browser/ui/find_bar",
+    "//ios/chrome/browser/ui/tools_menu",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/testing:ios_test_support",
+    "//ios/web:test_support",
+    "//ui/base",
+  ]
+  libs = [ "XCTest.framework" ]
+}
diff --git a/ios/chrome/browser/ui/first_run/BUILD.gn b/ios/chrome/browser/ui/first_run/BUILD.gn
index 57823a4..379efcc 100644
--- a/ios/chrome/browser/ui/first_run/BUILD.gn
+++ b/ios/chrome/browser/ui/first_run/BUILD.gn
@@ -21,3 +21,103 @@
     "{{bundle_resources_dir}}/{{source_file_part}}",
   ]
 }
+
+source_set("first_run") {
+  sources = [
+    "first_run_chrome_signin_view_controller.h",
+    "first_run_chrome_signin_view_controller.mm",
+    "first_run_histograms.h",
+    "first_run_util.h",
+    "first_run_util.mm",
+    "static_file_view_controller.h",
+    "static_file_view_controller.mm",
+    "welcome_to_chrome_view.h",
+    "welcome_to_chrome_view.mm",
+    "welcome_to_chrome_view_controller.h",
+    "welcome_to_chrome_view_controller.mm",
+  ]
+  deps = [
+    "//base",
+    "//base:i18n",
+    "//components/metrics",
+    "//components/prefs",
+    "//components/signin/core/browser",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/crash_report",
+    "//ios/chrome/browser/first_run",
+    "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/authentication",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/fancy_ui",
+    "//ios/chrome/browser/ui/first_run:assets",
+    "//ios/chrome/browser/ui/material_components",
+    "//ios/chrome/browser/ui/promos",
+    "//ios/chrome/browser/ui/settings",
+    "//ios/chrome/browser/ui/sync",
+    "//ios/chrome/browser/ui/util",
+    "//ios/chrome/common",
+    "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser/signin",
+    "//ios/third_party/material_components_ios",
+    "//ios/third_party/material_roboto_font_loader_ios",
+    "//ios/web",
+    "//ui/base",
+    "//ui/gfx",
+    "//url",
+  ]
+  libs = [ "UIKit.framework" ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "first_run_util_unittest.mm",
+    "welcome_to_chrome_view_controller_unittest.mm",
+  ]
+  deps = [
+    ":first_run",
+    "//base",
+    "//components/metrics",
+    "//components/prefs",
+    "//components/prefs:test_support",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/fancy_ui",
+    "//ios/chrome/test:test_support",
+    "//ios/web:test_support",
+    "//testing/gtest",
+    "//third_party/ocmock",
+  ]
+}
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "first_run_egtest.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/metrics",
+    "//components/prefs",
+    "//components/signin/core/browser",
+    "//ios/chrome/app:app_internal",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/geolocation:geolocation_internal",
+    "//ios/chrome/browser/geolocation:test_support",
+    "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/sync",
+    "//ios/chrome/browser/ui/first_run",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/public/provider/chrome/browser/signin:test_support",
+    "//ios/third_party/earl_grey",
+    "//ui/base",
+  ]
+  libs = [ "XCTest.framework" ]
+}
diff --git a/ios/chrome/browser/ui/history/BUILD.gn b/ios/chrome/browser/ui/history/BUILD.gn
new file mode 100644
index 0000000..ba1c361c
--- /dev/null
+++ b/ios/chrome/browser/ui/history/BUILD.gn
@@ -0,0 +1,176 @@
+# 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.
+
+source_set("history") {
+  sources = [
+    "clear_browsing_bar.h",
+    "clear_browsing_bar.mm",
+    "favicon_view.h",
+    "favicon_view.mm",
+    "favicon_view_provider.h",
+    "favicon_view_provider.mm",
+    "history_collection_view_controller.h",
+    "history_collection_view_controller.mm",
+    "history_entries_status_item.h",
+    "history_entries_status_item.mm",
+    "history_entry.cc",
+    "history_entry.h",
+    "history_entry_inserter.h",
+    "history_entry_inserter.mm",
+    "history_entry_item.h",
+    "history_entry_item.mm",
+    "history_panel_view_controller.h",
+    "history_panel_view_controller.mm",
+    "history_search_view.h",
+    "history_search_view.mm",
+    "history_search_view_controller.h",
+    "history_search_view_controller.mm",
+    "history_service_facade.h",
+    "history_service_facade.mm",
+    "history_service_facade_delegate.h",
+    "history_util.h",
+    "history_util.mm",
+    "tab_history_cell.h",
+    "tab_history_cell.mm",
+    "tab_history_popup_controller.h",
+    "tab_history_popup_controller.mm",
+    "tab_history_view_controller.h",
+    "tab_history_view_controller.mm",
+  ]
+  deps = [
+    "//base",
+    "//base:i18n",
+    "//components/browser_sync",
+    "//components/browsing_data/core",
+    "//components/favicon/core",
+    "//components/favicon_base",
+    "//components/history/core/browser",
+    "//components/keyed_service/core",
+    "//components/prefs",
+    "//components/query_parser",
+    "//components/strings",
+    "//components/sync/protocol",
+    "//components/url_formatter",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/favicon",
+    "//ios/chrome/browser/history",
+    "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/sync",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/collection_view",
+    "//ios/chrome/browser/ui/collection_view/cells",
+    "//ios/chrome/browser/ui/colors",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/context_menu",
+    "//ios/chrome/browser/ui/icons",
+    "//ios/chrome/browser/ui/material_components",
+    "//ios/chrome/browser/ui/ntp/recent_tabs/views",
+    "//ios/chrome/browser/ui/popup_menu",
+    "//ios/chrome/browser/ui/settings",
+    "//ios/chrome/browser/ui/util",
+    "//ios/chrome/common",
+    "//ios/third_party/material_components_ios",
+    "//ios/third_party/material_roboto_font_loader_ios",
+    "//ios/web",
+    "//net",
+    "//skia",
+    "//ui/base",
+    "//ui/gfx",
+    "//url",
+  ]
+  libs = [
+    "MobileCoreServices.framework",
+    "QuartzCore.framework",
+    "UIKit.framework",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "favicon_view_provider_unittest.mm",
+    "history_collection_view_controller_unittest.mm",
+    "history_entries_status_item_unittest.mm",
+    "history_entry_inserter_unittest.mm",
+    "history_entry_item_unittest.mm",
+    "history_search_view_controller_unittest.mm",
+    "history_service_facade_unittest.mm",
+    "history_util_unittest.mm",
+    "tab_history_popup_controller_unittest.mm",
+  ]
+  deps = [
+    ":history",
+    ":resources_unit_tests",
+    "//base",
+    "//base/test:test_support",
+    "//components/favicon/core",
+    "//components/favicon_base",
+    "//components/history/core/browser",
+    "//components/keyed_service/core",
+    "//components/sessions",
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/history",
+    "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/signin:test_support",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/collection_view",
+    "//ios/chrome/browser/ui/util",
+    "//ios/chrome/common",
+    "//ios/chrome/test:test_support",
+    "//ios/web",
+    "//ios/web:test_support",
+    "//skia",
+    "//testing/gtest",
+    "//third_party/ocmock",
+    "//ui/base",
+    "//ui/gfx",
+    "//url",
+  ]
+}
+
+bundle_data("resources_unit_tests") {
+  visibility = [ ":unit_tests" ]
+  testonly = true
+  sources = [
+    "//ios/chrome/test/data/favicon/test_favicon.png",
+  ]
+  outputs = [
+    "{{bundle_resources_dir}}/" +
+        "ios/chrome/test/data/favicon/{{source_file_part}}",
+  ]
+}
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "history_ui_egtest.mm",
+    "tab_history_popup_controller_egtest.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/browsing_data/core",
+    "//components/prefs",
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/ui/history",
+    "//ios/chrome/browser/ui/settings",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/testing:ios_test_support",
+    "//ios/third_party/earl_grey",
+    "//ios/web:test_support",
+    "//net",
+    "//ui/base",
+  ]
+  libs = [
+    "UIKit.framework",
+    "XCTest.framework",
+  ]
+}
diff --git a/ios/chrome/browser/ui/icons/BUILD.gn b/ios/chrome/browser/ui/icons/BUILD.gn
index 8ecfe91..8114034 100644
--- a/ios/chrome/browser/ui/icons/BUILD.gn
+++ b/ios/chrome/browser/ui/icons/BUILD.gn
@@ -29,3 +29,34 @@
     "{{bundle_resources_dir}}/{{source_file_part}}",
   ]
 }
+
+source_set("icons") {
+  sources = [
+    "chrome_icon.h",
+    "chrome_icon.mm",
+  ]
+  deps = [
+    "//base",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui/icons:assets",
+    "//ui/base",
+  ]
+  libs = [
+    "CoreGraphics.framework",
+    "UIKit.framework",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "chrome_icon_unittest.mm",
+  ]
+  deps = [
+    ":icons",
+    "//ios/chrome/app/strings",
+    "//testing/gtest",
+    "//third_party/ocmock",
+    "//ui/base",
+  ]
+}
diff --git a/ios/chrome/browser/ui/infobars/BUILD.gn b/ios/chrome/browser/ui/infobars/BUILD.gn
index b23164c..1f0e2f4 100644
--- a/ios/chrome/browser/ui/infobars/BUILD.gn
+++ b/ios/chrome/browser/ui/infobars/BUILD.gn
@@ -26,3 +26,61 @@
     "{{bundle_resources_dir}}/{{source_file_part}}",
   ]
 }
+
+source_set("infobars") {
+  sources = [
+    "infobar_view.h",
+    "infobar_view.mm",
+  ]
+  deps = [
+    "//base",
+    "//base:i18n",
+    "//components/strings",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/colors",
+    "//ios/chrome/browser/ui/fancy_ui",
+    "//ios/chrome/browser/ui/infobars:resources",
+    "//ios/chrome/browser/ui/util",
+    "//ios/public/provider/chrome/browser/ui",
+    "//ios/third_party/material_components_ios",
+    "//ui/base",
+    "//ui/gfx",
+    "//url",
+  ]
+  libs = [
+    "CoreGraphics.framework",
+    "QuartzCore.framework",
+    "UIKit.framework",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "infobar_view_unittest.mm",
+  ]
+  deps = [
+    ":infobars",
+    "//testing/gtest",
+  ]
+}
+
+source_set("eg_tests") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  testonly = true
+  sources = [
+    "infobar_egtest.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/infobars/core",
+    "//ios/chrome/app:app_internal",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/third_party/earl_grey",
+    "//ios/web:test_support",
+    "//url",
+  ]
+  libs = [ "XCTest.framework" ]
+}
diff --git a/ios/chrome/browser/ui/main/BUILD.gn b/ios/chrome/browser/ui/main/BUILD.gn
new file mode 100644
index 0000000..e7ea0ca
--- /dev/null
+++ b/ios/chrome/browser/ui/main/BUILD.gn
@@ -0,0 +1,53 @@
+# 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.
+
+source_set("main") {
+  sources = [
+    "browser_view_information.h",
+    "browser_view_wrangler.h",
+    "browser_view_wrangler.mm",
+    "main_coordinator.h",
+    "main_coordinator.mm",
+    "main_view_controller.h",
+    "main_view_controller.mm",
+  ]
+  deps = [
+    "//base",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/browsing_data",
+    "//ios/chrome/browser/browsing_data:browsing_data_internal",
+    "//ios/chrome/browser/crash_report:crash_report_internal",
+    "//ios/chrome/browser/device_sharing",
+    "//ios/chrome/browser/physical_web",
+    "//ios/chrome/browser/sessions:sessions_internal",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/tabs:tabs_internal",
+    "//ios/public/provider/chrome/browser",
+  ]
+  public_deps = [
+    "//ios/chrome/browser/ui:ui_internal",
+  ]
+  libs = [ "UIKit.framework" ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "browser_view_wrangler_unittest.mm",
+    "main_coordinator_unittest.mm",
+    "main_view_controller_unittest.mm",
+  ]
+  deps = [
+    ":main",
+    "//base",
+    "//components/bookmarks/test",
+    "//ios/chrome/browser/bookmarks",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui:ui_internal",
+    "//ios/web:test_support",
+    "//testing/gtest",
+  ]
+}
diff --git a/ios/chrome/browser/ui/material_components/BUILD.gn b/ios/chrome/browser/ui/material_components/BUILD.gn
new file mode 100644
index 0000000..63e674f
--- /dev/null
+++ b/ios/chrome/browser/ui/material_components/BUILD.gn
@@ -0,0 +1,18 @@
+# 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.
+
+source_set("material_components") {
+  sources = [
+    "activity_indicator.h",
+    "activity_indicator.mm",
+    "app_bar_presenting.h",
+    "utils.h",
+    "utils.mm",
+  ]
+  deps = [
+    "//ios/chrome/browser/ui/colors",
+    "//ios/third_party/material_components_ios",
+  ]
+  libs = [ "UIKit.framework" ]
+}
diff --git a/ios/chrome/browser/ui/no_tabs/BUILD.gn b/ios/chrome/browser/ui/no_tabs/BUILD.gn
new file mode 100644
index 0000000..e243a5d
--- /dev/null
+++ b/ios/chrome/browser/ui/no_tabs/BUILD.gn
@@ -0,0 +1,34 @@
+# 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.
+
+source_set("no_tabs") {
+  sources = [
+    "no_tabs_controller.h",
+    "no_tabs_controller.mm",
+    "no_tabs_controller_testing.h",
+    "no_tabs_toolbar_controller.h",
+    "no_tabs_toolbar_controller.mm",
+  ]
+  deps = [
+    "//base",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/toolbar",
+    "//ios/chrome/browser/ui/tools_menu",
+    "//ui/gfx",
+  ]
+  libs = [ "UIKit.framework" ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "no_tabs_controller_unittest.mm",
+  ]
+  deps = [
+    ":no_tabs",
+    "//base",
+    "//testing/gtest",
+  ]
+}
diff --git a/ios/chrome/browser/ui/ntp/BUILD.gn b/ios/chrome/browser/ui/ntp/BUILD.gn
index d16c6993..4ea93cdb 100644
--- a/ios/chrome/browser/ui/ntp/BUILD.gn
+++ b/ios/chrome/browser/ui/ntp/BUILD.gn
@@ -100,3 +100,179 @@
     "{{bundle_resources_dir}}/{{source_file_part}}",
   ]
 }
+
+source_set("ntp") {
+  sources = [
+    "new_tab_page_panel_protocol.h",
+  ]
+}
+
+source_set("ntp_internal") {
+  sources = [
+    "centering_scrollview.h",
+    "centering_scrollview.mm",
+    "google_landing_controller.h",
+    "google_landing_controller.mm",
+    "incognito_panel_controller.h",
+    "incognito_panel_controller.mm",
+    "most_visited_cell.h",
+    "most_visited_cell.mm",
+    "most_visited_layout.h",
+    "most_visited_layout.mm",
+    "new_tab_page_bar.h",
+    "new_tab_page_bar.mm",
+    "new_tab_page_bar_button.h",
+    "new_tab_page_bar_button.mm",
+    "new_tab_page_bar_item.h",
+    "new_tab_page_bar_item.mm",
+    "new_tab_page_controller.h",
+    "new_tab_page_controller.mm",
+    "new_tab_page_header_constants.h",
+    "new_tab_page_header_constants.mm",
+    "new_tab_page_header_view.h",
+    "new_tab_page_header_view.mm",
+    "new_tab_page_panel_protocol.mm",
+    "new_tab_page_toolbar_controller.h",
+    "new_tab_page_toolbar_controller.mm",
+    "new_tab_page_view.h",
+    "new_tab_page_view.mm",
+    "notification_promo_whats_new.h",
+    "notification_promo_whats_new.mm",
+    "whats_new_header_view.h",
+    "whats_new_header_view.mm",
+  ]
+  deps = [
+    ":ntp",
+    "//base",
+    "//base:i18n",
+    "//components/favicon/core",
+    "//components/favicon_base",
+    "//components/google/core/browser",
+    "//components/history/core/browser",
+    "//components/keyed_service/core",
+    "//components/metrics",
+    "//components/ntp_tiles",
+    "//components/prefs",
+    "//components/rappor",
+    "//components/reading_list/core",
+    "//components/search_engines",
+    "//components/strings",
+    "//components/suggestions",
+    "//components/sync_sessions",
+    "//components/toolbar",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/app/theme",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/favicon",
+    "//ios/chrome/browser/history",
+    "//ios/chrome/browser/metrics:metrics_internal",
+    "//ios/chrome/browser/ntp_tiles",
+    "//ios/chrome/browser/reading_list",
+    "//ios/chrome/browser/search_engines",
+    "//ios/chrome/browser/suggestions",
+    "//ios/chrome/browser/sync",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/bookmarks",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/context_menu",
+    "//ios/chrome/browser/ui/ntp:resources",
+    "//ios/chrome/browser/ui/ntp/recent_tabs",
+    "//ios/chrome/browser/ui/overscroll_actions",
+    "//ios/chrome/browser/ui/toolbar",
+    "//ios/chrome/browser/ui/toolbar:resource_macros",
+    "//ios/chrome/common",
+    "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser/images",
+    "//ios/public/provider/chrome/browser/ui",
+    "//ios/public/provider/chrome/browser/voice",
+    "//ios/third_party/material_components_ios",
+    "//ios/third_party/material_roboto_font_loader_ios",
+    "//ios/web",
+    "//net",
+    "//skia",
+    "//ui/base",
+    "//ui/gfx",
+    "//url",
+  ]
+  libs = [
+    "CoreGraphics.framework",
+    "QuartzCore.framework",
+    "UIKit.framework",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "centering_scrollview_unittest.mm",
+    "google_landing_controller_unittest.mm",
+    "most_visited_cell_unittest.mm",
+    "new_tab_page_bar_unittest.mm",
+    "new_tab_page_controller_unittest.mm",
+    "notification_promo_whats_new_unittest.mm",
+  ]
+  deps = [
+    ":ntp",
+    ":ntp_internal",
+    "//base",
+    "//base/test:test_support",
+    "//components/bookmarks/test",
+    "//components/metrics",
+    "//components/prefs:test_support",
+    "//components/search_engines",
+    "//components/sessions",
+    "//components/variations",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/bookmarks",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/search_engines",
+    "//ios/chrome/browser/sessions",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/test:test_support",
+    "//ios/public/provider/chrome/browser/images",
+    "//ios/web:test_support",
+    "//testing/gtest",
+    "//third_party/ocmock",
+    "//ui/base",
+    "//url",
+  ]
+}
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "new_tab_page_egtest.mm",
+  ]
+  deps = [
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/ntp:ntp_internal",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/testing:ios_test_support",
+    "//ios/testing/earl_grey:earl_grey_support",
+    "//ios/third_party/earl_grey",
+    "//ui/base",
+  ]
+  libs = [ "XCTest.framework" ]
+}
+
+source_set("perf_tests") {
+  testonly = true
+  sources = [
+    "new_tab_page_perftest.mm",
+  ]
+  deps = [
+    "//base/test:test_support",
+    "//ios/chrome/browser/sessions",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/test:perf_test_support",
+    "//ios/chrome/browser/ui:ui_internal",
+  ]
+}
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/BUILD.gn b/ios/chrome/browser/ui/ntp/recent_tabs/BUILD.gn
new file mode 100644
index 0000000..5317f199
--- /dev/null
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/BUILD.gn
@@ -0,0 +1,92 @@
+# 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.
+
+source_set("recent_tabs") {
+  sources = [
+    "recent_tabs_bridges.h",
+    "recent_tabs_bridges.mm",
+    "recent_tabs_panel_controller.h",
+    "recent_tabs_panel_controller.mm",
+    "recent_tabs_panel_view_controller.h",
+    "recent_tabs_panel_view_controller.mm",
+    "recent_tabs_table_view_controller.h",
+    "recent_tabs_table_view_controller.mm",
+    "sessions_sync_user_state.h",
+    "synced_sessions.h",
+    "synced_sessions.mm",
+    "synced_sessions_bridge.h",
+    "synced_sessions_bridge.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/browser_sync",
+    "//components/sessions",
+    "//components/signin/core/browser",
+    "//components/sync",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/app/theme",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/metrics:metrics_internal",
+    "//ios/chrome/browser/sessions",
+    "//ios/chrome/browser/sessions:sessions_internal",
+    "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/sync",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/context_menu",
+    "//ios/chrome/browser/ui/ntp",
+    "//ios/chrome/browser/ui/ntp/recent_tabs/views",
+    "//ios/web",
+    "//ui/base",
+    "//url",
+  ]
+  public_deps = [
+    "//components/sync_sessions",
+  ]
+  allow_circular_includes_from =
+      [ "//ios/chrome/browser/ui/ntp/recent_tabs/views" ]
+  libs = [ "UIKit.framework" ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "recent_tabs_panel_controller_unittest.mm",
+  ]
+  deps = [
+    ":recent_tabs",
+    "//base",
+    "//components/browser_sync",
+    "//components/browser_sync:test_support",
+    "//components/signin/core/browser",
+    "//components/sync_sessions",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/sync",
+    "//ios/chrome/browser/sync:test_support",
+    "//ios/chrome/browser/ui/ntp:ntp_internal",
+    "//ios/chrome/test:test_support",
+    "//ios/web:test_support",
+    "//testing/gtest",
+    "//third_party/ocmock",
+  ]
+}
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "recent_tabs_panel_controller_egtest.mm",
+  ]
+  deps = [
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/tools_menu",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/third_party/earl_grey",
+    "//ios/web:test_support",
+  ]
+  libs = [ "XCTest.framework" ]
+}
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/views/BUILD.gn b/ios/chrome/browser/ui/ntp/recent_tabs/views/BUILD.gn
new file mode 100644
index 0000000..2a203c2
--- /dev/null
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/views/BUILD.gn
@@ -0,0 +1,52 @@
+# 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.
+
+source_set("views") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [
+    "disclosure_view.h",
+    "disclosure_view.mm",
+    "generic_section_header_view.h",
+    "generic_section_header_view.mm",
+    "header_of_collapsable_section_protocol.h",
+    "panel_bar_view.h",
+    "panel_bar_view.mm",
+    "session_section_header_view.h",
+    "session_section_header_view.mm",
+    "session_tab_data_view.h",
+    "session_tab_data_view.mm",
+    "show_full_history_view.h",
+    "show_full_history_view.mm",
+    "signed_in_sync_in_progress_view.h",
+    "signed_in_sync_in_progress_view.mm",
+    "signed_in_sync_off_view.h",
+    "signed_in_sync_off_view.mm",
+    "signed_in_sync_on_no_sessions_view.h",
+    "signed_in_sync_on_no_sessions_view.mm",
+    "signed_out_view.h",
+    "signed_out_view.mm",
+    "spacers_view.h",
+    "spacers_view.mm",
+    "views_utils.h",
+    "views_utils.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/resources",
+    "//components/sessions",
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/favicon",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/fancy_ui",
+    "//ios/chrome/browser/ui/material_components",
+    "//ios/chrome/browser/ui/sync",
+    "//ios/chrome/browser/ui/tab_switcher:utils",
+    "//ios/third_party/material_components_ios",
+    "//ios/third_party/material_roboto_font_loader_ios",
+    "//ui/base",
+  ]
+  libs = [ "UIKit.framework" ]
+}
diff --git a/ios/chrome/browser/ui/omnibox/BUILD.gn b/ios/chrome/browser/ui/omnibox/BUILD.gn
index 8deca11..7bf0059 100644
--- a/ios/chrome/browser/ui/omnibox/BUILD.gn
+++ b/ios/chrome/browser/ui/omnibox/BUILD.gn
@@ -30,3 +30,109 @@
     "{{bundle_resources_dir}}/{{source_file_part}}",
   ]
 }
+
+source_set("omnibox_internal") {
+  sources = [
+    "chrome_omnibox_client_ios.h",
+    "chrome_omnibox_client_ios.mm",
+    "location_bar_view_ios.h",
+    "location_bar_view_ios.mm",
+    "omnibox_popup_material_row.h",
+    "omnibox_popup_material_row.mm",
+    "omnibox_popup_material_view_controller.h",
+    "omnibox_popup_material_view_controller.mm",
+    "omnibox_popup_positioner.h",
+    "omnibox_popup_view_ios.h",
+    "omnibox_popup_view_ios.mm",
+    "omnibox_text_field_ios.h",
+    "omnibox_text_field_ios.mm",
+    "omnibox_view_ios.h",
+    "omnibox_view_ios.mm",
+    "page_info_model.cc",
+    "page_info_model.h",
+    "page_info_model_observer.h",
+    "page_info_view_controller.h",
+    "page_info_view_controller.mm",
+    "preload_provider.h",
+    "truncating_attributed_label.h",
+    "truncating_attributed_label.mm",
+  ]
+  deps = [
+    "//base",
+    "//base:i18n",
+    "//components/favicon/ios",
+    "//components/keyed_service/core",
+    "//components/open_from_clipboard",
+    "//components/resources",
+    "//components/search_engines",
+    "//components/ssl_errors",
+    "//components/strings",
+    "//components/toolbar",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/app/theme",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/autocomplete",
+    "//ios/chrome/browser/bookmarks",
+    "//ios/chrome/browser/bookmarks:bookmarks_utils",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/net",
+    "//ios/chrome/browser/search_engines",
+    "//ios/chrome/browser/sessions",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/fancy_ui",
+    "//ios/chrome/browser/ui/omnibox",
+    "//ios/chrome/browser/ui/omnibox:resources",
+    "//ios/chrome/browser/ui/popup_menu",
+    "//ios/chrome/common",
+    "//ios/public/provider/chrome/browser",
+    "//ios/third_party/material_components_ios",
+    "//ios/third_party/material_roboto_font_loader_ios",
+    "//ios/web",
+    "//ios/web/public/image_fetcher",
+    "//net",
+    "//skia",
+    "//third_party/google_toolbox_for_mac",
+    "//ui/base",
+    "//ui/gfx",
+    "//ui/gfx/geometry",
+    "//url",
+  ]
+  public_deps = [
+    "//components/omnibox/browser",
+  ]
+  libs = [
+    "CoreText.framework",
+    "MobileCoreServices.framework",
+    "QuartzCore.framework",
+    "UIKit.framework",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "omnibox_text_field_ios_unittest.mm",
+  ]
+  deps = [
+    ":omnibox_internal",
+    ":resources_unit_tests",
+    "//base",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//testing/gtest",
+    "//ui/base",
+  ]
+}
+
+bundle_data("resources_unit_tests") {
+  visibility = [ ":unit_tests" ]
+  testonly = true
+  sources = [
+    "//ios/chrome/test/data/omnibox/selected_ranges.txt",
+  ]
+  outputs = [
+    "{{bundle_resources_dir}}/" +
+        "ios/chrome/test/data/omnibox/{{source_file_part}}",
+  ]
+}
diff --git a/ios/chrome/browser/ui/overscroll_actions/BUILD.gn b/ios/chrome/browser/ui/overscroll_actions/BUILD.gn
index 5a3642f..ab71ac6 100644
--- a/ios/chrome/browser/ui/overscroll_actions/BUILD.gn
+++ b/ios/chrome/browser/ui/overscroll_actions/BUILD.gn
@@ -27,3 +27,29 @@
     "{{bundle_resources_dir}}/{{source_file_part}}",
   ]
 }
+
+source_set("overscroll_actions") {
+  sources = [
+    "overscroll_actions_controller.h",
+    "overscroll_actions_controller.mm",
+    "overscroll_actions_view.h",
+    "overscroll_actions_view.mm",
+  ]
+  deps = [
+    "//base",
+    "//ios/chrome/app/theme",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/overscroll_actions:resources",
+    "//ios/chrome/browser/ui/static_content",
+    "//ios/chrome/browser/ui/toolbar",
+    "//ios/chrome/browser/ui/util",
+    "//ios/chrome/browser/ui/voice",
+    "//ios/web",
+    "//ui/base",
+  ]
+  allow_circular_includes_from = [ "//ios/chrome/browser/ui/static_content" ]
+  libs = [
+    "QuartzCore.framework",
+    "UIKit.framework",
+  ]
+}
diff --git a/ios/chrome/browser/ui/popup_menu/BUILD.gn b/ios/chrome/browser/ui/popup_menu/BUILD.gn
index 7ac0c67..7d59bd4a 100644
--- a/ios/chrome/browser/ui/popup_menu/BUILD.gn
+++ b/ios/chrome/browser/ui/popup_menu/BUILD.gn
@@ -12,3 +12,24 @@
     "{{bundle_resources_dir}}/{{source_file_part}}",
   ]
 }
+
+source_set("popup_menu") {
+  sources = [
+    "popup_menu_controller.h",
+    "popup_menu_controller.mm",
+    "popup_menu_view.h",
+    "popup_menu_view.mm",
+  ]
+  deps = [
+    "//base",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/popup_menu:resources",
+    "//ios/chrome/common",
+    "//ui/base",
+  ]
+  libs = [
+    "QuartzCore.framework",
+    "UIKit.framework",
+  ]
+}
diff --git a/ios/chrome/browser/ui/presenters/BUILD.gn b/ios/chrome/browser/ui/presenters/BUILD.gn
new file mode 100644
index 0000000..99e39183
--- /dev/null
+++ b/ios/chrome/browser/ui/presenters/BUILD.gn
@@ -0,0 +1,13 @@
+# 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.
+
+source_set("presenters") {
+  sources = [
+    "menu_presentation_controller.h",
+    "menu_presentation_controller.mm",
+    "menu_presentation_delegate.h",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+}
diff --git a/ios/chrome/browser/ui/print/BUILD.gn b/ios/chrome/browser/ui/print/BUILD.gn
new file mode 100644
index 0000000..3b1f3ad
--- /dev/null
+++ b/ios/chrome/browser/ui/print/BUILD.gn
@@ -0,0 +1,42 @@
+# 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.
+
+source_set("print") {
+  sources = [
+    "print_controller.h",
+    "print_controller.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui/alert_coordinator",
+    "//ios/chrome/browser/ui/alert_coordinator:alert_coordinator_internal",
+    "//ios/web",
+    "//net",
+    "//ui/base",
+  ]
+  libs = [ "UIKit.framework" ]
+}
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "print_controller_egtest.mm",
+  ]
+  deps = [
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/third_party/earl_grey",
+    "//ios/web:test_support",
+    "//ui/base",
+    "//url",
+  ]
+  libs = [
+    "UIKit.framework",
+    "XCTest.framework",
+  ]
+}
diff --git a/ios/chrome/browser/ui/promos/BUILD.gn b/ios/chrome/browser/ui/promos/BUILD.gn
new file mode 100644
index 0000000..655326c
--- /dev/null
+++ b/ios/chrome/browser/ui/promos/BUILD.gn
@@ -0,0 +1,49 @@
+# 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.
+
+source_set("promos") {
+  sources = [
+    "promo_view_controller.h",
+    "signin_promo_view_controller.h",
+    "signin_promo_view_controller.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/signin/core/browser",
+    "//components/version_info",
+    "//ios/chrome/app:tests_hook",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/ui/authentication",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser/signin",
+    "//net",
+  ]
+  libs = [ "UIKit.framework" ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "signin_promo_view_controller_unittest.mm",
+  ]
+  deps = [
+    ":promos",
+    "//base",
+    "//components/pref_registry",
+    "//components/sync_preferences",
+    "//components/sync_preferences:test_support",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/prefs:browser_prefs",
+    "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/signin:test_support",
+    "//ios/chrome/test:test_support",
+    "//ios/public/provider/chrome/browser/signin:test_support",
+    "//ios/web:test_support",
+    "//testing/gtest",
+    "//third_party/ocmock",
+  ]
+}
diff --git a/ios/chrome/browser/ui/qr_scanner/BUILD.gn b/ios/chrome/browser/ui/qr_scanner/BUILD.gn
index 3fbb672b..8116491 100644
--- a/ios/chrome/browser/ui/qr_scanner/BUILD.gn
+++ b/ios/chrome/browser/ui/qr_scanner/BUILD.gn
@@ -21,3 +21,67 @@
     "{{bundle_resources_dir}}/{{source_file_part}}",
   ]
 }
+
+source_set("qr_scanner") {
+  sources = [
+    "camera_controller.h",
+    "camera_controller.mm",
+    "qr_scanner_alerts.h",
+    "qr_scanner_alerts.mm",
+    "qr_scanner_transitioning_delegate.h",
+    "qr_scanner_transitioning_delegate.mm",
+    "qr_scanner_view.h",
+    "qr_scanner_view.mm",
+    "qr_scanner_view_controller.h",
+    "qr_scanner_view_controller.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/version_info",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/icons",
+    "//ios/chrome/browser/ui/qr_scanner:assets",
+    "//ios/chrome/common:ios_app_bundle_id_prefix_header",
+    "//ios/third_party/material_components_ios",
+    "//ui/base",
+  ]
+  libs = [
+    "AVFoundation.framework",
+    "UIKit.framework",
+  ]
+}
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "qr_scanner_view_controller_egtest.mm",
+  ]
+  deps = [
+    "//base",
+    "//base/test:test_support",
+    "//components/strings",
+    "//components/version_info",
+    "//ios/chrome/app:app_internal",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/ui:ui_internal",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/icons",
+    "//ios/chrome/browser/ui/qr_scanner",
+    "//ios/chrome/browser/ui/toolbar",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/base",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/testing/earl_grey:earl_grey_support",
+    "//ios/third_party/earl_grey",
+    "//ios/web:test_support",
+    "//third_party/ocmock",
+    "//ui/base",
+  ]
+  libs = [
+    "AVFoundation.framework",
+    "UIKit.framework",
+  ]
+}
diff --git a/ios/chrome/browser/ui/reader_mode/BUILD.gn b/ios/chrome/browser/ui/reader_mode/BUILD.gn
new file mode 100644
index 0000000..4916f60
--- /dev/null
+++ b/ios/chrome/browser/ui/reader_mode/BUILD.gn
@@ -0,0 +1,31 @@
+# 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.
+
+source_set("reader_mode") {
+  sources = [
+    "reader_mode_checker.h",
+    "reader_mode_checker.mm",
+    "reader_mode_controller.h",
+    "reader_mode_controller.mm",
+    "reader_mode_infobar_delegate.h",
+    "reader_mode_infobar_delegate.mm",
+    "reader_mode_view.h",
+    "reader_mode_view.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/dom_distiller/core",
+    "//components/infobars/core",
+    "//components/resources",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/dom_distiller",
+    "//ios/chrome/browser/infobars",
+    "//ios/chrome/browser/ui/material_components",
+    "//ios/third_party/material_components_ios",
+    "//ios/web",
+    "//ui/base",
+    "//url",
+  ]
+  libs = [ "UIKit.framework" ]
+}
diff --git a/ios/chrome/browser/ui/reading_list/BUILD.gn b/ios/chrome/browser/ui/reading_list/BUILD.gn
index 7a673fd..924867c 100644
--- a/ios/chrome/browser/ui/reading_list/BUILD.gn
+++ b/ios/chrome/browser/ui/reading_list/BUILD.gn
@@ -24,3 +24,107 @@
     "{{bundle_resources_dir}}/{{source_file_part}}",
   ]
 }
+
+source_set("reading_list") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [
+    "number_badge_view.h",
+    "number_badge_view.mm",
+    "offline_page_native_content.h",
+    "offline_page_native_content.mm",
+    "reading_list_collection_view_item.h",
+    "reading_list_collection_view_item.mm",
+    "reading_list_menu_notification_delegate.h",
+    "reading_list_menu_notifier.h",
+    "reading_list_menu_notifier.mm",
+    "reading_list_side_swipe_provider.h",
+    "reading_list_side_swipe_provider.mm",
+    "reading_list_toolbar.h",
+    "reading_list_toolbar.mm",
+    "reading_list_view_controller.h",
+    "reading_list_view_controller.mm",
+    "reading_list_view_controller_builder.h",
+    "reading_list_view_controller_builder.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/prefs",
+    "//components/reading_list/core",
+    "//components/strings",
+    "//components/url_formatter",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/favicon",
+    "//ios/chrome/browser/reading_list",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/alert_coordinator",
+    "//ios/chrome/browser/ui/collection_view/cells",
+    "//ios/chrome/browser/ui/colors",
+    "//ios/chrome/browser/ui/material_components",
+    "//ios/chrome/browser/ui/reading_list:resources",
+    "//ios/chrome/browser/ui/side_swipe",
+    "//ios/chrome/browser/ui/static_content",
+    "//ios/chrome/common",
+    "//ios/third_party/material_components_ios",
+    "//ios/third_party/material_roboto_font_loader_ios",
+    "//ios/web",
+    "//net",
+    "//ui/base",
+    "//url",
+  ]
+  public_deps = [
+    "//components/reading_list/ios",
+    "//ios/chrome/browser/ui/collection_view",
+  ]
+  allow_circular_includes_from = [ "//ios/chrome/browser/ui/side_swipe" ]
+  libs = [ "UIKit.framework" ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "offline_page_native_content_unittest.mm",
+    "reading_list_view_controller_unittest.mm",
+  ]
+  deps = [
+    ":reading_list",
+    "//base",
+    "//components/favicon/core",
+    "//components/prefs",
+    "//components/reading_list/ios",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/favicon",
+    "//ios/chrome/browser/reading_list",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/static_content",
+    "//ios/web",
+    "//ios/web:test_support",
+    "//testing/gtest",
+    "//third_party/ocmock",
+  ]
+}
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "reading_list_egtest.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/reading_list/ios",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/reading_list",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/testing:ios_test_support",
+    "//ios/third_party/earl_grey",
+  ]
+  libs = [
+    "UIKit.framework",
+    "XCTest.framework",
+  ]
+}
diff --git a/ios/chrome/browser/ui/sad_tab/BUILD.gn b/ios/chrome/browser/ui/sad_tab/BUILD.gn
new file mode 100644
index 0000000..7b92411f
--- /dev/null
+++ b/ios/chrome/browser/ui/sad_tab/BUILD.gn
@@ -0,0 +1,27 @@
+# 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.
+
+source_set("sad_tab") {
+  sources = [
+    "sad_tab_view.h",
+    "sad_tab_view.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/resources",
+    "//components/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/colors",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/util",
+    "//ios/third_party/material_components_ios",
+    "//ios/third_party/material_roboto_font_loader_ios",
+    "//ios/web",
+    "//net",
+    "//ui/base",
+    "//ui/gfx",
+  ]
+  libs = [ "UIKit.framework" ]
+}
diff --git a/ios/chrome/browser/ui/settings/BUILD.gn b/ios/chrome/browser/ui/settings/BUILD.gn
index c006f69..e358659 100644
--- a/ios/chrome/browser/ui/settings/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/BUILD.gn
@@ -24,3 +24,360 @@
     "{{bundle_resources_dir}}/{{source_file_part}}",
   ]
 }
+
+source_set("settings") {
+  sources = [
+    "about_chrome_collection_view_controller.h",
+    "about_chrome_collection_view_controller.mm",
+    "accounts_collection_view_controller.h",
+    "accounts_collection_view_controller.mm",
+    "autofill_collection_view_controller.h",
+    "autofill_collection_view_controller.mm",
+    "autofill_credit_card_edit_collection_view_controller.h",
+    "autofill_credit_card_edit_collection_view_controller.mm",
+    "autofill_edit_accessory_view.h",
+    "autofill_edit_accessory_view.mm",
+    "autofill_edit_collection_view_controller.h",
+    "autofill_edit_collection_view_controller.mm",
+    "autofill_profile_edit_collection_view_controller.h",
+    "autofill_profile_edit_collection_view_controller.mm",
+    "bandwidth_management_collection_view_controller.h",
+    "bandwidth_management_collection_view_controller.mm",
+    "bar_button_activity_indicator.h",
+    "bar_button_activity_indicator.mm",
+    "block_popups_collection_view_controller.h",
+    "block_popups_collection_view_controller.mm",
+    "clear_browsing_data_collection_view_controller.h",
+    "clear_browsing_data_collection_view_controller.mm",
+    "content_settings_collection_view_controller.h",
+    "content_settings_collection_view_controller.mm",
+    "contextual_search_collection_view_controller.h",
+    "contextual_search_collection_view_controller.mm",
+    "dataplan_usage_collection_view_controller.h",
+    "dataplan_usage_collection_view_controller.mm",
+    "do_not_track_collection_view_controller.h",
+    "do_not_track_collection_view_controller.mm",
+    "handoff_collection_view_controller.h",
+    "handoff_collection_view_controller.mm",
+    "import_data_collection_view_controller.h",
+    "import_data_collection_view_controller.mm",
+    "material_cell_catalog_view_controller.h",
+    "material_cell_catalog_view_controller.mm",
+    "native_apps_collection_view_controller.h",
+    "native_apps_collection_view_controller.mm",
+    "native_apps_collection_view_controller_private.h",
+    "password_details_collection_view_controller.h",
+    "password_details_collection_view_controller.mm",
+    "physical_web_collection_view_controller.h",
+    "physical_web_collection_view_controller.mm",
+    "privacy_collection_view_controller.h",
+    "privacy_collection_view_controller.mm",
+    "reauthentication_module.h",
+    "reauthentication_module.mm",
+    "reauthentication_protocol.h",
+    "save_passwords_collection_view_controller.h",
+    "save_passwords_collection_view_controller.mm",
+    "search_engine_settings_collection_view_controller.h",
+    "search_engine_settings_collection_view_controller.mm",
+    "settings_collection_view_controller.h",
+    "settings_collection_view_controller.mm",
+    "settings_navigation_controller.h",
+    "settings_navigation_controller.mm",
+    "settings_root_collection_view_controller.h",
+    "settings_root_collection_view_controller.mm",
+    "settings_utils.h",
+    "settings_utils.mm",
+    "sync_create_passphrase_collection_view_controller.h",
+    "sync_create_passphrase_collection_view_controller.mm",
+    "sync_encryption_collection_view_controller.h",
+    "sync_encryption_collection_view_controller.mm",
+    "sync_encryption_passphrase_collection_view_controller.h",
+    "sync_encryption_passphrase_collection_view_controller.mm",
+    "sync_settings_collection_view_controller.h",
+    "sync_settings_collection_view_controller.mm",
+    "time_range_selector_collection_view_controller.h",
+    "time_range_selector_collection_view_controller.mm",
+    "translate_collection_view_controller.h",
+    "translate_collection_view_controller.mm",
+    "voicesearch_collection_view_controller.h",
+    "voicesearch_collection_view_controller.mm",
+  ]
+  deps = [
+    "//base",
+    "//base:i18n",
+    "//components/autofill/core/browser",
+    "//components/autofill/core/common",
+    "//components/autofill/ios/browser",
+    "//components/browser_sync",
+    "//components/browsing_data/core",
+    "//components/content_settings/core/browser",
+    "//components/content_settings/core/common",
+    "//components/google/core/browser",
+    "//components/handoff",
+    "//components/history/core/browser",
+    "//components/keyed_service/core",
+    "//components/metrics",
+    "//components/password_manager/core/browser",
+    "//components/password_manager/core/common",
+    "//components/physical_web/data_source",
+    "//components/prefs",
+    "//components/resources",
+    "//components/search_engines",
+    "//components/signin/core/browser",
+    "//components/signin/core/common",
+    "//components/signin/ios/browser",
+    "//components/strings",
+    "//components/sync",
+    "//components/translate/core/browser",
+    "//components/translate/core/common",
+    "//components/url_formatter",
+    "//components/version_info",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/autofill",
+    "//ios/chrome/browser/autofill:autofill_internal",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/browser_state:browser_state_impl",
+    "//ios/chrome/browser/browsing_data",
+    "//ios/chrome/browser/content_settings",
+    "//ios/chrome/browser/history",
+    "//ios/chrome/browser/native_app_launcher:native_app_launcher_internal",
+    "//ios/chrome/browser/passwords",
+    "//ios/chrome/browser/physical_web",
+    "//ios/chrome/browser/prefs",
+    "//ios/chrome/browser/search_engines",
+    "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/sync",
+    "//ios/chrome/browser/translate",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/alert_coordinator",
+    "//ios/chrome/browser/ui/authentication",
+    "//ios/chrome/browser/ui/autofill/cells",
+    "//ios/chrome/browser/ui/collection_view",
+    "//ios/chrome/browser/ui/colors",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/contextual_search",
+    "//ios/chrome/browser/ui/icons",
+    "//ios/chrome/browser/ui/keyboard",
+    "//ios/chrome/browser/ui/material_components",
+    "//ios/chrome/browser/ui/settings:resources",
+    "//ios/chrome/browser/ui/settings/cells",
+    "//ios/chrome/browser/ui/settings/utils",
+    "//ios/chrome/browser/ui/sync",
+    "//ios/chrome/browser/voice",
+    "//ios/chrome/common",
+    "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser/images",
+    "//ios/public/provider/chrome/browser/native_app_launcher",
+    "//ios/public/provider/chrome/browser/signin",
+    "//ios/public/provider/chrome/browser/user_feedback",
+    "//ios/public/provider/chrome/browser/voice",
+    "//ios/third_party/material_components_ios",
+    "//ios/third_party/material_roboto_font_loader_ios",
+    "//ios/web",
+    "//net",
+    "//ui/base",
+    "//url",
+  ]
+  public_deps = [
+    "//ios/chrome/browser/ui/collection_view/cells",
+  ]
+  allow_circular_includes_from = [ "//ios/chrome/browser/ui/authentication" ]
+  libs = [
+    "CoreLocation.framework",
+    "LocalAuthentication.framework",
+    "StoreKit.framework",
+    "UIKit.framework",
+  ]
+}
+
+source_set("test_support") {
+  testonly = true
+  sources = [
+    "passphrase_collection_view_controller_test.h",
+    "passphrase_collection_view_controller_test.mm",
+  ]
+  deps = [
+    ":settings",
+    "//base",
+    "//components/browser_sync",
+    "//components/browser_sync:test_support",
+    "//components/keyed_service/core",
+    "//components/pref_registry",
+    "//components/sync",
+    "//components/sync_preferences",
+    "//components/sync_preferences:test_support",
+    "//google_apis",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/prefs:browser_prefs",
+    "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/signin:test_support",
+    "//ios/chrome/browser/sync",
+    "//ios/chrome/browser/sync:test_support",
+    "//ios/chrome/browser/ui/collection_view:test_support",
+    "//ios/public/provider/chrome/browser/signin:test_support",
+    "//ios/web:test_support",
+    "//testing/gtest",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "about_chrome_collection_view_controller_unittest.mm",
+    "autofill_collection_view_controller_unittest.mm",
+    "autofill_profile_edit_collection_view_controller_unittest.mm",
+    "bandwidth_management_collection_view_controller_unittest.mm",
+    "block_popups_collection_view_controller_unittest.mm",
+    "clear_browsing_data_collection_view_controller_unittest.mm",
+    "content_settings_collection_view_controller_unittest.mm",
+    "contextual_search_collection_view_controller_unittest.mm",
+    "dataplan_usage_collection_view_controller_unittest.mm",
+    "do_not_track_collection_view_controller_unittest.mm",
+    "import_data_collection_view_controller_unittest.mm",
+    "native_apps_collection_view_controller_unittest.mm",
+    "password_details_collection_view_controller_unittest.mm",
+    "physical_web_collection_view_controller_unittest.mm",
+    "privacy_collection_view_controller_unittest.mm",
+    "save_passwords_collection_view_controller_unittest.mm",
+    "search_engine_settings_collection_view_controller_unittest.mm",
+    "settings_navigation_controller_unittest.mm",
+    "settings_root_collection_view_controller_unittest.mm",
+    "sync_create_passphrase_collection_view_controller_unittest.mm",
+    "sync_encryption_collection_view_controller_unittest.mm",
+    "sync_encryption_passphrase_collection_view_controller_unittest.mm",
+    "sync_settings_collection_view_controller_unittest.mm",
+    "time_range_selector_collection_view_controller_unittest.mm",
+    "translate_collection_view_controller_unittest.mm",
+    "voicesearch_collection_view_controller_unittest.mm",
+  ]
+  deps = [
+    ":settings",
+    ":test_support",
+    "//base",
+    "//base/test:test_support",
+    "//components/autofill/core/browser",
+    "//components/autofill/core/common",
+    "//components/browser_sync:test_support",
+    "//components/browsing_data/core",
+    "//components/content_settings/core/browser",
+    "//components/google/core/browser",
+    "//components/handoff",
+    "//components/password_manager/core/browser:test_support",
+    "//components/pref_registry",
+    "//components/prefs:test_support",
+    "//components/search_engines",
+    "//components/signin/core/browser:test_support",
+    "//components/strings",
+    "//components/sync_preferences",
+    "//components/sync_preferences:test_support",
+    "//components/translate/core/browser",
+    "//components/translate/core/common",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/autofill",
+    "//ios/chrome/browser/autofill:autofill_internal",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/browsing_data",
+    "//ios/chrome/browser/content_settings",
+    "//ios/chrome/browser/passwords",
+    "//ios/chrome/browser/physical_web",
+    "//ios/chrome/browser/prefs:browser_prefs",
+    "//ios/chrome/browser/search_engines",
+    "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/signin:test_support",
+    "//ios/chrome/browser/sync",
+    "//ios/chrome/browser/sync:test_support",
+    "//ios/chrome/browser/translate",
+    "//ios/chrome/browser/ui/collection_view",
+    "//ios/chrome/browser/ui/collection_view:test_support",
+    "//ios/chrome/browser/ui/collection_view/cells",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/contextual_search",
+    "//ios/chrome/browser/ui/icons",
+    "//ios/chrome/browser/ui/settings/cells",
+    "//ios/chrome/browser/ui/sync",
+    "//ios/chrome/browser/voice",
+    "//ios/chrome/browser/web:test_support",
+    "//ios/chrome/common",
+    "//ios/chrome/test:test_support",
+    "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser/native_app_launcher:test_support",
+    "//ios/public/provider/chrome/browser/voice",
+    "//ios/third_party/material_components_ios",
+    "//ios/web",
+    "//ios/web:test_support",
+    "//net",
+    "//net:test_support",
+    "//testing/gmock",
+    "//testing/gtest",
+    "//third_party/ocmock",
+    "//ui/base",
+    "//url",
+  ]
+}
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "accounts_collection_egtest.mm",
+    "autofill_settings_egtest.mm",
+    "block_popups_egtest.mm",
+    "clear_browsing_data_egtest.mm",
+    "settings_egtest.mm",
+    "translate_ui_egtest.mm",
+  ]
+
+  deps = [
+    "//base",
+    "//components/browsing_data/core",
+    "//components/content_settings/core/browser",
+    "//components/metrics",
+    "//components/password_manager/core/common",
+    "//components/prefs",
+    "//components/search_engines",
+    "//components/signin/core/browser",
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/app/theme",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/content_settings",
+    "//ios/chrome/browser/search_engines",
+    "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/ui/settings",
+    "//ios/chrome/browser/ui/tools_menu",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/public/provider/chrome/browser/signin:test_support",
+    "//ios/testing/earl_grey:earl_grey_support",
+    "//ios/third_party/earl_grey",
+    "//ios/web",
+    "//ios/web:test_support",
+    "//net",
+    "//ui/base",
+    "//url",
+  ]
+  libs = [
+    "UIKit.framework",
+    "XCTest.framework",
+  ]
+}
+
+# Clean Skeleton targets.
+source_set("settings_clean_skeleton") {
+  sources = [
+    "settings_coordinator.h",
+    "settings_coordinator.mm",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+
+  deps = [
+    ":settings",
+    "//ios/chrome/browser:browser_clean_skeleton",
+    "//ios/chrome/browser/ui/actions",
+  ]
+}
diff --git a/ios/chrome/browser/ui/settings/cells/BUILD.gn b/ios/chrome/browser/ui/settings/cells/BUILD.gn
new file mode 100644
index 0000000..74d8d7c5
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/cells/BUILD.gn
@@ -0,0 +1,87 @@
+# 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.
+
+source_set("cells") {
+  sources = [
+    "account_control_item.h",
+    "account_control_item.mm",
+    "account_signin_item.h",
+    "account_signin_item.mm",
+    "autofill_data_item.h",
+    "autofill_data_item.mm",
+    "autofill_edit_item.h",
+    "autofill_edit_item.mm",
+    "byo_textfield_item.h",
+    "byo_textfield_item.mm",
+    "card_multiline_item.h",
+    "card_multiline_item.mm",
+    "copied_to_chrome_item.h",
+    "copied_to_chrome_item.mm",
+    "encryption_item.h",
+    "encryption_item.mm",
+    "import_data_multiline_detail_cell.h",
+    "import_data_multiline_detail_cell.mm",
+    "native_app_item.h",
+    "native_app_item.mm",
+    "passphrase_error_item.h",
+    "passphrase_error_item.mm",
+    "password_details_item.h",
+    "password_details_item.mm",
+    "sync_switch_item.h",
+    "sync_switch_item.mm",
+    "text_and_error_item.h",
+    "text_and_error_item.mm",
+    "version_item.h",
+    "version_item.mm",
+  ]
+
+  deps = [
+    "//components/autofill/core/browser",
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/collection_view/cells",
+    "//ios/chrome/browser/ui/colors",
+    "//ios/third_party/material_components_ios",
+    "//ios/third_party/material_roboto_font_loader_ios",
+    "//ui/base",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "account_control_item_unittest.mm",
+    "account_signin_item_unittest.mm",
+    "autofill_data_item_unittest.mm",
+    "autofill_edit_item_unittest.mm",
+    "byo_textfield_item_unittest.mm",
+    "card_multiline_item_unittest.mm",
+    "copied_to_chrome_item_unittest.mm",
+    "encryption_item_unittest.mm",
+    "import_data_multiline_detail_cell_unittest.mm",
+    "native_app_item_unittest.mm",
+    "passphrase_error_item_unittest.mm",
+    "password_details_item_unittest.mm",
+    "sync_switch_item_unittest.mm",
+    "text_and_error_item_unittest.mm",
+    "version_item_unittest.mm",
+  ]
+
+  deps = [
+    ":cells",
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui/collection_view/cells",
+    "//ios/chrome/browser/ui/collection_view/cells:test_support",
+    "//ios/chrome/browser/ui/colors",
+    "//ios/third_party/material_components_ios",
+    "//testing/gtest",
+    "//ui/base",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+}
diff --git a/ios/chrome/browser/ui/settings/utils/BUILD.gn b/ios/chrome/browser/ui/settings/utils/BUILD.gn
new file mode 100644
index 0000000..3f450298
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/utils/BUILD.gn
@@ -0,0 +1,57 @@
+# 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.
+
+source_set("utils") {
+  sources = [
+    "content_setting_backed_boolean.h",
+    "content_setting_backed_boolean.mm",
+    "observable_boolean.h",
+    "pref_backed_boolean.h",
+    "pref_backed_boolean.mm",
+    "resized_avatar_cache.h",
+    "resized_avatar_cache.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/content_settings/core/browser",
+    "//components/content_settings/core/common",
+    "//components/prefs",
+    "//ios/chrome/browser/ui",
+    "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser/signin",
+  ]
+}
+
+source_set("test_support") {
+  testonly = true
+  sources = [
+    "fake_observable_boolean.h",
+    "fake_observable_boolean.mm",
+  ]
+  deps = [
+    ":utils",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "content_setting_backed_boolean_unittest.mm",
+    "pref_backed_boolean_unittest.mm",
+  ]
+  deps = [
+    ":test_support",
+    ":utils",
+    "//base",
+    "//components/content_settings/core/browser",
+    "//components/content_settings/core/common",
+    "//components/prefs",
+    "//components/prefs:test_support",
+    "//components/sync_preferences:test_support",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/content_settings",
+    "//ios/web:test_support",
+    "//testing/gtest",
+  ]
+}
diff --git a/ios/chrome/browser/ui/side_swipe/BUILD.gn b/ios/chrome/browser/ui/side_swipe/BUILD.gn
index 0b2f874..404b0f6 100644
--- a/ios/chrome/browser/ui/side_swipe/BUILD.gn
+++ b/ios/chrome/browser/ui/side_swipe/BUILD.gn
@@ -15,3 +15,57 @@
     "{{bundle_resources_dir}}/{{source_file_part}}",
   ]
 }
+
+source_set("side_swipe") {
+  sources = [
+    "card_side_swipe_view.h",
+    "card_side_swipe_view.mm",
+    "history_side_swipe_provider.h",
+    "history_side_swipe_provider.mm",
+    "side_swipe_controller.h",
+    "side_swipe_controller.mm",
+    "side_swipe_navigation_view.h",
+    "side_swipe_navigation_view.mm",
+    "side_swipe_util.h",
+    "side_swipe_util.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/reading_list/core",
+    "//components/reading_list/ios",
+    "//ios/chrome/app/theme",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/reading_list",
+    "//ios/chrome/browser/snapshots",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/ntp",
+    "//ios/chrome/browser/ui/side_swipe:resources",
+    "//ios/chrome/browser/ui/tabs",
+    "//ios/chrome/common",
+    "//ios/web",
+    "//ui/base",
+    "//url",
+  ]
+  public_deps = [
+    "//ios/chrome/browser/infobars",
+  ]
+  libs = [ "UIKit.framework" ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "side_swipe_controller_unittest.mm",
+  ]
+  deps = [
+    ":side_swipe",
+    "//base",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/ui/toolbar",
+    "//ios/web:test_support",
+    "//testing/gtest",
+    "//third_party/ocmock",
+  ]
+}
diff --git a/ios/chrome/browser/ui/stack_view/BUILD.gn b/ios/chrome/browser/ui/stack_view/BUILD.gn
index 692c3ac..4df6b3c 100644
--- a/ios/chrome/browser/ui/stack_view/BUILD.gn
+++ b/ios/chrome/browser/ui/stack_view/BUILD.gn
@@ -50,3 +50,119 @@
     "{{bundle_resources_dir}}/{{source_file_part}}",
   ]
 }
+
+source_set("stack_view") {
+  sources = [
+    "card_set.h",
+    "card_set.mm",
+    "card_stack_layout_manager.h",
+    "card_stack_layout_manager.mm",
+    "card_stack_pinch_gesture_recognizer.h",
+    "card_stack_pinch_gesture_recognizer.mm",
+    "card_view.h",
+    "card_view.mm",
+    "close_button.h",
+    "close_button.mm",
+    "page_animation_util.h",
+    "page_animation_util.mm",
+    "stack_card.h",
+    "stack_card.mm",
+    "stack_view_controller.h",
+    "stack_view_controller.mm",
+    "stack_view_controller_private.h",
+    "stack_view_toolbar_controller.h",
+    "stack_view_toolbar_controller.mm",
+    "title_label.h",
+    "title_label.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/keyboard",
+    "//ios/chrome/browser/ui/ntp",
+    "//ios/chrome/browser/ui/ntp:ntp_internal",
+    "//ios/chrome/browser/ui/stack_view:resources",
+    "//ios/chrome/browser/ui/tab_switcher",
+    "//ios/chrome/browser/ui/tabs",
+    "//ios/chrome/browser/ui/toolbar",
+    "//ios/chrome/browser/ui/tools_menu",
+    "//ios/chrome/common",
+    "//ios/third_party/material_components_ios",
+    "//ios/web",
+    "//net",
+    "//ui/base",
+    "//ui/gfx",
+  ]
+  libs = [
+    "CoreGraphics.framework",
+    "QuartzCore.framework",
+    "UIKit.framework",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "card_set_unittest.mm",
+    "card_stack_layout_manager_unittest.mm",
+    "stack_card_unittest.mm",
+    "stack_view_controller_unittest.mm",
+  ]
+  deps = [
+    ":stack_view",
+    "//base",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/test:test_support",
+    "//ios/testing:ocmock_support",
+    "//testing/gtest",
+    "//third_party/ocmock",
+  ]
+}
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "stack_view_egtest.mm",
+  ]
+  deps = [
+    "//base",
+    "//base/test:test_support",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui:ui_internal",
+    "//ios/chrome/browser/ui/stack_view",
+    "//ios/chrome/browser/ui/toolbar",
+    "//ios/chrome/browser/ui/tools_menu",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/testing/earl_grey:earl_grey_support",
+  ]
+  libs = [ "XCTest.framework" ]
+}
+
+source_set("perf_tests") {
+  testonly = true
+  sources = [
+    "stack_view_controller_perftest.mm",
+  ]
+  deps = [
+    "//base",
+    "//base/test:test_support",
+    "//ios/chrome/browser/snapshots",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/test:perf_test_support",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui:ui_internal",
+    "//ios/chrome/browser/ui/stack_view",
+    "//ios/web",
+    "//net",
+  ]
+  libs = [ "UIKit.framework" ]
+}
diff --git a/ios/chrome/browser/ui/static_content/BUILD.gn b/ios/chrome/browser/ui/static_content/BUILD.gn
new file mode 100644
index 0000000..494c90d
--- /dev/null
+++ b/ios/chrome/browser/ui/static_content/BUILD.gn
@@ -0,0 +1,42 @@
+# 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.
+
+source_set("static_content") {
+  sources = [
+    "static_html_native_content.h",
+    "static_html_native_content.mm",
+    "static_html_view_controller.h",
+    "static_html_view_controller.mm",
+  ]
+  deps = [
+    "//base",
+    "//ios/chrome/browser/ui",
+    "//ios/web",
+    "//net",
+    "//ui/base",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "static_html_native_content_unittest.mm",
+    "static_html_view_controller_unittest.mm",
+  ]
+  deps = [
+    ":static_content",
+    "//base",
+    "//base/test:test_support",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/ui",
+    "//ios/testing:ocmock_support",
+    "//ios/web",
+    "//ios/web:test_support",
+    "//net",
+    "//testing/gtest",
+    "//third_party/ocmock",
+    "//ui/base",
+  ]
+}
diff --git a/ios/chrome/browser/ui/sync/BUILD.gn b/ios/chrome/browser/ui/sync/BUILD.gn
new file mode 100644
index 0000000..53aaf3e
--- /dev/null
+++ b/ios/chrome/browser/ui/sync/BUILD.gn
@@ -0,0 +1,61 @@
+# 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.
+
+import("//ios/public/provider/chrome/browser/build_config.gni")
+
+source_set("sync") {
+  sources = [
+    "sync_error_infobar_delegate.h",
+    "sync_error_infobar_delegate.mm",
+    "sync_util.h",
+    "sync_util.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/browser_sync",
+    "//components/infobars/core",
+    "//components/strings",
+    "//components/sync",
+    "//google_apis",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/sync",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui/commands",
+    "//ui/base",
+    "//ui/gfx",
+  ]
+  libs = [ "UIKit.framework" ]
+}
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "sync_fake_server_egtest.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/bookmarks/browser",
+    "//components/browser_sync",
+    "//components/strings",
+    "//components/sync",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/bookmarks",
+    "//ios/chrome/browser/bookmarks:bookmarks_utils",
+    "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/sync",
+    "//ios/chrome/browser/ui/settings",
+    "//ios/chrome/browser/ui/tools_menu",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/public/provider/chrome/browser/signin:test_support",
+    "//ios/testing:ios_test_support",
+    "//ios/third_party/earl_grey",
+    "//ios/web:test_support",
+    "//net",
+    "//ui/base",
+    "//url",
+  ]
+  libs = [ "XCTest.framework" ]
+}
diff --git a/ios/chrome/browser/ui/tab/BUILD.gn b/ios/chrome/browser/ui/tab/BUILD.gn
new file mode 100644
index 0000000..396fb44
--- /dev/null
+++ b/ios/chrome/browser/ui/tab/BUILD.gn
@@ -0,0 +1,25 @@
+# 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.
+
+source_set("tab") {
+  sources = [
+    "tab_container_view_controller.h",
+    "tab_container_view_controller.mm",
+    "tab_coordinator.h",
+    "tab_coordinator.mm",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+
+  deps = [
+    "//base",
+    "//ios/chrome/browser:browser_clean_skeleton",
+    "//ios/chrome/browser/ui:ui_clean_skeleton",
+    "//ios/chrome/browser/ui/animators",
+    "//ios/chrome/browser/ui/presenters",
+    "//ios/chrome/browser/ui/toolbar:toolbar_clean_skeleton",
+    "//ios/chrome/browser/ui/web_contents",
+    "//ios/web",
+  ]
+}
diff --git a/ios/chrome/browser/ui/tab_grid/BUILD.gn b/ios/chrome/browser/ui/tab_grid/BUILD.gn
new file mode 100644
index 0000000..e38eb26e
--- /dev/null
+++ b/ios/chrome/browser/ui/tab_grid/BUILD.gn
@@ -0,0 +1,41 @@
+# 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.
+
+source_set("tab_grid") {
+  sources = [
+    "tab_grid_coordinator.h",
+    "tab_grid_coordinator.mm",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+
+  deps = [
+    ":tab_grid_ui",
+    "//base",
+    "//ios/chrome/browser:browser_clean_skeleton",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/ui/settings:settings_clean_skeleton",
+    "//ios/chrome/browser/ui/tab",
+    "//ios/web",
+    "//net",
+    "//ui/base",
+  ]
+}
+
+source_set("tab_grid_ui") {
+  sources = [
+    "tab_grid_tab_cell.h",
+    "tab_grid_tab_cell.mm",
+    "tab_grid_view_controller.h",
+    "tab_grid_view_controller.mm",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+
+  deps = [
+    "//base",
+    "//ios/chrome/browser/ui/actions",
+    "//ios/chrome/browser/ui/animators",
+  ]
+}
diff --git a/ios/chrome/browser/ui/tab_switcher/BUILD.gn b/ios/chrome/browser/ui/tab_switcher/BUILD.gn
index dfa0ffef..55c1d92 100644
--- a/ios/chrome/browser/ui/tab_switcher/BUILD.gn
+++ b/ios/chrome/browser/ui/tab_switcher/BUILD.gn
@@ -48,3 +48,154 @@
     "{{bundle_resources_dir}}/{{source_file_part}}",
   ]
 }
+
+source_set("tab_switcher") {
+  sources = [
+    "session_changes.h",
+    "session_changes.mm",
+    "tab_model_snapshot.h",
+    "tab_model_snapshot.mm",
+    "tab_switcher.h",
+    "tab_switcher_button.h",
+    "tab_switcher_button.mm",
+    "tab_switcher_cache.h",
+    "tab_switcher_cache.mm",
+    "tab_switcher_controller.h",
+    "tab_switcher_controller.mm",
+    "tab_switcher_header_cell.h",
+    "tab_switcher_header_cell.mm",
+    "tab_switcher_header_view.h",
+    "tab_switcher_header_view.mm",
+    "tab_switcher_model.h",
+    "tab_switcher_model.mm",
+    "tab_switcher_model_private.h",
+    "tab_switcher_panel_cell.h",
+    "tab_switcher_panel_cell.mm",
+    "tab_switcher_panel_collection_view_layout.h",
+    "tab_switcher_panel_collection_view_layout.mm",
+    "tab_switcher_panel_controller.h",
+    "tab_switcher_panel_controller.mm",
+    "tab_switcher_panel_overlay_view.h",
+    "tab_switcher_panel_overlay_view.mm",
+    "tab_switcher_panel_view.h",
+    "tab_switcher_panel_view.mm",
+    "tab_switcher_session_cell_data.h",
+    "tab_switcher_session_cell_data.mm",
+    "tab_switcher_tab_strip_placeholder_view.h",
+    "tab_switcher_tab_strip_placeholder_view.mm",
+    "tab_switcher_transition_context.h",
+    "tab_switcher_transition_context.mm",
+    "tab_switcher_view.h",
+    "tab_switcher_view.mm",
+  ]
+  deps = [
+    ":utils",
+    "//base",
+    "//components/browser_sync",
+    "//components/sessions",
+    "//components/signin/core/browser",
+    "//components/sync",
+    "//components/sync_sessions",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/app/theme",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/favicon",
+    "//ios/chrome/browser/metrics:metrics_internal",
+    "//ios/chrome/browser/sessions",
+    "//ios/chrome/browser/sessions:sessions_internal",
+    "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/sync",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/colors",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/keyboard",
+    "//ios/chrome/browser/ui/material_components",
+    "//ios/chrome/browser/ui/ntp/recent_tabs/views",
+    "//ios/chrome/browser/ui/sync",
+    "//ios/chrome/browser/ui/tab_switcher:resources",
+    "//ios/chrome/browser/ui/tabs",
+    "//ios/chrome/browser/ui/toolbar",
+    "//ios/chrome/common:ios_app_bundle_id_prefix_header",
+    "//ios/public/provider/chrome/browser",
+    "//ios/third_party/material_components_ios",
+    "//ios/third_party/material_roboto_font_loader_ios",
+    "//ios/third_party/material_text_accessibility_ios",
+    "//ios/web",
+    "//ui/base",
+    "//ui/gfx",
+    "//url",
+  ]
+  public_deps = [
+    "//ios/chrome/browser/ui/ntp/recent_tabs",
+  ]
+  allow_circular_includes_from = [ "//ios/chrome/browser/ui/tabs" ]
+  libs = [
+    "QuartzCore.framework",
+    "UIKit.framework",
+  ]
+}
+
+source_set("utils") {
+  sources = [
+    "tab_switcher_utils.h",
+    "tab_switcher_utils.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/browser_sync",
+    "//components/sync",
+    "//components/sync_sessions",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/app/theme",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/favicon",
+    "//ios/chrome/browser/sync",
+    "//ui/base",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "tab_model_snapshot_unittest.mm",
+    "tab_switcher_model_unittest.mm",
+    "tab_switcher_utils_unittest.mm",
+  ]
+  deps = [
+    ":tab_switcher",
+    ":utils",
+    "//base",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui/ntp/recent_tabs",
+    "//testing/gtest",
+    "//third_party/ocmock",
+  ]
+}
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "tab_switcher_controller_egtest.mm",
+  ]
+  deps = [
+    "//base",
+    "//base/test:test_support",
+    "//ios/chrome/app:app_internal",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/tools_menu",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/third_party/earl_grey",
+    "//ui/base",
+  ]
+  libs = [
+    "UIKit.framework",
+    "XCTest.framework",
+  ]
+}
diff --git a/ios/chrome/browser/ui/tabs/BUILD.gn b/ios/chrome/browser/ui/tabs/BUILD.gn
index 8f2fb48..1f607c1 100644
--- a/ios/chrome/browser/ui/tabs/BUILD.gn
+++ b/ios/chrome/browser/ui/tabs/BUILD.gn
@@ -40,3 +40,75 @@
     "{{bundle_resources_dir}}/{{source_file_part}}",
   ]
 }
+
+source_set("tabs") {
+  sources = [
+    "tab_strip_controller+tab_switcher_animation.h",
+    "tab_strip_controller.h",
+    "tab_strip_controller.mm",
+    "tab_strip_controller_private.h",
+    "tab_strip_view.h",
+    "tab_strip_view.mm",
+    "tab_util.h",
+    "tab_util.mm",
+    "tab_view.h",
+    "tab_view.mm",
+    "target_frame_cache.h",
+    "target_frame_cache.mm",
+  ]
+  deps = [
+    "//base",
+    "//base:i18n",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/colors",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/tabs:resources",
+    "//ios/chrome/browser/ui/util",
+    "//ios/third_party/material_components_ios",
+    "//ios/web",
+    "//third_party/google_toolbox_for_mac",
+    "//ui/base",
+    "//ui/gfx",
+  ]
+  libs = [ "UIKit.framework" ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "tab_strip_controller_unittest.mm",
+  ]
+  deps = [
+    ":tabs",
+    "//base",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/sessions:test_support",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui",
+    "//ios/web:test_support",
+    "//testing/gtest",
+    "//third_party/ocmock",
+  ]
+}
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "tab_strip_egtest.mm",
+  ]
+  deps = [
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/tabs",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/third_party/earl_grey",
+    "//ui/base",
+  ]
+  libs = [ "XCTest.framework" ]
+}
diff --git a/ios/chrome/browser/ui/toolbar/BUILD.gn b/ios/chrome/browser/ui/toolbar/BUILD.gn
index a612d73..360b1db6 100644
--- a/ios/chrome/browser/ui/toolbar/BUILD.gn
+++ b/ios/chrome/browser/ui/toolbar/BUILD.gn
@@ -39,3 +39,187 @@
     "{{bundle_resources_dir}}/{{source_file_part}}",
   ]
 }
+
+source_set("toolbar") {
+  sources = [
+    "new_tab_button.h",
+    "new_tab_button.mm",
+    "toolbar_button_tints.h",
+    "toolbar_button_tints.mm",
+    "toolbar_controller+protected.h",
+    "toolbar_controller.h",
+    "toolbar_controller.mm",
+    "toolbar_controller_private.h",
+    "toolbar_model_delegate_ios.h",
+    "toolbar_model_delegate_ios.mm",
+    "toolbar_model_impl_ios.h",
+    "toolbar_model_impl_ios.mm",
+    "toolbar_model_ios.h",
+    "toolbar_owner.h",
+    "toolbar_tools_menu_button.h",
+    "toolbar_tools_menu_button.mm",
+    "tools_menu_button_observer_bridge.h",
+    "tools_menu_button_observer_bridge.mm",
+    "web_toolbar_controller.h",
+    "web_toolbar_controller.mm",
+  ]
+  deps = [
+    ":resource_macros",
+    "//base",
+    "//base:i18n",
+    "//components/bookmarks/browser",
+    "//components/google/core/browser",
+    "//components/omnibox/browser",
+    "//components/prefs",
+    "//components/reading_list/core",
+    "//components/reading_list/ios",
+    "//components/search_engines",
+    "//components/strings",
+    "//components/toolbar",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/app/theme",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/autocomplete",
+    "//ios/chrome/browser/bookmarks",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/reading_list",
+    "//ios/chrome/browser/search_engines",
+    "//ios/chrome/browser/ssl",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/colors",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/fancy_ui",
+    "//ios/chrome/browser/ui/history",
+    "//ios/chrome/browser/ui/keyboard",
+    "//ios/chrome/browser/ui/qr_scanner",
+    "//ios/chrome/browser/ui/toolbar:resources",
+    "//ios/chrome/browser/ui/tools_menu",
+    "//ios/chrome/browser/ui/util",
+    "//ios/chrome/browser/ui/voice",
+    "//ios/chrome/common",
+    "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser/images",
+    "//ios/public/provider/chrome/browser/voice",
+    "//ios/third_party/material_components_ios",
+    "//ios/third_party/material_roboto_font_loader_ios",
+    "//ios/web",
+    "//net",
+    "//ui/base",
+    "//ui/gfx",
+
+    # Fake dependencies to break cycles
+    "//ios/chrome/browser/ui/ntp",
+    "//ios/chrome/browser/ui/side_swipe",
+  ]
+  public_deps = [
+    "//ios/chrome/browser/ui/omnibox:omnibox_internal",
+  ]
+  allow_circular_includes_from = [
+    "//ios/chrome/browser/ui/side_swipe",
+    "//ios/chrome/browser/ui/ntp",
+  ]
+  libs = [
+    "CoreLocation.framework",
+    "UIKit.framework",
+  ]
+}
+
+source_set("resource_macros") {
+  sources = [
+    "toolbar_resource_macros.h",
+  ]
+  deps = [
+    "//ios/chrome/app/theme",
+  ]
+}
+
+source_set("test_support") {
+  testonly = true
+  sources = [
+    "test_toolbar_model_ios.h",
+    "test_toolbar_model_ios.mm",
+    "web_toolbar_controller_private.h",
+  ]
+  deps = [
+    ":toolbar",
+    "//base",
+    "//components/toolbar",
+    "//components/toolbar:test_support",
+    "//ios/chrome/browser/tabs",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "toolbar_controller_unittest.mm",
+    "toolbar_model_impl_ios_unittest.mm",
+    "web_toolbar_controller_unittest.mm",
+  ]
+  deps = [
+    ":test_support",
+    ":toolbar",
+    "//base",
+    "//components/bookmarks/browser",
+    "//components/bookmarks/test",
+    "//components/toolbar:test_support",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/bookmarks",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/test:test_support",
+    "//ios/testing:ocmock_support",
+    "//ios/web:test_support",
+    "//testing/gtest",
+    "//third_party/ocmock",
+  ]
+}
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "toolbar_egtest.mm",
+  ]
+
+  deps = [
+    "//base",
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/ntp:ntp_internal",
+    "//ios/chrome/browser/ui/omnibox:omnibox_internal",
+    "//ios/chrome/browser/ui/toolbar",
+    "//ios/chrome/browser/ui/tools_menu",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/testing/earl_grey:earl_grey_support",
+    "//ios/third_party/earl_grey",
+    "//ios/web:test_support",
+    "//ui/base",
+  ]
+  libs = [ "XCTest.framework" ]
+}
+
+# Clean Skeleton Targets
+source_set("toolbar_clean_skeleton") {
+  sources = [
+    "toolbar_coordinator.h",
+    "toolbar_coordinator.mm",
+    "toolbar_view_controller.h",
+    "toolbar_view_controller.mm",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+
+  deps = [
+    "//base",
+    "//ios/chrome/browser:browser_clean_skeleton",
+    "//ios/chrome/browser/ui/actions",
+    "//ios/chrome/browser/ui/animators",
+    "//ios/chrome/browser/ui/tools",
+    "//ios/web",
+  ]
+}
diff --git a/ios/chrome/browser/ui/tools/BUILD.gn b/ios/chrome/browser/ui/tools/BUILD.gn
new file mode 100644
index 0000000..a3225331
--- /dev/null
+++ b/ios/chrome/browser/ui/tools/BUILD.gn
@@ -0,0 +1,35 @@
+# 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.
+
+source_set("tools") {
+  sources = [
+    "tools_coordinator.h",
+    "tools_coordinator.mm",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+
+  deps = [
+    ":tools_ui",
+    "//base",
+    "//ios/chrome/browser:browser_clean_skeleton",
+    "//ios/chrome/browser/ui/actions",
+    "//ios/chrome/browser/ui/animators",
+    "//ios/chrome/browser/ui/presenters",
+  ]
+}
+
+source_set("tools_ui") {
+  sources = [
+    "menu_view_controller.h",
+    "menu_view_controller.mm",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+
+  deps = [
+    "//base",
+    "//ios/chrome/browser/ui/actions",
+  ]
+}
diff --git a/ios/chrome/browser/ui/tools_menu/BUILD.gn b/ios/chrome/browser/ui/tools_menu/BUILD.gn
new file mode 100644
index 0000000..4e29989
--- /dev/null
+++ b/ios/chrome/browser/ui/tools_menu/BUILD.gn
@@ -0,0 +1,75 @@
+# 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.
+
+source_set("tools_menu") {
+  sources = [
+    "reading_list_menu_view_item.h",
+    "reading_list_menu_view_item.mm",
+    "tools_menu_context.h",
+    "tools_menu_context.mm",
+    "tools_menu_view_controller.h",
+    "tools_menu_view_controller.mm",
+    "tools_menu_view_item.h",
+    "tools_menu_view_item.mm",
+    "tools_popup_controller.h",
+    "tools_popup_controller.mm",
+  ]
+  deps = [
+    "//base",
+    "//base:i18n",
+    "//components/reading_list/core",
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/colors",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/popup_menu",
+    "//ios/chrome/browser/ui/reading_list",
+    "//ios/chrome/browser/ui/toolbar:resource_macros",
+    "//ios/chrome/common",
+    "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser/user_feedback",
+    "//ios/third_party/material_components_ios",
+    "//ios/third_party/material_roboto_font_loader_ios",
+    "//ui/base",
+  ]
+  libs = [
+    "QuartzCore.framework",
+    "UIKit.framework",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "tools_menu_view_item_unittest.mm",
+  ]
+  deps = [
+    ":tools_menu",
+    "//base",
+    "//testing/gtest",
+  ]
+}
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "tools_popup_menu_egtest.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui:ui_internal",
+    "//ios/chrome/browser/ui/toolbar",
+    "//ios/chrome/browser/ui/tools_menu",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/third_party/earl_grey",
+    "//ios/web:test_support",
+    "//ui/base",
+  ]
+  libs = [ "XCTest.framework" ]
+}
diff --git a/ios/chrome/browser/ui/util/BUILD.gn b/ios/chrome/browser/ui/util/BUILD.gn
new file mode 100644
index 0000000..48dbae0
--- /dev/null
+++ b/ios/chrome/browser/ui/util/BUILD.gn
@@ -0,0 +1,59 @@
+# 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.
+
+source_set("util") {
+  sources = [
+    "CRUILabel+AttributeUtils.h",
+    "CRUILabel+AttributeUtils.mm",
+    "core_text_util.h",
+    "core_text_util.mm",
+    "label_link_controller.h",
+    "label_link_controller.mm",
+    "label_observer.h",
+    "label_observer.mm",
+    "manual_text_framer.h",
+    "manual_text_framer.mm",
+    "relaxed_bounds_constraints_hittest.h",
+    "snapshot_util.h",
+    "snapshot_util.mm",
+    "text_frame.h",
+    "text_frame.mm",
+    "text_region_mapper.h",
+    "text_region_mapper.mm",
+    "top_view_controller.h",
+    "top_view_controller.mm",
+    "transparent_link_button.h",
+    "transparent_link_button.mm",
+    "unicode_util.h",
+    "unicode_util.mm",
+  ]
+  deps = [
+    "//base",
+    "//base:i18n",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/ui",
+    "//net",
+    "//url",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "CRUILabel+AttributeUtils_unittest.mm",
+    "core_text_util_unittest.mm",
+    "label_link_controller_unittest.mm",
+    "label_observer_unittest.mm",
+    "manual_text_framer_unittest.mm",
+    "text_region_mapper_unittest.mm",
+  ]
+  deps = [
+    ":util",
+    "//base",
+    "//ios/third_party/material_components_ios",
+    "//ios/third_party/material_roboto_font_loader_ios",
+    "//testing/gtest",
+    "//url",
+  ]
+}
diff --git a/ios/chrome/browser/ui/web_contents/BUILD.gn b/ios/chrome/browser/ui/web_contents/BUILD.gn
new file mode 100644
index 0000000..dcbe549da
--- /dev/null
+++ b/ios/chrome/browser/ui/web_contents/BUILD.gn
@@ -0,0 +1,22 @@
+# 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.
+
+source_set("web_contents") {
+  sources = [
+    "web_contents_view_controller.h",
+    "web_contents_view_controller.mm",
+    "web_coordinator.h",
+    "web_coordinator.mm",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+
+  deps = [
+    "//ios/chrome/browser:browser_clean_skeleton",
+    "//ios/chrome/browser/web:web_clean_skeleton",
+    "//ios/web",
+    "//ui/base",
+    "//url",
+  ]
+}
diff --git a/ios/chrome/browser/ui/webui/BUILD.gn b/ios/chrome/browser/ui/webui/BUILD.gn
index b1478185..456c5ad 100644
--- a/ios/chrome/browser/ui/webui/BUILD.gn
+++ b/ios/chrome/browser/ui/webui/BUILD.gn
@@ -54,3 +54,55 @@
     "//url",
   ]
 }
+
+source_set("webui_internal") {
+  sources = [
+    "chrome_web_ui_ios_controller_factory.h",
+    "chrome_web_ui_ios_controller_factory.mm",
+    "omaha_ui.cc",
+    "omaha_ui.h",
+    "signin_internals_ui_ios.cc",
+    "signin_internals_ui_ios.h",
+  ]
+  deps = [
+    "//base",
+    "//components/favicon/core",
+    "//components/favicon_base",
+    "//components/resources",
+    "//components/signin/core/browser",
+    "//ios/chrome/app/resources:ios_resources",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/omaha",
+    "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/ui/webui",
+    "//ios/chrome/browser/ui/webui/gcm",
+    "//ios/chrome/browser/ui/webui/net_export",
+    "//ios/chrome/browser/ui/webui/sync_internals",
+    "//ios/web",
+    "//ui/base",
+    "//ui/gfx",
+    "//url",
+  ]
+}
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "web_ui_egtest.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/strings",
+    "//components/version_info",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/ui/omnibox:omnibox_internal",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/testing:ios_test_support",
+    "//ios/web",
+    "//ui/base",
+    "//url",
+  ]
+  libs = [ "XCTest.framework" ]
+}
diff --git a/ios/chrome/browser/web/BUILD.gn b/ios/chrome/browser/web/BUILD.gn
index acb5fb5..f825fc6 100644
--- a/ios/chrome/browser/web/BUILD.gn
+++ b/ios/chrome/browser/web/BUILD.gn
@@ -155,3 +155,170 @@
     "resources/print.js",
   ]
 }
+
+source_set("web_internal") {
+  sources = [
+    "auto_reload_bridge.h",
+    "auto_reload_bridge.mm",
+    "auto_reload_controller.h",
+    "auto_reload_controller.mm",
+    "blocked_popup_handler.h",
+    "blocked_popup_handler.mm",
+    "chrome_web_client.h",
+    "chrome_web_client.mm",
+    "error_page_content.h",
+    "error_page_content.mm",
+    "external_app_launcher.h",
+    "external_app_launcher.mm",
+    "passkit_dialog_provider.h",
+    "print_observer.h",
+    "print_observer.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/content_settings/core/browser",
+    "//components/dom_distiller/core",
+    "//components/error_page/common",
+    "//components/infobars/core",
+    "//components/prefs",
+    "//components/resources",
+    "//components/strings",
+    "//components/task_scheduler_util/initialization",
+    "//components/task_scheduler_util/variations",
+    "//components/version_info",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser:browser_impl",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/content_settings",
+    "//ios/chrome/browser/ssl",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/overscroll_actions",
+    "//ios/chrome/browser/ui/static_content",
+    "//ios/chrome/browser/web:injected_js",
+    "//ios/chrome/browser/web:resources",
+    "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser/voice",
+    "//ios/third_party/material_components_ios",
+    "//ios/web",
+    "//ios/web:user_agent",
+    "//net",
+    "//ui/base",
+    "//ui/gfx",
+    "//url",
+  ]
+  libs = [ "UIKit.framework" ]
+}
+
+source_set("test_support") {
+  testonly = true
+  sources = [
+    "chrome_web_test.h",
+    "chrome_web_test.mm",
+  ]
+  deps = [
+    "//components/password_manager/core/browser:test_support",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/passwords",
+    "//ios/chrome/browser/ui:ui_internal",
+    "//ios/web",
+    "//ios/web:test_support",
+  ]
+}
+
+source_set("unit_tests_internal") {
+  testonly = true
+  sources = [
+    "auto_reload_controller_unittest.mm",
+    "chrome_web_client_unittest.mm",
+    "error_page_content_unittest.mm",
+    "external_app_launcher_unittest.mm",
+    "find_in_page_js_unittest.mm",
+    "js_findinpage_manager_unittest.mm",
+  ]
+  deps = [
+    ":test_support",
+    ":web_internal",
+    "//base",
+    "//base/test:test_support",
+    "//ios/chrome/browser/find_in_page",
+    "//ios/chrome/browser/ui",
+    "//ios/web",
+    "//ios/web:test_support",
+    "//net",
+    "//testing/gtest",
+    "//third_party/ocmock",
+    "//url",
+  ]
+}
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "browsing_egtest.mm",
+    "browsing_prevent_default_egtest.mm",
+    "cache_egtest.mm",
+    "child_window_open_by_dom_egtest.mm",
+    "forms_egtest.mm",
+    "js_print_egtest.mm",
+    "navigation_egtest.mm",
+    "progress_indicator_egtest.mm",
+    "push_and_replace_state_navigation_egtest.mm",
+    "stop_loading_egtest.mm",
+    "visible_url_egtest.mm",
+    "window_open_by_dom_egtest.mm",
+  ]
+  deps = [
+    "//base",
+    "//base/test:test_support",
+    "//components/content_settings/core/browser",
+    "//components/content_settings/core/common",
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/content_settings",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/testing:ios_test_support",
+    "//ios/testing/earl_grey:earl_grey_support",
+    "//ios/third_party/earl_grey",
+    "//ios/third_party/material_components_ios",
+    "//ios/web:earl_grey_test_support",
+    "//ios/web:test_support",
+    "//net",
+    "//ui/base",
+    "//url",
+  ]
+  libs = [
+    "UIKit.framework",
+    "XCTest.framework",
+  ]
+}
+
+source_set("perf_tests") {
+  testonly = true
+  sources = [
+    "early_page_script_perftest.mm",
+  ]
+  deps = [
+    "//base",
+    "//ios/chrome/test/base:perf_test_support",
+    "//ios/web",
+    "//ios/web:test_support",
+  ]
+  libs = [ "WebKit.framework" ]
+}
+
+# Clean Skeleton targets.
+source_set("web_clean_skeleton") {
+  sources = [
+    "web_mediator+internal.h",
+    "web_mediator.h",
+    "web_mediator.mm",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+}
diff --git a/ios/chrome/test/BUILD.gn b/ios/chrome/test/BUILD.gn
index 127dd9b..4dd78dcb 100644
--- a/ios/chrome/test/BUILD.gn
+++ b/ios/chrome/test/BUILD.gn
@@ -6,9 +6,12 @@
 import("//ios/public/provider/chrome/browser/build_config.gni")
 import("//testing/test.gni")
 
+# All tests needs to be listed in that target to be built as part of
+# "gn_all" target (i.e. by the bots).
 group("all_tests") {
   testonly = true
   deps = [
+    ":ios_chrome_perftests",
     ":ios_chrome_unittests",
   ]
 }
@@ -74,45 +77,105 @@
   ]
 }
 
+test("ios_chrome_perftests") {
+  deps = [
+    # Ensure that all perf tests are run, use fake hooks and pack resources.
+    "//ios/chrome/app:tests_fake_hook",
+    "//ios/chrome/test:run_all_unittests",
+    ios_packed_resources_target,
+
+    # Add perf_tests target here.
+    "//ios/chrome/browser/ui:perf_tests",
+    "//ios/chrome/browser/ui/ntp:perf_tests",
+    "//ios/chrome/browser/ui/stack_view:perf_tests",
+    "//ios/chrome/browser/web:perf_tests",
+  ]
+
+  assert_no_deps = ios_assert_no_deps
+}
+
 test("ios_chrome_unittests") {
   deps = [
-    # Ensure that all unit tests are run and packed resources available.
-    ":run_all_unittests",
+    # Ensure that all unit tests are run, use fake hooks and pack resources.
+    "//ios/chrome/app:tests_fake_hook",
+    "//ios/chrome/test:run_all_unittests",
     ios_packed_resources_target,
 
     # Add unit_tests target here.
     ":unit_tests",
     "//ios/chrome/app:unit_tests",
     "//ios/chrome/app/application_delegate:unit_tests",
+    "//ios/chrome/app/safe_mode:unit_tests",
+    "//ios/chrome/app/spotlight:unit_tests",
     "//ios/chrome/browser:unit_tests",
+    "//ios/chrome/browser/autofill:unit_tests",
     "//ios/chrome/browser/browsing_data:unit_tests",
+    "//ios/chrome/browser/crash_report:unit_tests",
     "//ios/chrome/browser/device_sharing:unit_tests",
     "//ios/chrome/browser/favicon:unit_tests",
     "//ios/chrome/browser/geolocation:unit_tests",
     "//ios/chrome/browser/itunes_links:unit_tests",
     "//ios/chrome/browser/metrics:unit_tests",
+    "//ios/chrome/browser/metrics:unit_tests_internal",
     "//ios/chrome/browser/native_app_launcher:unit_tests",
+    "//ios/chrome/browser/native_app_launcher:unit_tests_internal",
     "//ios/chrome/browser/net:unit_tests",
     "//ios/chrome/browser/passwords:unit_tests",
+    "//ios/chrome/browser/payments:unit_tests",
+    "//ios/chrome/browser/payments/cells:unit_tests",
     "//ios/chrome/browser/reading_list:unit_tests",
+    "//ios/chrome/browser/sessions:unit_tests",
     "//ios/chrome/browser/signin:unit_tests",
     "//ios/chrome/browser/snapshots:unit_tests",
     "//ios/chrome/browser/ssl:unit_tests",
     "//ios/chrome/browser/suggestions:unit_tests",
     "//ios/chrome/browser/sync:unit_tests",
+    "//ios/chrome/browser/tabs:unit_tests",
     "//ios/chrome/browser/translate:unit_tests",
     "//ios/chrome/browser/u2f:unit_tests",
     "//ios/chrome/browser/ui:unit_tests",
+    "//ios/chrome/browser/ui/activity_services:unit_tests",
     "//ios/chrome/browser/ui/alert_coordinator:unit_tests",
+    "//ios/chrome/browser/ui/authentication:unit_tests",
+    "//ios/chrome/browser/ui/autofill/cells:unit_tests",
+    "//ios/chrome/browser/ui/bookmarks:unit_tests",
+    "//ios/chrome/browser/ui/bookmarks/cells:unit_tests",
+    "//ios/chrome/browser/ui/collection_view:unit_tests",
+    "//ios/chrome/browser/ui/collection_view/cells:unit_tests",
     "//ios/chrome/browser/ui/commands:unit_tests",
     "//ios/chrome/browser/ui/context_menu:unit_tests",
+    "//ios/chrome/browser/ui/contextual_search:unit_tests",
     "//ios/chrome/browser/ui/dialogs:unit_tests",
+    "//ios/chrome/browser/ui/dialogs:unit_tests_internal",
+    "//ios/chrome/browser/ui/downloads:unit_tests",
     "//ios/chrome/browser/ui/elements:unit_tests",
+    "//ios/chrome/browser/ui/fancy_ui:unit_tests",
+    "//ios/chrome/browser/ui/first_run:unit_tests",
+    "//ios/chrome/browser/ui/history:unit_tests",
+    "//ios/chrome/browser/ui/icons:unit_tests",
+    "//ios/chrome/browser/ui/infobars:unit_tests",
     "//ios/chrome/browser/ui/keyboard:unit_tests",
+    "//ios/chrome/browser/ui/main:unit_tests",
+    "//ios/chrome/browser/ui/no_tabs:unit_tests",
+    "//ios/chrome/browser/ui/ntp:unit_tests",
+    "//ios/chrome/browser/ui/omnibox:unit_tests",
+    "//ios/chrome/browser/ui/promos:unit_tests",
+    "//ios/chrome/browser/ui/reading_list:unit_tests",
+    "//ios/chrome/browser/ui/settings:unit_tests",
+    "//ios/chrome/browser/ui/settings/cells:unit_tests",
+    "//ios/chrome/browser/ui/side_swipe:unit_tests",
+    "//ios/chrome/browser/ui/stack_view:unit_tests",
+    "//ios/chrome/browser/ui/static_content:unit_tests",
+    "//ios/chrome/browser/ui/tab_switcher:unit_tests",
+    "//ios/chrome/browser/ui/tabs:unit_tests",
+    "//ios/chrome/browser/ui/toolbar:unit_tests",
+    "//ios/chrome/browser/ui/tools_menu:unit_tests",
+    "//ios/chrome/browser/ui/util:unit_tests",
     "//ios/chrome/browser/ui/voice:unit_tests",
     "//ios/chrome/browser/update_client:unit_tests",
     "//ios/chrome/browser/voice:unit_tests",
     "//ios/chrome/browser/web:unit_tests",
+    "//ios/chrome/browser/web:unit_tests_internal",
     "//ios/chrome/browser/web_resource:unit_tests",
     "//ios/chrome/common:unit_tests",
     "//ios/chrome/test/base:unit_tests",
diff --git a/ios/chrome/test/app/BUILD.gn b/ios/chrome/test/app/BUILD.gn
new file mode 100644
index 0000000..8b6ccd5
--- /dev/null
+++ b/ios/chrome/test/app/BUILD.gn
@@ -0,0 +1,80 @@
+# 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.
+
+source_set("test_support") {
+  testonly = true
+  sources = [
+    "bookmarks_test_util.h",
+    "bookmarks_test_util.mm",
+    "chrome_test_util.h",
+    "chrome_test_util.mm",
+    "histogram_test_util.h",
+    "histogram_test_util.mm",
+    "history_test_util.h",
+    "history_test_util.mm",
+    "navigation_test_util.h",
+    "navigation_test_util.mm",
+    "settings_test_util.h",
+    "settings_test_util.mm",
+    "signin_test_util.h",
+    "signin_test_util.mm",
+    "stack_view_test_util.h",
+    "stack_view_test_util.mm",
+    "sync_test_util.h",
+    "sync_test_util.mm",
+    "tab_test_util.h",
+    "tab_test_util.mm",
+    "web_view_interaction_test_util.h",
+    "web_view_interaction_test_util.mm",
+  ]
+  deps = [
+    "//base",
+    "//base/test:test_support",
+    "//breakpad:client",
+    "//components/autofill/core/browser:browser",
+    "//components/bookmarks/browser:browser",
+    "//components/browser_sync",
+    "//components/browsing_data/core",
+    "//components/content_settings/core/browser:browser",
+    "//components/content_settings/core/common:common",
+    "//components/history/core/browser:browser",
+    "//components/keyed_service/core",
+    "//components/metrics",
+    "//components/prefs:prefs",
+    "//components/signin/core/browser:browser",
+    "//components/sync:test_support_fake_server",
+    "//google_apis",
+    "//ios/chrome/app:app_internal",
+    "//ios/chrome/app/application_delegate:application_delegate_internal",
+    "//ios/chrome/app/application_delegate:test_support",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser:browser_internal",
+    "//ios/chrome/browser/autofill",
+    "//ios/chrome/browser/bookmarks",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/browsing_data",
+    "//ios/chrome/browser/content_settings",
+    "//ios/chrome/browser/history",
+    "//ios/chrome/browser/metrics",
+    "//ios/chrome/browser/metrics:metrics_internal",
+    "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/sync",
+    "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui:browser_list",
+    "//ios/chrome/browser/ui:ui_internal",
+    "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/main",
+    "//ios/chrome/browser/ui/ntp:ntp_internal",
+    "//ios/chrome/browser/ui/stack_view",
+    "//ios/chrome/browser/ui/tabs",
+    "//ios/public/provider/chrome/browser",
+    "//ios/public/provider/chrome/browser/signin:test_support",
+    "//ios/testing:ios_test_support",
+    "//ios/web",
+    "//ios/web:test_support",
+    "//net",
+    "//net:test_support",
+    "//url",
+  ]
+}
diff --git a/ios/chrome/test/base/BUILD.gn b/ios/chrome/test/base/BUILD.gn
index 9c7dffc..811cbbb 100644
--- a/ios/chrome/test/base/BUILD.gn
+++ b/ios/chrome/test/base/BUILD.gn
@@ -24,3 +24,17 @@
     "//testing/gtest",
   ]
 }
+
+source_set("perf_test_support") {
+  testonly = true
+  sources = [
+    "perf_test_ios.h",
+    "perf_test_ios.mm",
+  ]
+  deps = [
+    "//base",
+    "//ios/chrome/browser/web:web_internal",
+    "//ios/chrome/test:test_support",
+    "//ios/web:test_support",
+  ]
+}
diff --git a/ios/chrome/test/earl_grey/BUILD.gn b/ios/chrome/test/earl_grey/BUILD.gn
index f05c0ec..eb83ac00 100644
--- a/ios/chrome/test/earl_grey/BUILD.gn
+++ b/ios/chrome/test/earl_grey/BUILD.gn
@@ -2,9 +2,202 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-# This empty target is there to help with upstreaming by removing a manual
-# step from the process (updating the //ios:all target). It will be changed
-# to a real target as part of upstreaming.
+import("//ios/chrome/test/earl_grey/chrome_ios_eg_test.gni")
+
 group("all_tests") {
   testonly = true
+  deps = [
+    ":ios_chrome_device_check_egtests",
+    ":ios_chrome_flaky_egtests",
+    ":ios_chrome_integration_egtests",
+    ":ios_chrome_multitasking_egtests",
+    ":ios_chrome_reading_list_egtests",
+    ":ios_chrome_settings_egtests",
+    ":ios_chrome_smoke_egtests",
+    ":ios_chrome_ui_egtests",
+    ":ios_chrome_web_egtests",
+  ]
+}
+
+chrome_ios_eg_test("ios_chrome_integration_egtests") {
+  deps = [
+    "//ios/chrome/browser/autofill:eg_tests",
+    "//ios/chrome/browser/context_menu:eg_tests",
+    "//ios/chrome/browser/device_sharing:eg_tests",
+    "//ios/chrome/browser/metrics:eg_tests",
+    "//ios/chrome/browser/net:eg_tests",
+    "//ios/chrome/browser/translate:eg_tests",
+  ]
+}
+
+chrome_ios_eg_test("ios_chrome_reading_list_egtests") {
+  deps = [
+    ":test_support",
+    "//ios/chrome/browser/ui/reading_list:eg_tests",
+  ]
+}
+
+chrome_ios_eg_test("ios_chrome_settings_egtests") {
+  deps = [
+    "//ios/chrome/browser/ui/settings:eg_tests",
+  ]
+}
+
+chrome_ios_eg_test("ios_chrome_ui_egtests") {
+  deps = [
+    "//ios/chrome/app/safe_mode:eg_tests",
+    "//ios/chrome/browser/ui:eg_tests",
+    "//ios/chrome/browser/ui/activity_services:eg_tests",
+    "//ios/chrome/browser/ui/alert_coordinator:eg_tests",
+    "//ios/chrome/browser/ui/authentication:eg_tests",
+    "//ios/chrome/browser/ui/bookmarks:eg_tests",
+    "//ios/chrome/browser/ui/dialogs:eg_tests",
+    "//ios/chrome/browser/ui/find_bar:eg_tests",
+    "//ios/chrome/browser/ui/first_run:eg_tests",
+    "//ios/chrome/browser/ui/history:eg_tests",
+    "//ios/chrome/browser/ui/infobars:eg_tests",
+    "//ios/chrome/browser/ui/ntp:eg_tests",
+    "//ios/chrome/browser/ui/ntp/recent_tabs:eg_tests",
+    "//ios/chrome/browser/ui/print:eg_tests",
+    "//ios/chrome/browser/ui/qr_scanner:eg_tests",
+    "//ios/chrome/browser/ui/stack_view:eg_tests",
+    "//ios/chrome/browser/ui/sync:eg_tests",
+    "//ios/chrome/browser/ui/tab_switcher:eg_tests",
+    "//ios/chrome/browser/ui/tabs:eg_tests",
+    "//ios/chrome/browser/ui/toolbar:eg_tests",
+    "//ios/chrome/browser/ui/tools_menu:eg_tests",
+    "//ios/chrome/browser/ui/webui:eg_tests",
+  ]
+}
+
+chrome_ios_eg_test("ios_chrome_web_egtests") {
+  deps = [
+    "//ios/chrome/browser/web:eg_tests",
+  ]
+}
+
+chrome_ios_eg_test("ios_chrome_multitasking_egtests") {
+  sources = [
+    "//ios/chrome/app/multitasking_test_application_delegate.h",
+    "//ios/chrome/app/multitasking_test_application_delegate.mm",
+  ]
+
+  deps = [
+    ":test_support",
+    "//base",
+    "//ios/chrome/app:app_internal",
+    "//ios/chrome/app/application_delegate:application_delegate_internal",
+
+    # Depends on all EarlGrey test suites to create multitasking tests suite.
+    ":ios_chrome_integration_egtests_deps_group",
+    ":ios_chrome_settings_egtests_deps_group",
+    ":ios_chrome_ui_egtests_deps_group",
+    ":ios_chrome_web_egtests_deps_group",
+  ]
+
+  eg_main_application_delegate = "MultitaskingTestApplicationDelegate"
+}
+
+chrome_ios_eg_test("ios_chrome_device_check_egtests") {
+  sources = [
+    "device_check_egtest.mm",
+  ]
+  deps = [
+    ":test_support",
+    "//ios/third_party/earl_grey",
+    "//url",
+  ]
+}
+
+chrome_ios_eg_test("ios_chrome_flaky_egtests") {
+  deps = [
+    ":test_support",
+    "//base",
+
+    # Depends on all EarlGrey test suites to run all the FLAKY_ tests found.
+    # When adding a new test application, please follow the same pattern.
+    ":ios_chrome_integration_egtests_deps_group",
+    ":ios_chrome_settings_egtests_deps_group",
+    ":ios_chrome_ui_egtests_deps_group",
+    ":ios_chrome_web_egtests_deps_group",
+  ]
+}
+
+chrome_ios_eg_test("ios_chrome_smoke_egtests") {
+  sources = [
+    "smoke_egtest.mm",
+  ]
+  deps = [
+    ":test_support",
+    "//ios/chrome/app:app_internal",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui:ui_internal",
+    "//ios/third_party/earl_grey",
+    "//ui/base",
+  ]
+  libs = [ "XCTest.framework" ]
+}
+
+source_set("test_support") {
+  testonly = true
+  sources = [
+    "accessibility_util.h",
+    "accessibility_util.mm",
+    "chrome_actions.h",
+    "chrome_actions.mm",
+    "chrome_assertions.h",
+    "chrome_assertions.mm",
+    "chrome_earl_grey.h",
+    "chrome_earl_grey.mm",
+    "chrome_earl_grey_ui.h",
+    "chrome_earl_grey_ui.mm",
+    "chrome_matchers.h",
+    "chrome_matchers.mm",
+    "chrome_test_case.h",
+    "chrome_test_case.mm",
+    "chrome_util.h",
+    "chrome_util.mm",
+  ]
+
+  deps = [
+    "//base",
+    "//base/test:test_support",
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui:ui",
+    "//ios/chrome/browser/ui/collection_view/cells",
+    "//ios/chrome/browser/ui/omnibox:omnibox_internal",
+    "//ios/chrome/browser/ui/static_content",
+    "//ios/chrome/browser/ui/toolbar",
+    "//ios/chrome/browser/ui/tools_menu",
+    "//ios/chrome/test/app:test_support",
+    "//ios/testing:ios_test_support",
+    "//ios/third_party/material_components_ios",
+    "//ios/web",
+    "//ios/web:earl_grey_test_support",
+    "//ios/web:test_support",
+    "//ui/base",
+    "//url",
+  ]
+
+  public_deps = [
+    "//build/config/ios:xctest",
+    "//ios/third_party/earl_grey",
+  ]
+
+  libs = [
+    "OCHamcrest.framework",
+    "WebKit.framework",
+    "XCTest.framework",
+  ]
+}
+
+source_set("hooks") {
+  testonly = true
+  sources = [
+    "eg_tests_hook.mm",
+  ]
+  deps = [
+    "//ios/chrome/app:tests_hook",
+  ]
 }
diff --git a/ios/chrome/test/earl_grey/chrome_ios_eg_test.gni b/ios/chrome/test/earl_grey/chrome_ios_eg_test.gni
new file mode 100644
index 0000000..c5d7fb9
--- /dev/null
+++ b/ios/chrome/test/earl_grey/chrome_ios_eg_test.gni
@@ -0,0 +1,141 @@
+# 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.
+
+import("//build/mac/tweak_info_plist.gni")
+import("//ios/build/chrome_build.gni")
+import("//ios/public/provider/chrome/browser/build_config.gni")
+import("//ios/third_party/earl_grey/ios_eg_test.gni")
+
+# Template wrapping ios_eg_test, setting default values for EarlGrey test
+# based on //ios/chrome/app:chrome.
+#
+# Arguments:
+#
+#  info_plist:
+#      (optional) string, path to the Info.plist file that will be used for
+#      the bundle.
+#
+#  info_plist_target:
+#      (optional) string, if the info_plist is generated from an action,
+#      rather than a regular source file, specify the target name in lieu
+#      of info_plist. The two arguments are mutually exclusive.
+#
+#  extra_info_plists:
+#      (optional) string array, extra list of plist files that will be merged
+#      and tweaked; ignored if either info_plist or info_plist_target is set.
+#
+#   entitlements_path:
+#       (optional) path to the template to use to generate the application
+#       entitlements by performing variable substitutions, defaults to
+#       //build/config/ios/entitlements.plist.
+#
+#   entitlements_target:
+#       (optional) label of the target generating the application
+#       entitlements (must generate a single file as output); cannot be
+#       defined if entitlements_path is set.
+#
+#   deps
+#        list of labels to depends on.
+#
+# This template defines two targets, one named "${target_name}" is the EarlGrey
+# test application, and the other named "${target_name}_deps_group" is a group
+# target that depends on the template "deps" property (used to implement the
+# test suite running the FLAKY_ tests).
+#
+template("chrome_ios_eg_test") {
+  if (!defined(entitlements_path) && !defined(entitlements_target)) {
+    _target_name = target_name
+    _tweak_entitlements = target_name + "_tweak_entitlements"
+    compile_plist(_tweak_entitlements) {
+      format = "xml1"
+      substitutions = [ "IOS_BUNDLE_ID_PREFIX=$ios_app_bundle_id_prefix" ]
+      output_name = "$target_gen_dir/$_target_name.entitlements"
+      plist_templates =
+          [ "//ios/chrome/test/earl_grey/resources/Chrome.entitlements" ]
+    }
+  }
+
+  if (!defined(info_plist) && !defined(info_plist_target)) {
+    _tweak_info_plist = target_name + "_tweak_info_plist"
+    tweak_info_plist(_tweak_info_plist) {
+      info_plists = [
+        "//ios/chrome/app/resources/Info.plist",
+        "//ios/chrome/app/resources/EarlGreyAddition+Info.plist",
+      ]
+      if (ios_chrome_info_plist_additions != []) {
+        info_plists += ios_chrome_info_plist_additions
+      }
+      if (defined(invoker.extra_info_plists)) {
+        info_plists += invoker.extra_info_plists
+      }
+      args = [
+        "--breakpad=$breakpad_enabled_as_int",
+        "--branding=$chromium_short_name",
+        "--version-overrides=MINOR=9999",
+      ]
+    }
+  }
+
+  _deps_group_name = target_name + "_deps_group"
+  group(_deps_group_name) {
+    testonly = true
+    public_deps = invoker.deps
+    if (defined(invoker.public_deps)) {
+      public_deps += invoker.public_deps
+    }
+  }
+
+  ios_eg_test(target_name) {
+    forward_variables_from(invoker,
+                           "*",
+                           [
+                             "deps",
+                             "entitlements_path",
+                             "entitlements_target",
+                             "eg_main_application_delegate",
+                             "info_plist",
+                             "info_plist_target",
+                             "public_deps",
+                           ])
+
+    if (!defined(entitlements_path) && !defined(entitlements_target)) {
+      entitlements_target = ":$_tweak_entitlements"
+    }
+
+    if (!defined(info_plist) && !defined(info_plist_target)) {
+      info_plist_target = ":$_tweak_info_plist"
+    }
+
+    _eg_main_application_delegate = "MainApplicationDelegate"
+    if (defined(invoker.eg_main_application_delegate)) {
+      _eg_main_application_delegate = invoker.eg_main_application_delegate
+    }
+
+    deps = [
+      ":$_deps_group_name",
+      "//ios/chrome/app:main",
+      "//ios/chrome/test/earl_grey:hooks",
+      "//ios/testing:http_server_bundle_data",
+    ]
+    if (!defined(bundle_deps)) {
+      bundle_deps = []
+    }
+    bundle_deps += [ "//ios/chrome/app/resources" ]
+
+    if (!defined(extra_substitutions)) {
+      extra_substitutions = []
+    }
+    extra_substitutions += [
+      "CHROMIUM_BUNDLE_ID=gtest.$target_name",
+      "CHROMIUM_HANDOFF_ID=$chromium_handoff_id",
+      "CHROMIUM_SHORT_NAME=$target_name",
+      "CHROMIUM_URL_SCHEME_1=$url_unsecure_scheme",
+      "CHROMIUM_URL_SCHEME_2=$url_secure_scheme",
+      "CHROMIUM_URL_SCHEME_3=$url_x_callback_scheme",
+      "CHROMIUM_URL_SCHEME_4=$url_channel_scheme",
+      "EG_MAIN_APPLICATION_DELEGATE=$_eg_main_application_delegate",
+      "SSOAUTH_URL_SCHEME=$url_ssoauth_scheme",
+    ]
+  }
+}
diff --git a/ios/chrome/test/ocmock/BUILD.gn b/ios/chrome/test/ocmock/BUILD.gn
new file mode 100644
index 0000000..a023247
--- /dev/null
+++ b/ios/chrome/test/ocmock/BUILD.gn
@@ -0,0 +1,21 @@
+# 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.
+
+source_set("ocmock") {
+  testonly = true
+  sources = [
+    "OCMockObject+BreakpadControllerTesting.h",
+    "OCMockObject+BreakpadControllerTesting.mm",
+    "OCMockObject+CrOCMockAdditions.h",
+    "OCMockObject+CrOCMockAdditions.mm",
+    "scoped_mock_object.h",
+    "scoped_verifying_mock_object.h",
+  ]
+  deps = [
+    "//base",
+    "//breakpad:client",
+    "//testing/gtest",
+    "//third_party/ocmock",
+  ]
+}
diff --git a/ios/public/provider/chrome/browser/build_config.gni b/ios/public/provider/chrome/browser/build_config.gni
index aaf2ee9..676dd82 100644
--- a/ios/public/provider/chrome/browser/build_config.gni
+++ b/ios/public/provider/chrome/browser/build_config.gni
@@ -20,5 +20,5 @@
 
   # Label of the target providing implementation for ChromeBrowserProvider.
   # Overridden when using the Google-internal repository to build Chrome on iOS.
-  ios_provider_target = "//ios/chrome/browser/providers:provider_factory"
+  ios_provider_target = "//ios/chrome/browser:downstream_provider_factory"
 }
diff --git a/ios/web/test/data/mojo_test.js b/ios/web/test/data/mojo_test.js
index 7b3a9e4..6c48cca 100644
--- a/ios/web/test/data/mojo_test.js
+++ b/ios/web/test/data/mojo_test.js
@@ -13,10 +13,9 @@
   return new Promise(function(resolve, reject) {
     define([
       'mojo/public/js/bindings',
-      'mojo/public/js/connection',
       'ios/web/test/mojo_test.mojom',
       'content/public/renderer/frame_interfaces',
-    ], function(bindings, connection, mojom, frameInterfaces) {
+    ], function(bindings, mojom, frameInterfaces) {
       var pageImpl, browserProxy;
 
       /** @constructor */
@@ -35,9 +34,8 @@
         },
       };
 
-      browserProxy = connection.bindHandleToProxy(
-          frameInterfaces.getInterface(mojom.TestUIHandlerMojo.name),
-          mojom.TestUIHandlerMojo);
+      browserProxy = new mojom.TestUIHandlerMojoPtr(
+          frameInterfaces.getInterface(mojom.TestUIHandlerMojo.name));
       pageImpl = new TestPageImpl();
 
       browserProxy.setClientPage(pageImpl.binding.createInterfacePtrAndBind());
diff --git a/media/capture/video/mac/video_capture_device_avfoundation_mac.mm b/media/capture/video/mac/video_capture_device_avfoundation_mac.mm
index 0145616d7..10a0792 100644
--- a/media/capture/video/mac/video_capture_device_avfoundation_mac.mm
+++ b/media/capture/video/mac/video_capture_device_avfoundation_mac.mm
@@ -261,6 +261,12 @@
   }
   [captureSession_ addInput:captureDeviceInput_];
 
+  // Create and plug the still image capture output. This should happen in
+  // advance of the actual picture to allow for the 3A to stabilize.
+  stillImageOutput_.reset([[AVCaptureStillImageOutput alloc] init]);
+  if (stillImageOutput_ && [captureSession_ canAddOutput:stillImageOutput_])
+    [captureSession_ addOutput:stillImageOutput_];
+
   // Create a new data output for video. The data output is configured to
   // discard late frames by default.
   captureVideoDataOutput_.reset([[AVCaptureVideoDataOutput alloc] init]);
@@ -277,12 +283,6 @@
                                   DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
   [captureSession_ addOutput:captureVideoDataOutput_];
 
-  // Create and plug the still image capture output. This should happen in
-  // advance of the actual picture to allow for the 3A to stabilize.
-  stillImageOutput_.reset([[AVCaptureStillImageOutput alloc] init]);
-  if (stillImageOutput_ && [captureSession_ canAddOutput:stillImageOutput_])
-    [captureSession_ addOutput:stillImageOutput_];
-
   return YES;
 }
 
diff --git a/media/filters/vpx_video_decoder.cc b/media/filters/vpx_video_decoder.cc
index 541478a1..af5d01c 100644
--- a/media/filters/vpx_video_decoder.cc
+++ b/media/filters/vpx_video_decoder.cc
@@ -230,13 +230,9 @@
 };
 
 VpxVideoDecoder::MemoryPool::MemoryPool() {
-  base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
-      this, "VpxVideoDecoder", base::ThreadTaskRunnerHandle::Get());
 }
 
 VpxVideoDecoder::MemoryPool::~MemoryPool() {
-  base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
-      this);
 }
 
 VpxVideoDecoder::MemoryPool::VP9FrameBuffer*
@@ -482,7 +478,12 @@
           g_vpx_offload_thread.Pointer()->RequestOffloadThread();
     }
 
+    DCHECK(!memory_pool_);
     memory_pool_ = new MemoryPool();
+    base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+        memory_pool_.get(), "VpxVideoDecoder",
+        base::ThreadTaskRunnerHandle::Get());
+
     if (vpx_codec_set_frame_buffer_functions(vpx_codec_,
                                              &MemoryPool::GetVP9FrameBuffer,
                                              &MemoryPool::ReleaseVP9FrameBuffer,
@@ -511,6 +512,8 @@
     vpx_codec_destroy(vpx_codec_);
     delete vpx_codec_;
     vpx_codec_ = nullptr;
+    base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
+        memory_pool_.get());
     memory_pool_ = nullptr;
   }
   if (vpx_codec_alpha_) {
diff --git a/remoting/protocol/jingle_messages.cc b/remoting/protocol/jingle_messages.cc
index 5463dbb2..480a2c25 100644
--- a/remoting/protocol/jingle_messages.cc
+++ b/remoting/protocol/jingle_messages.cc
@@ -9,6 +9,7 @@
 #include "remoting/base/constants.h"
 #include "remoting/protocol/content_description.h"
 #include "remoting/protocol/name_value_map.h"
+#include "remoting/signaling/jid_util.h"
 #include "remoting/signaling/remoting_bot.h"
 #include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
 
@@ -173,9 +174,10 @@
 
 SignalingAddress ParseAddress(
     const buzz::XmlElement* iq, bool from, std::string* error) {
-  SignalingAddress empty_instance;
-
   std::string jid(iq->Attr(GetQNameByField(Field::JID, from)));
+  if (jid.empty()) {
+    return SignalingAddress();
+  }
 
   const XmlElement* jingle = iq->FirstNamed(QName(kJingleNamespace, "jingle"));
 
@@ -199,7 +201,7 @@
     channel = SignalingAddress::Channel::XMPP;
   } else if (!NameToValue(kChannelTypes, channel_str, &channel)) {
     *error = "Unknown channel: " + channel_str;
-    return empty_instance;
+    return SignalingAddress();
   }
 
   bool is_lcs = (channel == SignalingAddress::Channel::LCS);
@@ -207,12 +209,12 @@
   if (is_lcs == endpoint_id.empty()) {
     *error = (is_lcs ? "Missing |endpoint-id| for LCS channel"
                     : "|endpoint_id| should be empty for XMPP channel");
-    return empty_instance;
+    return SignalingAddress();
   }
 
   if (from && is_lcs && !IsValidBotJid(jid)) {
     *error = "Reject LCS message from untrusted sender: " + jid;
-    return empty_instance;
+    return SignalingAddress();
   }
 
   return SignalingAddress(jid, endpoint_id, channel);
@@ -227,7 +229,7 @@
   }
 
   // Always set the JID.
-  iq->SetAttr(GetQNameByField(Field::JID, from), address.jid);
+  iq->SetAttr(GetQNameByField(Field::JID, from), address.jid());
 
   // Do not tamper the routing-info in the jingle tag for error IQ's, as
   // it corresponds to the original message.
@@ -241,47 +243,39 @@
   jingle->ClearAttr(GetQNameByField(Field::ENDPOINT_ID, from));
 
   // Only set the channel and endpoint_id in the LCS channel.
-  if (address.channel == SignalingAddress::Channel::LCS) {
-    jingle->AddAttr(
-        GetQNameByField(Field::ENDPOINT_ID, from), address.endpoint_id);
-    jingle->AddAttr(
-        GetQNameByField(Field::CHANNEL, from),
-        ValueToName(kChannelTypes, address.channel));
+  if (address.channel() == SignalingAddress::Channel::LCS) {
+    jingle->AddAttr(GetQNameByField(Field::ENDPOINT_ID, from),
+                    address.endpoint_id());
+    jingle->AddAttr(GetQNameByField(Field::CHANNEL, from),
+                    ValueToName(kChannelTypes, address.channel()));
   }
 }
 
 }  // namespace
 
-IceTransportInfo::NamedCandidate::NamedCandidate(
-    const std::string& name,
-    const cricket::Candidate& candidate)
-    : name(name),
-      candidate(candidate) {
-}
-
-IceTransportInfo::IceCredentials::IceCredentials(std::string channel,
-                                              std::string ufrag,
-                                              std::string password)
-    : channel(channel), ufrag(ufrag), password(password) {
-}
-
 SignalingAddress::SignalingAddress()
-    : channel(SignalingAddress::Channel::XMPP) {}
+    : channel_(SignalingAddress::Channel::XMPP) {}
 
 SignalingAddress::SignalingAddress(const std::string& jid)
-    : jid(jid), channel(SignalingAddress::Channel::XMPP) {}
+    : jid_(NormalizeJid(jid)), channel_(SignalingAddress::Channel::XMPP) {
+  DCHECK(!jid.empty());
+}
 
 SignalingAddress::SignalingAddress(const std::string& jid,
                                    const std::string& endpoint_id,
                                    Channel channel)
-    : jid(jid), endpoint_id(endpoint_id), channel(channel) {}
-
-bool SignalingAddress::operator==(const SignalingAddress& other) {
-  return (other.endpoint_id == endpoint_id) && (other.jid == jid) &&
-         (other.channel == channel);
+    : jid_(NormalizeJid(jid)),
+      endpoint_id_(NormalizeJid(endpoint_id)),
+      channel_(channel) {
+  DCHECK(!jid.empty());
 }
 
-bool SignalingAddress::operator!=(const SignalingAddress& other) {
+bool SignalingAddress::operator==(const SignalingAddress& other) const {
+  return (other.jid_ == jid_) && (other.endpoint_id_ == endpoint_id_) &&
+         (other.channel_ == channel_);
+}
+
+bool SignalingAddress::operator!=(const SignalingAddress& other) const {
   return !(*this == other);
 }
 
@@ -628,6 +622,16 @@
   return iq;
 }
 
+IceTransportInfo::NamedCandidate::NamedCandidate(
+    const std::string& name,
+    const cricket::Candidate& candidate)
+    : name(name), candidate(candidate) {}
+
+IceTransportInfo::IceCredentials::IceCredentials(std::string channel,
+                                                 std::string ufrag,
+                                                 std::string password)
+    : channel(channel), ufrag(ufrag), password(password) {}
+
 IceTransportInfo::IceTransportInfo() {}
 IceTransportInfo::~IceTransportInfo() {}
 
diff --git a/remoting/protocol/jingle_messages.h b/remoting/protocol/jingle_messages.h
index ef33b4a..73c148f 100644
--- a/remoting/protocol/jingle_messages.h
+++ b/remoting/protocol/jingle_messages.h
@@ -21,7 +21,8 @@
 // Represents an address of a Chromoting endpoint and its routing channel.
 // TODO(kelvinp): Move the struct to remoting/signaling. Potentially we could
 // update SignalStrategy interface to use this instead of jid for addressing.
-struct SignalingAddress {
+class SignalingAddress {
+ public:
   enum class Channel { LCS, XMPP };
 
   SignalingAddress();
@@ -30,23 +31,27 @@
                    const std::string& endpoint_id,
                    Channel channel);
 
+  const std::string& jid() const { return jid_; }
+  const std::string& endpoint_id() const { return endpoint_id_; }
+  Channel channel() const { return channel_; }
+  const std::string& id() const {
+    return (channel_ == Channel::LCS) ? endpoint_id_ : jid_;
+  }
+
+  bool empty() const { return jid_.empty(); }
+
+  bool operator==(const SignalingAddress& other) const;
+  bool operator!=(const SignalingAddress& other) const;
+
+ private:
   // Represents the |to| or |from| field in an IQ stanza.
-  std::string jid;
+  std::string jid_;
 
   // Represents the identifier of an endpoint. In  LCS, this is the LCS address
   // encoded in a JID like format.  In XMPP, it is empty.
-  std::string endpoint_id;
+  std::string endpoint_id_;
 
-  Channel channel;
-
-  inline const std::string& id() const {
-    return (channel == Channel::LCS) ? endpoint_id : jid;
-  }
-
-  inline bool empty() const { return jid.empty(); }
-
-  bool operator==(const SignalingAddress& other);
-  bool operator!=(const SignalingAddress& other);
+  Channel channel_;
 };
 
 struct JingleMessage {
diff --git a/remoting/protocol/jingle_messages_unittest.cc b/remoting/protocol/jingle_messages_unittest.cc
index e10e935d..38d4844 100644
--- a/remoting/protocol/jingle_messages_unittest.cc
+++ b/remoting/protocol/jingle_messages_unittest.cc
@@ -419,14 +419,14 @@
 
   JingleMessage message;
   ParseFormatAndCompare(kTestSessionInfoMessage, &message);
-  EXPECT_EQ(message.from.jid, "remoting@bot.talk.google.com");
-  EXPECT_EQ(message.from.channel, SignalingAddress::Channel::LCS);
-  EXPECT_EQ(message.from.endpoint_id, "user@gmail.com/xBrnereror=");
+  EXPECT_EQ(message.from.jid(), "remoting@bot.talk.google.com");
+  EXPECT_EQ(message.from.channel(), SignalingAddress::Channel::LCS);
+  EXPECT_EQ(message.from.endpoint_id(), "user@gmail.com/xBrnereror=");
   EXPECT_EQ(message.from.id(), "user@gmail.com/xBrnereror=");
 
-  EXPECT_EQ(message.to.jid, "user@gmail.com/chromiumsy5C6A652D");
-  EXPECT_EQ(message.to.channel, SignalingAddress::Channel::XMPP);
-  EXPECT_EQ(message.to.endpoint_id, "");
+  EXPECT_EQ(message.to.jid(), "user@gmail.com/chromiumsy5C6A652D");
+  EXPECT_EQ(message.to.channel(), SignalingAddress::Channel::XMPP);
+  EXPECT_EQ(message.to.endpoint_id(), "");
   EXPECT_EQ(message.to.id(), "user@gmail.com/chromiumsy5C6A652D");
 
   EXPECT_EQ(message.action, JingleMessage::SESSION_INFO);
diff --git a/remoting/protocol/jingle_session_unittest.cc b/remoting/protocol/jingle_session_unittest.cc
index 22a57d4..64808e3 100644
--- a/remoting/protocol/jingle_session_unittest.cc
+++ b/remoting/protocol/jingle_session_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/strings/string_util.h"
 #include "base/test/test_timeouts.h"
 #include "base/time/time.h"
 #include "net/socket/socket.h"
@@ -143,8 +144,10 @@
 
   void CreateSessionManagers(int auth_round_trips, int messages_till_start,
                              FakeAuthenticator::Action auth_action) {
-    host_signal_strategy_.reset(new FakeSignalStrategy(kHostJid));
-    client_signal_strategy_.reset(new FakeSignalStrategy(kClientJid));
+    if (!host_signal_strategy_)
+      host_signal_strategy_.reset(new FakeSignalStrategy(kHostJid));
+    if (!client_signal_strategy_)
+      client_signal_strategy_.reset(new FakeSignalStrategy(kClientJid));
     FakeSignalStrategy::Connect(host_signal_strategy_.get(),
                                 client_signal_strategy_.get());
 
@@ -231,7 +234,7 @@
 
   void ConnectClient(std::unique_ptr<Authenticator> authenticator) {
     client_session_ =
-        client_server_->Connect(kHostJid, std::move(authenticator));
+        client_server_->Connect(host_jid_, std::move(authenticator));
     client_session_->SetEventHandler(&client_session_event_handler_);
     client_session_->SetTransport(&client_transport_);
     base::RunLoop().RunUntilIdle();
@@ -262,6 +265,8 @@
   std::unique_ptr<FakeSignalStrategy> host_signal_strategy_;
   std::unique_ptr<FakeSignalStrategy> client_signal_strategy_;
 
+  std::string host_jid_ = kHostJid;
+
   std::unique_ptr<JingleSessionManager> host_server_;
   MockSessionManagerListener host_server_listener_;
   std::unique_ptr<JingleSessionManager> client_server_;
@@ -321,6 +326,24 @@
             jingle_element->Attr(buzz::QName(std::string(), "initiator")));
 }
 
+TEST_F(JingleSessionTest, MixedCaseHostJid) {
+  std::string host_jid = std::string("A") + kHostJid;
+  host_signal_strategy_.reset(new FakeSignalStrategy(host_jid));
+
+  // Imitate host JID being lower-cased when stored in the directory.
+  host_jid_ = base::ToLowerASCII(host_jid);
+
+  CreateSessionManagers(1, FakeAuthenticator::ACCEPT);
+  InitiateConnection(1, FakeAuthenticator::ACCEPT, false);
+}
+
+TEST_F(JingleSessionTest, MixedCaseClientJid) {
+  client_signal_strategy_.reset(
+      new FakeSignalStrategy(std::string("A") + kClientJid));
+  CreateSessionManagers(1, FakeAuthenticator::ACCEPT);
+  InitiateConnection(1, FakeAuthenticator::ACCEPT, false);
+}
+
 // Verify that we can connect two endpoints with multi-step authentication.
 TEST_F(JingleSessionTest, ConnectWithMultistep) {
   CreateSessionManagers(3, FakeAuthenticator::ACCEPT);
diff --git a/remoting/signaling/fake_signal_strategy.cc b/remoting/signaling/fake_signal_strategy.cc
index dfa8b7aa..b0ecd38b 100644
--- a/remoting/signaling/fake_signal_strategy.cc
+++ b/remoting/signaling/fake_signal_strategy.cc
@@ -13,6 +13,7 @@
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "remoting/signaling/jid_util.h"
 #include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
 #include "third_party/webrtc/libjingle/xmpp/constants.h"
 
@@ -164,7 +165,7 @@
   received_messages_.push_back(stanza.release());
 
   const std::string& to_field = stanza_ptr->Attr(buzz::QN_TO);
-  if (to_field != jid_) {
+  if (NormalizeJid(to_field) != NormalizeJid(jid_)) {
     LOG(WARNING) << "Dropping stanza that is addressed to " << to_field
                  << ". Local jid: " << jid_
                  << ". Message content: " << stanza_ptr->Str();
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index 0c426cc..24abba0 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -197,10 +197,6 @@
 #   define SK_SUPPORT_LEGACY_GETTOPDEVICE
 #endif
 
-#ifndef    SK_SUPPORT_LEGACY_GETDEVICE
-#   define SK_SUPPORT_LEGACY_GETDEVICE
-#endif
-
 // Workaround for poor anisotropic mipmap quality,
 // pending Skia ripmap support.
 // (https://bugs.chromium.org/p/skia/issues/detail?id=4863)
diff --git a/skia/ext/platform_canvas.cc b/skia/ext/platform_canvas.cc
index ec99dfe..c19464d8 100644
--- a/skia/ext/platform_canvas.cc
+++ b/skia/ext/platform_canvas.cc
@@ -77,9 +77,7 @@
 }
 
 SkMetaData& GetMetaData(const SkCanvas& canvas) {
-  SkBaseDevice* device = canvas.getDevice();
-  DCHECK(device != nullptr);
-  return device->getMetaData();
+  return const_cast<SkCanvas&>(canvas).getMetaData();
 }
 
 #if defined(OS_MACOSX)
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index 798ef30..e8bd249 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -10361,6 +10361,19 @@
         },
         "test": "gles2_conform_test",
         "use_xvfb": false
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:104a",
+              "os": "Windows-10-10586"
+            }
+          ]
+        },
+        "test": "video_decode_accelerator_unittest",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -10821,6 +10834,19 @@
         },
         "test": "gles2_conform_test",
         "use_xvfb": false
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0412",
+              "os": "Windows-10-10586"
+            }
+          ]
+        },
+        "test": "video_decode_accelerator_unittest",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -11297,6 +11323,19 @@
         },
         "test": "tab_capture_end2end_tests",
         "use_xvfb": false
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:104a",
+              "os": "Windows-10-10586"
+            }
+          ]
+        },
+        "test": "video_decode_accelerator_unittest",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -11796,6 +11835,19 @@
         },
         "test": "gles2_conform_test",
         "use_xvfb": false
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0412",
+              "os": "Windows-10-10586"
+            }
+          ]
+        },
+        "test": "video_decode_accelerator_unittest",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -12282,6 +12334,19 @@
         },
         "test": "gles2_conform_test",
         "use_xvfb": false
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:6613",
+              "os": "Windows-2008ServerR2-SP1"
+            }
+          ]
+        },
+        "test": "video_decode_accelerator_unittest",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -12719,6 +12784,19 @@
         },
         "test": "gles2_conform_test",
         "use_xvfb": false
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:104a",
+              "os": "Windows-2008ServerR2-SP1"
+            }
+          ]
+        },
+        "test": "video_decode_accelerator_unittest",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -13179,6 +13257,19 @@
         },
         "test": "gles2_conform_test",
         "use_xvfb": false
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0412",
+              "os": "Windows-2008ServerR2-SP1"
+            }
+          ]
+        },
+        "test": "video_decode_accelerator_unittest",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -13629,6 +13720,19 @@
         },
         "test": "gles2_conform_test",
         "use_xvfb": false
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:6779",
+              "os": "Windows-2008ServerR2-SP1"
+            }
+          ]
+        },
+        "test": "video_decode_accelerator_unittest",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -14146,6 +14250,19 @@
         },
         "test": "tab_capture_end2end_tests",
         "use_xvfb": false
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:6613",
+              "os": "Windows-2008ServerR2-SP1"
+            }
+          ]
+        },
+        "test": "video_decode_accelerator_unittest",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -14622,6 +14739,19 @@
         },
         "test": "gles2_conform_test",
         "use_xvfb": false
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:041a",
+              "os": "Windows-2008ServerR2-SP1"
+            }
+          ]
+        },
+        "test": "video_decode_accelerator_unittest",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -15098,6 +15228,19 @@
         },
         "test": "gles2_conform_test",
         "use_xvfb": false
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:0f02",
+              "os": "Windows-2008ServerR2-SP1"
+            }
+          ]
+        },
+        "test": "video_decode_accelerator_unittest",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -15692,6 +15835,19 @@
         },
         "test": "tab_capture_end2end_tests",
         "use_xvfb": false
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:104a",
+              "os": "Windows-2008ServerR2-SP1"
+            }
+          ]
+        },
+        "test": "video_decode_accelerator_unittest",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -16191,6 +16347,19 @@
         },
         "test": "gles2_conform_test",
         "use_xvfb": false
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0412",
+              "os": "Windows-2008ServerR2-SP1"
+            }
+          ]
+        },
+        "test": "video_decode_accelerator_unittest",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -16654,6 +16823,19 @@
         },
         "test": "gles2_conform_test",
         "use_xvfb": false
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:104a",
+              "os": "Windows-2008ServerR2-SP1"
+            }
+          ]
+        },
+        "test": "video_decode_accelerator_unittest",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -17165,6 +17347,19 @@
         },
         "test": "tab_capture_end2end_tests",
         "use_xvfb": false
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:104a",
+              "os": "Windows-2008ServerR2-SP1"
+            }
+          ]
+        },
+        "test": "video_decode_accelerator_unittest",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -17651,6 +17846,19 @@
         },
         "test": "gles2_conform_test",
         "use_xvfb": false
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:104a",
+              "os": "Windows-10-10586"
+            }
+          ]
+        },
+        "test": "video_decode_accelerator_unittest",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -18127,6 +18335,19 @@
         },
         "test": "tab_capture_end2end_tests",
         "use_xvfb": false
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:104a",
+              "os": "Windows-10-10586"
+            }
+          ]
+        },
+        "test": "video_decode_accelerator_unittest",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
diff --git a/testing/buildbot/chromium.gpu.json b/testing/buildbot/chromium.gpu.json
index 7bacd13..1def634 100644
--- a/testing/buildbot/chromium.gpu.json
+++ b/testing/buildbot/chromium.gpu.json
@@ -1962,6 +1962,19 @@
         },
         "test": "gl_unittests",
         "use_xvfb": false
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:104a",
+              "os": "Windows-2008ServerR2-SP1"
+            }
+          ]
+        },
+        "test": "video_decode_accelerator_unittest",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -2283,6 +2296,19 @@
         },
         "test": "tab_capture_end2end_tests",
         "use_xvfb": false
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:104a",
+              "os": "Windows-2008ServerR2-SP1"
+            }
+          ]
+        },
+        "test": "video_decode_accelerator_unittest",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index 266f4073..8628a95 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -947,6 +947,12 @@
     "label": "//url:url_unittests",
     "type": "console_test_launcher",
   },
+
+  "video_decode_accelerator_unittest": {
+    "label": "//media/gpu:video_decode_accelerator_unittest",
+    "type": "raw",
+    "args": ["--test_video_data=../../media/test/data/test-25fps.h264:320:240:250:258:50:175:1"],
+  },
   "views_aura_mus_unittests": {
     "label": "//ui/views/mus:views_aura_mus_unittests",
     "type": "windowed_test_launcher",
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 9af7aaa..f425c45 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1628,10 +1628,6 @@
 
 crbug.com/240576 imported/wpt/fullscreen/api/element-ready-check-containing-iframe-manual.html [ Timeout Failure Pass ]
 
-# TODO(foolip): Make the timing of fullscreen events reliable.
-crbug.com/402376 imported/wpt/fullscreen/api/document-exit-fullscreen-timing-manual.html [ Failure Pass ]
-crbug.com/402376 imported/wpt/fullscreen/api/element-request-fullscreen-timing-manual.html [ Failure Pass ]
-
 crbug.com/567230 [ Debug ] virtual/threaded/animations/restart-not-visible.html [ Timeout ]
 
 crbug.com/567419 inspector/elements/styles-2/metrics-box-sizing.html [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/battery-status/resources/mock-battery-monitor.js b/third_party/WebKit/LayoutTests/battery-status/resources/mock-battery-monitor.js
index d1346f2..e6739ef 100644
--- a/third_party/WebKit/LayoutTests/battery-status/resources/mock-battery-monitor.js
+++ b/third_party/WebKit/LayoutTests/battery-status/resources/mock-battery-monitor.js
@@ -4,25 +4,20 @@
     'mockBatteryMonitor',
     ['device/battery/battery_monitor.mojom',
      'device/battery/battery_status.mojom',
-     'mojo/public/js/router',
+     'mojo/public/js/bindings',
     ]).then(mojo => {
-  let [batteryMonitor, batteryStatus, router] = mojo.modules;
+  let [batteryMonitor, batteryStatus, bindings] = mojo.modules;
 
-  class MockBatteryMonitor extends batteryMonitor.BatteryMonitor.stubClass {
+  class MockBatteryMonitor {
     constructor(interfaceProvider) {
-      super();
       interfaceProvider.addInterfaceOverrideForTesting(
           batteryMonitor.BatteryMonitor.name,
-          handle => this.connect_(handle));
+          handle => this.bindingSet_.addBinding(this, handle));
 
       this.interfaceProvider_ = interfaceProvider;
       this.pendingRequests_ = [];
       this.status_ = null;
-    }
-
-    connect_(handle) {
-      this.router_ = new router.Router(handle);
-      this.router_.setIncomingReceiver(this);
+      this.bindingSet_ = new bindings.BindingSet(batteryMonitor.BatteryMonitor);
     }
 
     queryNextStatus() {
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/spellcheck-queue.html b/third_party/WebKit/LayoutTests/editing/spelling/spellcheck-queue.html
index 8f1e888..73bcd3b 100644
--- a/third_party/WebKit/LayoutTests/editing/spelling/spellcheck-queue.html
+++ b/third_party/WebKit/LayoutTests/editing/spelling/spellcheck-queue.html
@@ -23,15 +23,9 @@
 spellcheck_test(
   [
     '<div id="container">',
-      '<input>',
       '<textarea></textarea>',
       '<div contenteditable></div>',
       '<input>',
-      '<textarea></textarea>',
-      '<div contenteditable></div>',
-      '<input>',
-      '<textarea></textarea>',
-      '<div contenteditable></div>',
     '</div>'
   ].join(''),
   document => {
@@ -41,15 +35,9 @@
   },
   [
     '<div id="container">',
-      '<input value="#zz# apple orange">',
       '<textarea>#zz# apple orange</textarea>',
       '<div contenteditable>#zz# apple orange</div>',
       '<input value="#zz# apple orange">',
-      '<textarea>#zz# apple orange</textarea>',
-      '<div contenteditable>#zz# apple orange</div>',
-      '<input value="#zz# apple orange">',
-      '<textarea>#zz# apple orange</textarea>',
-      '<div contenteditable>#zz# apple orange</div>',
     '</div>'
   ].join(''),
   'Spellchecker handles multiple requests.');
diff --git a/third_party/WebKit/LayoutTests/fast/dnd/file-drag-drop-on-page.html b/third_party/WebKit/LayoutTests/fast/dnd/file-drag-drop-on-page.html
new file mode 100644
index 0000000..9aa18ef0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/dnd/file-drag-drop-on-page.html
@@ -0,0 +1,298 @@
+<!doctype html>
+<meta charset="utf-8" />
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="resources/copy-data-transfer.js"></script>
+<style>
+#dropwrapper {
+  display: block;
+  width: 400px;
+  height: 200px;
+  position: relative;
+  padding: 50px 0 0 100px;
+}
+#dropzone {
+  display: block;
+  border: 1px solid black;
+  width: 200px;
+  height: 100px;
+}
+</style>
+
+<p>
+  Please download <a download href="resources/dragged-file.txt">this file</a>,
+  and drag it into the box below.
+</p>
+
+<div id="dropwrapper">
+  <div id="dropzone">
+    Drop Here
+  </div>
+</div>
+
+<script>
+'use strict';
+
+const dropWrapper = document.querySelector('#dropwrapper');
+const dropZone = document.querySelector('#dropzone');
+
+const dragEnterPromise = new Promise((resolve, reject) => {
+  // Needed to keep the drag-and-drop going.
+  dropWrapper.ondragenter = event => event.preventDefault();
+
+  dropZone.ondragenter = event => {
+    event.preventDefault();  // Needed to keep the drag-and-drop going.
+    resolve(copyDataTransfer(event.dataTransfer));
+  };
+});
+const dragOverPromise = new Promise((resolve, reject) => {
+  // Needed to keep the drag-and-drop going.
+  dropZone.ondragover = event => event.preventDefault();
+
+  dropWrapper.ondragover = event => {
+    event.preventDefault();  // Needed to keep the drag-and-drop going.
+    resolve(copyDataTransfer(event.dataTransfer));
+  };
+});
+const dragLeavePromise = new Promise((resolve, reject) => {
+  dropWrapper.ondragleave = event => {
+    resolve(copyDataTransfer(event.dataTransfer));
+  };
+});
+const dropPromise = new Promise((resolve, reject) => {
+  dropZone.ondrop = event => {
+    event.preventDefault();  // Needed to prevent drop navigation.
+    resolve(copyDataTransfer(event.dataTransfer));
+  };
+});
+
+const wrapperRect = dropWrapper.getBoundingClientRect();
+const dropRect = dropZone.getBoundingClientRect();
+if (window.eventSender) {
+  eventSender.mouseMoveTo(0, 0);
+  eventSender.beginDragWithFiles(['resources/dragged-file.txt']);
+
+  // dragenter + dragover on #dropwrapper
+  const wrapperX = wrapperRect.left + 10;
+  const wrapperY = wrapperRect.top + 10;
+  eventSender.mouseMoveTo(wrapperX, wrapperY);
+
+  // dragleave on #dropwrapper and dragenter + dragover + dragleave on #dropzone
+  setTimeout(() => {
+    const centerX = (dropRect.left + dropRect.right) / 2;
+    const centerY = (dropRect.top + dropRect.bottom) / 2;
+    eventSender.mouseMoveTo(centerX, centerY);
+    eventSender.mouseUp();
+  }, 0);
+}
+
+promise_test(() => {
+  return dragEnterPromise.then((dataTransfer) => {
+    assert_array_equals(dataTransfer.types, ['Files']);
+  });
+}, 'DataTransfer.types in dragenter');
+
+promise_test(() => {
+  return dragOverPromise.then((dataTransfer) => {
+    assert_array_equals(dataTransfer.types, ['Files']);
+  });
+}, 'DataTransfer.types in dragover');
+
+promise_test(() => {
+  return dragLeavePromise.then((dataTransfer) => {
+    assert_array_equals(dataTransfer.types, ['Files']);
+  });
+}, 'DataTransfer.types in dragleave');
+
+promise_test(() => {
+  return dropPromise.then((dataTransfer) => {
+    assert_array_equals(dataTransfer.types, ['Files']);
+  });
+}, 'DataTransfer.types in drop');
+
+promise_test(() => {
+  return dragEnterPromise.then((dataTransfer) => {
+    assert_object_equals(dataTransfer.data, {Files: ''});
+  });
+}, 'DataTransfer.getData() return values in dragenter');
+
+promise_test(() => {
+  return dragOverPromise.then((dataTransfer) => {
+    assert_object_equals(dataTransfer.data, {Files: ''});
+  });
+}, 'DataTransfer.getData() return values in dragover');
+
+promise_test(() => {
+  return dragLeavePromise.then((dataTransfer) => {
+    assert_object_equals(dataTransfer.data, {Files: ''});
+  });
+}, 'DataTransfer.getData() return values in dragleave');
+
+promise_test(() => {
+  return dropPromise.then((dataTransfer) => {
+    assert_object_equals(dataTransfer.data, {Files: ''});
+  });
+}, 'DataTransfer.getData() return values in drop');
+
+promise_test(() => {
+  return dragEnterPromise.then((dataTransfer) => {
+    assert_equals(
+        dataTransfer.files.length, 0,
+        'DataTransfer is protected, so DataTransfer.files should be empty');
+  });
+}, 'DataTransfer.files in dragenter');
+
+promise_test(() => {
+  return dragOverPromise.then((dataTransfer) => {
+    assert_equals(
+        dataTransfer.files.length, 0,
+        'DataTransfer is protected, so DataTransfer.files should be empty');
+  });
+}, 'DataTransfer.files in dragover');
+
+promise_test(() => {
+  return dragLeavePromise.then((dataTransfer) => {
+    assert_equals(
+        dataTransfer.files.length, 0,
+        'DataTransfer is protected, so DataTransfer.files should be empty');
+  });
+}, 'DataTransfer.files in dragleave');
+
+promise_test(() => {
+  return dropPromise.then((dataTransfer) => {
+    assert_equals(
+        dataTransfer.files.length, 1,
+        'DataTransfer.files should have one element');
+    const file = dataTransfer.files[0];
+    assert_equals(file.file.name, 'dragged-file.txt');
+    assert_equals(file.file.type, 'text/plain');
+    assert_equals(file.file.size, 21);
+    assert_equals(file.data, 'The test has FAILED.\n');
+  });
+}, 'DataTransfer.files in drop');
+
+promise_test(() => {
+  return dropPromise.then((dataTransfer) => {
+    const file = dataTransfer.files[0].file;
+    assert_true(
+        file instanceof File,
+        'DataTransfer.files[0] should be a File instance');
+    assert_equals(
+        file.name, 'dragged-file.txt',
+        "File.name should reflect the dropped file's name");
+    assert_equals(
+        file.type, 'text/plain',
+        "File.type should reflect the dropped file's MIME type");
+    assert_equals(
+        file.size, 21,
+        "File.type should reflect the dropped file's size");
+  });
+}, 'DataTransfer.files[0] File metadata in drop');
+
+promise_test(() => {
+  return dropPromise.then((dataTransfer) => {
+    assert_equals(dataTransfer.files[0].data, 'The test has FAILED.\n');
+  });
+}, 'Using FileReader to read DataTransfer.files[0] in drop');
+
+promise_test(() => {
+  return dragEnterPromise.then((dataTransfer) => {
+    assert_equals(
+        dataTransfer.items.length, 1,
+        'DataTransfer.items should have 1 element');
+    const item = dataTransfer.items[0];
+    assert_equals(
+        item.kind, 'file',
+        'DataTransferItem.kind should indicate that a file was dropped');
+    assert_equals(
+        item.type, 'text/plain',  // Firefox returns application/x-moz-file.
+        "DataTransferItem.type should reflect the dropped file's MIME type");
+    assert_equals(
+        item.file, null,  // Firefox returns the file's metadata.
+        'DataTransferItem.getAsFile() should reflect that the DataTransfer ' +
+        'is protected');
+  });
+}, 'DataTransfer.items in dragenter');
+
+promise_test(() => {
+  return dragOverPromise.then((dataTransfer) => {
+    assert_equals(
+        dataTransfer.items.length, 1,
+        'DataTransfer.items should have 1 element');
+    const item = dataTransfer.items[0];
+    assert_equals(
+        item.kind, 'file',
+        'DataTransferItem.kind should indicate that a file was dropped');
+    assert_equals(
+        item.type, 'text/plain',  // Firefox returns application/x-moz-file.
+        "DataTransferItem.type should reflect the dropped file's MIME type");
+    assert_equals(
+        item.file, null,  // Firefox returns the file's metadata.
+        'DataTransferItem.getAsFile() should reflect that the DataTransfer ' +
+        'is protected');
+  });
+}, 'DataTransfer.items in dragover');
+
+promise_test(() => {
+  return dragLeavePromise.then((dataTransfer) => {
+    assert_equals(
+        dataTransfer.items.length, 1,
+        'DataTransfer.items should have 1 element');
+    const item = dataTransfer.items[0];
+    assert_equals(
+        item.kind, 'file',
+        'DataTransferItem.kind should indicate that a file was dropped');
+    assert_equals(
+        item.type, 'text/plain',  // Firefox returns application/x-moz-file.
+        "DataTransferItem.type should reflect the dropped file's MIME type");
+    assert_equals(
+        item.file, null,  // Firefox returns the file's metadata.
+        'DataTransferItem.getAsFile() should reflect that the DataTransfer ' +
+        'is protected');
+  });
+}, 'DataTransfer.items in dragleave');
+
+promise_test(() => {
+  return dropPromise.then((dataTransfer) => {
+    assert_equals(
+        dataTransfer.items.length, 1,
+        'DataTransfer.items should have 1 element');
+    const item = dataTransfer.items[0];
+    assert_equals(
+        item.kind, 'file',
+        'DataTransferItem.kind should indicate that a file was dropped');
+    assert_equals(
+        item.type, 'text/plain',  // Firefox returns application/x-moz-file
+        "DataTransferItem.type should reflect the dropped file's MIME type");
+  });
+}, 'DataTransfer.items in drop');
+
+promise_test(() => {
+  return dropPromise.then((dataTransfer) => {
+    assert_equals(
+        dataTransfer.items[0].error, undefined,
+        'Reading the file in DataTransfer.items[0] should not throw');
+
+    const file = dataTransfer.items[0].file;
+    assert_true(
+        file instanceof File,
+        'DataTransfer.items[0].getAsFile() should return a File instance');
+    assert_equals(
+        file.name, 'dragged-file.txt',
+        "File.name should reflect the dropped file's name");
+    assert_equals(
+        file.type, 'text/plain',
+        "File.type should reflect the dropped file's MIME type");
+    assert_equals(
+        file.size, 21,
+        "File.type should reflect the dropped file's size");
+  });
+}, 'DataTransfer.items[0].getAsFile() File metadata in drop');
+
+promise_test(() => {
+  return dropPromise.then((dataTransfer) => {
+    assert_equals(dataTransfer.items[0].data, 'The test has FAILED.\n');
+  });
+}, 'Using FileReader to read DataTransfer.items[0].getAsFile() in drop');
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/dnd/file-drag-over-page-cancel.html b/third_party/WebKit/LayoutTests/fast/dnd/file-drag-over-page-cancel.html
new file mode 100644
index 0000000..cf083d04
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/dnd/file-drag-over-page-cancel.html
@@ -0,0 +1,88 @@
+<!doctype html>
+<meta charset="utf-8" />
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="resources/copy-data-transfer.js"></script>
+<style>
+#dropzone {
+  display: block;
+  border: 1px solid black;
+  width: 200px;
+  height: 200px;
+}
+</style>
+
+<p>
+  Please download <a download href="resources/dragged-file.txt">this file</a>,
+  drag it <em>over</em> the box below, then press the <key>ESC</key> key.
+</p>
+
+<div id="dropzone">
+  Drop Here
+</div>
+
+<script>
+'use strict';
+
+const dropZone = document.querySelector('#dropzone');
+
+const dragLeavePromise = new Promise((resolve, reject) => {
+  dropZone.ondragleave = event => {
+    resolve(copyDataTransfer(event.dataTransfer));
+  };
+});
+
+const clientRect = dropZone.getBoundingClientRect();
+if (window.eventSender) {
+  // dragenter + dragover on #dropzone
+  eventSender.beginDragWithFiles(['resources/dragged-file.txt']);
+  const centerX = (clientRect.left + clientRect.right) / 2;
+  const centerY = (clientRect.top + clientRect.bottom) / 2;
+  eventSender.mouseMoveTo(centerX, centerY);
+
+  // dragleave on #dropwrapper
+  setTimeout(() => {
+    eventSender.keyDown("Escape");
+  }, 0);
+}
+
+promise_test(() => {
+  return dragLeavePromise.then((dataTransfer) => {
+    assert_array_equals(dataTransfer.types, ['Files']);
+  });
+}, 'DataTransfer.types in dragleave');
+
+promise_test(() => {
+  return dragLeavePromise.then((dataTransfer) => {
+    assert_object_equals(dataTransfer.data, {Files: ''});
+  });
+}, 'DataTransfer.getData() return values in dragleave');
+
+promise_test(() => {
+  return dragLeavePromise.then((dataTransfer) => {
+    assert_equals(
+        dataTransfer.files.length, 0,
+        'DataTransfer is protected, so DataTransfer.files should be empty');
+  });
+}, 'DataTransfer.files in dragleave');
+
+promise_test(() => {
+  return dragLeavePromise.then((dataTransfer) => {
+    assert_equals(
+        dataTransfer.items.length, 1,
+        'DataTransfer.items should have 1 element');
+    const item = dataTransfer.items[0];
+    assert_equals(
+        item.kind, 'file',
+        'DataTransferItem.kind should indicate that a file was dropped');
+    assert_equals(
+        item.type, 'text/plain',  // Firefox returns application/x-moz-file.
+        "DataTransferItem.type should reflect the dropped file's MIME type");
+    assert_equals(
+        item.file, null,  // Firefox returns the file's metadata.
+        'DataTransferItem.getAsFile() should reflect that the DataTransfer ' +
+        'is protected');
+  });
+}, 'DataTransfer.items in dragleave');
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/dnd/file-drop-on-webkitdropzone-element.html b/third_party/WebKit/LayoutTests/fast/dnd/file-drop-on-webkitdropzone-element.html
new file mode 100644
index 0000000..8238735d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/dnd/file-drop-on-webkitdropzone-element.html
@@ -0,0 +1,137 @@
+<!doctype html>
+<meta charset="utf-8" />
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="resources/copy-data-transfer.js"></script>
+<style>
+#dropzone {
+  display: block;
+  border: 1px solid black;
+  width: 200px;
+  height: 200px;
+}
+</style>
+
+<p>
+  Please download <a download href="resources/dragged-file.txt">this file</a>,
+  and drag it into the box below.
+</p>
+
+<div id="dropzone" webkitdropzone="copy file:text/plain">
+  Drop Here
+</div>
+
+<script>
+'use strict';
+
+const dropZone = document.querySelector('#dropzone');
+
+const dropPromise = new Promise((resolve, reject) => {
+  dropZone.ondrop = event => {
+    event.preventDefault();  // Needed to prevent drop navigation.
+    resolve(copyDataTransfer(event.dataTransfer));
+  };
+});
+
+const clientRect = dropZone.getBoundingClientRect();
+if (window.eventSender) {
+  eventSender.beginDragWithFiles(['resources/dragged-file.txt']);
+  const centerX = (clientRect.left + clientRect.right) / 2;
+  const centerY = (clientRect.top + clientRect.bottom) / 2;
+  eventSender.mouseMoveTo(centerX, centerY);
+  eventSender.mouseUp();
+}
+
+promise_test(() => {
+  return dropPromise.then((dataTransfer) => {
+    assert_array_equals(dataTransfer.types, ['Files']);
+  });
+}, 'DataTransfer.types in drop');
+
+promise_test(() => {
+  return dropPromise.then((dataTransfer) => {
+    assert_object_equals(dataTransfer.data, {Files: ''});
+  });
+}, 'DataTransfer.getData() return values in drop');
+
+promise_test(() => {
+  return dropPromise.then((dataTransfer) => {
+    assert_equals(
+        dataTransfer.files.length, 1,
+        'DataTransfer.files should have one element');
+    const file = dataTransfer.files[0];
+    assert_equals(file.file.name, 'dragged-file.txt');
+    assert_equals(file.file.type, 'text/plain');
+    assert_equals(file.file.size, 21);
+    assert_equals(file.data, 'The test has FAILED.\n');
+  });
+}, 'DataTransfer.files in drop');
+
+promise_test(() => {
+  return dropPromise.then((dataTransfer) => {
+    const file = dataTransfer.files[0].file;
+    assert_true(
+        file instanceof File,
+        'DataTransfer.files[0] should be a File instance');
+    assert_equals(
+        file.name, 'dragged-file.txt',
+        "File.name should reflect the dropped file's name");
+    assert_equals(
+        file.type, 'text/plain',
+        "File.type should reflect the dropped file's MIME type");
+    assert_equals(
+        file.size, 21,
+        "File.type should reflect the dropped file's size");
+  });
+}, 'DataTransfer.files[0] File metadata in drop');
+
+promise_test(() => {
+  return dropPromise.then((dataTransfer) => {
+    assert_equals(dataTransfer.files[0].data, 'The test has FAILED.\n');
+  });
+}, 'Using FileReader to read DataTransfer.files[0] in drop');
+
+promise_test(() => {
+  return dropPromise.then((dataTransfer) => {
+    assert_equals(
+        dataTransfer.items.length, 1,
+        'DataTransfer.items should have 1 element');
+    const item = dataTransfer.items[0];
+    assert_equals(
+        item.kind, 'file',
+        'DataTransferItem.kind should indicate that a file was dropped');
+    assert_equals(
+        item.type, 'text/plain',  // Firefox returns application/x-moz-file
+        "DataTransferItem.type should reflect the dropped file's MIME type");
+  });
+}, 'DataTransfer.items in drop');
+
+promise_test(() => {
+  return dropPromise.then((dataTransfer) => {
+    assert_equals(
+        dataTransfer.items[0].error, undefined,
+        'Reading the file in DataTransfer.items[0] should not throw');
+
+    const file = dataTransfer.items[0].file;
+    assert_true(
+        file instanceof File,
+        'DataTransfer.items[0].getAsFile() should return a File instance');
+    assert_equals(
+        file.name, 'dragged-file.txt',
+        "File.name should reflect the dropped file's name");
+    assert_equals(
+        file.type, 'text/plain',
+        "File.type should reflect the dropped file's MIME type");
+    assert_equals(
+        file.size, 21,
+        "File.type should reflect the dropped file's size");
+  });
+}, 'DataTransfer.items[0].getAsFile() File metadata in drop');
+
+promise_test(() => {
+  return dropPromise.then((dataTransfer) => {
+    assert_equals(dataTransfer.items[0].data, 'The test has FAILED.\n');
+  });
+}, 'Using FileReader to read DataTransfer.items[0].getAsFile() in drop');
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/dnd/resources/copy-data-transfer.js b/third_party/WebKit/LayoutTests/fast/dnd/resources/copy-data-transfer.js
new file mode 100644
index 0000000..200ed92
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/dnd/resources/copy-data-transfer.js
@@ -0,0 +1,70 @@
+'use strict';
+
+// Copies the information out of a DataTransfer instance. This is necessary
+// because dataTransfer instances get neutered after their event handlers exit.
+//
+// Returns a Promise that resolves to an object which mirrors the DataTransfer's
+// files, items, and types attributes, as well as the return values of the
+// getData function. The contents of files and file items are read using
+// FileReader.
+const copyDataTransfer = dataTransfer => {
+  const types = dataTransfer.types.slice();
+  const data = {};
+  for (let type of types) {
+    try {
+      data[type] = dataTransfer.getData(type);
+    } catch(e) {  // Catches SecurityError exceptions.
+      data[type] = e;
+    }
+  }
+
+  const readerPromises = [];
+
+  const files = [];
+  for (let file of Array.from(dataTransfer.files || [])) {
+    const fileData = { file: file };
+    files.push(fileData);
+
+    readerPromises.push(new Promise((resolve, reject) => {
+      const reader = new FileReader();
+      reader.onloadend = event => {
+        if (event.target.error)
+          fileData.error = event.target.error;
+        else
+          fileData.data = event.target.result;
+        resolve();
+      };
+      reader.readAsText(file);
+    }).catch(e => fileData.error = e));
+  }
+
+  const items = [];
+  for (let item of Array.from(dataTransfer.items || [])) {
+    const itemData = { kind: item.kind, type: item.type };
+    items.push(itemData);
+
+    readerPromises.push(new Promise((resolve, reject) => {
+      if (itemData.kind === 'file') {
+        itemData.file = item.getAsFile();
+        if (itemData.file === null) {  // DataTransfer is in protected mode.
+          resolve();
+          return;
+        }
+
+        const reader = new FileReader();
+        reader.onloadend = event => {
+          if (event.target.error)
+            itemData.data = event.target.error;
+          else
+            itemData.data = event.target.result;
+          resolve();
+        };
+        reader.readAsText(itemData.file);
+      }
+    }).catch(e => itemData.error = e));
+  }
+
+  return Promise.all(readerPromises).then(() => {
+    return { data, files, items, types };
+  });
+};
diff --git a/third_party/WebKit/LayoutTests/fast/dnd/resources/dragged-file.txt b/third_party/WebKit/LayoutTests/fast/dnd/resources/dragged-file.txt
new file mode 100644
index 0000000..b55dadb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/dnd/resources/dragged-file.txt
@@ -0,0 +1 @@
+The test has FAILED.
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Geolocation/resources/geolocation-mock.js b/third_party/WebKit/LayoutTests/fast/dom/Geolocation/resources/geolocation-mock.js
index 836c79d..40b657d 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/Geolocation/resources/geolocation-mock.js
+++ b/third_party/WebKit/LayoutTests/fast/dom/Geolocation/resources/geolocation-mock.js
@@ -10,9 +10,9 @@
     ['device/geolocation/public/interfaces/geolocation.mojom',
      'third_party/WebKit/public/platform/modules/permissions/permission.mojom',
      'third_party/WebKit/public/platform/modules/permissions/permission_status.mojom',
-     'mojo/public/js/router',
+     'mojo/public/js/bindings',
     ]).then(mojo => {
-  let [geolocation, permission, permissionStatus, router] =
+  let [geolocation, permission, permissionStatus, bindings] =
       mojo.modules;
 
   class GeolocationServiceMock {
@@ -51,6 +51,11 @@
       this.permissionStatus_ = permissionStatus.PermissionStatus.ASK;
       this.rejectPermissionConnections_ = false;
       this.rejectGeolocationConnections_ = false;
+
+      this.geolocationBindingSet_ = new bindings.BindingSet(
+          geolocation.GeolocationService);
+      this.permissionBindingSet_ = new bindings.BindingSet(
+          permission.PermissionService);
     }
 
     connectGeolocation_(handle) {
@@ -58,10 +63,7 @@
         mojo.core.close(handle);
         return;
       }
-      this.geolocationStub_ = new geolocation.GeolocationService.stubClass(
-          this);
-      this.geolocationRouter_ = new router.Router(handle);
-      this.geolocationRouter_.setIncomingReceiver(this.geolocationStub_);
+      this.geolocationBindingSet_.addBinding(this, handle);
     }
 
     connectPermission_(handle) {
@@ -69,9 +71,7 @@
         mojo.core.close(handle);
         return;
       }
-      this.permissionStub_ = new permission.PermissionService.stubClass(this);
-      this.permissionRouter_ = new router.Router(handle);
-      this.permissionRouter_.setIncomingReceiver(this.permissionStub_);
+      this.permissionBindingSet_.addBinding(this, handle);
     }
 
     setHighAccuracy(highAccuracy) {
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-capture-expected.txt b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-capture-expected.txt
index d60b3a88..3b76bf3 100644
--- a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-capture-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-capture-expected.txt
@@ -87,10 +87,8 @@
 green received mousemove
     **** Release the mouse outside of the page & move back to blue box ****
 green received lostpointercapture
-green received pointermove
-Capture pointer event attributes are correct!
-green received mousemove
 green received pointerout
+Capture pointer event attributes are correct!
 green received pointerleave
 grey received pointerleave
 blue received pointerover
@@ -102,6 +100,8 @@
 blue received mouseenter
 blue received pointermove
 blue received mousemove
+blue received pointermove
+blue received mousemove
     **** Move to (0,0) ***** 
 blue received pointerout
 blue received pointerleave
@@ -135,10 +135,8 @@
     **** Release Pointer Capture  ***** 
 green received mousemove
 green received lostpointercapture
-green received pointermove
-Capture pointer event attributes are correct!
-green received mousemove
 green received pointerout
+Capture pointer event attributes are correct!
 green received pointerleave
 grey received pointerleave
 blue received pointerover
@@ -150,6 +148,8 @@
 blue received mouseenter
 blue received pointermove
 blue received mousemove
+blue received pointermove
+blue received mousemove
     **** Move back to green & again to blue & mouse release ***** 
 blue received pointerout
 blue received pointerleave
@@ -213,15 +213,14 @@
     **** Remove Element ***** 
 grey received mousemove
 document received lostpointercapture
-green received pointermove
-Capture pointer event attributes are correct!
-green received mousemove
 blue received pointerover
 blue received pointerenter
 blue received mouseover
 blue received mouseenter
 blue received pointermove
 blue received mousemove
+blue received pointermove
+blue received mousemove
     **** Move back to green & again to blue & mouse release ***** 
 blue received pointerout
 blue received pointerleave
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-capture-transition-events-expected.txt b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-capture-transition-events-expected.txt
index 199587ba..3c7fbd6 100644
--- a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-capture-transition-events-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-capture-transition-events-expected.txt
@@ -18,11 +18,11 @@
 green received mousemove
 --- Set pointercapture for blue ---
  **** Move to blue box *****
-blue received gotpointercapture
 green received pointerout
 green received pointerleave
 blue received pointerover
 blue received pointerenter
+blue received gotpointercapture
 green received mouseout
 green received mouseleave
 blue received mouseover
@@ -81,11 +81,11 @@
 green received mousemove
  **** Set initial capturing and jiggle mouse in green *****
 --- Set pointercapture for blue ---
-blue received gotpointercapture
 green received pointerout
 green received pointerleave
 blue received pointerover
 blue received pointerenter
+blue received gotpointercapture
 green received mouseout
 green received mouseleave
 blue received mouseover
@@ -123,14 +123,22 @@
 --- Release pointercapture for green ---
  **** Move to blue box *****
 green received lostpointercapture
-green received pointermove
-green received mousemove
- ****  Move out of grey, then release *****
 green received pointerout
 green received pointerleave
-grey received pointerleave
+blue received pointerover
+blue received pointerenter
 green received mouseout
 green received mouseleave
+blue received mouseover
+blue received mouseenter
+blue received pointermove
+blue received mousemove
+ ****  Move out of grey, then release *****
+blue received pointerout
+blue received pointerleave
+grey received pointerleave
+blue received mouseout
+blue received mouseleave
 grey received mouseleave
 
     ==== 'blue' is capturing and then 'green' will capture; will move pointer to 'blue' ====
@@ -145,11 +153,11 @@
 green received mousemove
  **** Set initial capturing and jiggle mouse in green *****
 --- Set pointercapture for blue ---
-blue received gotpointercapture
 green received pointerout
 green received pointerleave
 blue received pointerover
 blue received pointerenter
+blue received gotpointercapture
 green received mouseout
 green received mouseleave
 blue received mouseover
@@ -159,11 +167,11 @@
 --- Set pointercapture for green ---
  **** Move to blue box *****
 blue received lostpointercapture
-green received gotpointercapture
 blue received pointerout
 blue received pointerleave
 green received pointerover
 green received pointerenter
+green received gotpointercapture
 blue received mouseout
 blue received mouseleave
 green received mouseover
@@ -199,11 +207,11 @@
 --- Set pointercapture for blue ---
  **** Move to blue box *****
 green received lostpointercapture
-blue received gotpointercapture
 green received pointerout
 green received pointerleave
 blue received pointerover
 blue received pointerenter
+blue received gotpointercapture
 green received mouseout
 green received mouseleave
 blue received mouseover
@@ -236,11 +244,11 @@
 green received mousemove
 --- Set pointercapture for blue ---
  **** Jiggle mouse in green *****
-blue received gotpointercapture
 green received pointerout
 green received pointerleave
 blue received pointerover
 blue received pointerenter
+blue received gotpointercapture
 green received mouseout
 green received mouseleave
 blue received mouseover
@@ -299,11 +307,11 @@
 green received mousemove
  **** Set initial capturing and jiggle mouse in green *****
 --- Set pointercapture for blue ---
-blue received gotpointercapture
 green received pointerout
 green received pointerleave
 blue received pointerover
 blue received pointerenter
+blue received gotpointercapture
 green received mouseout
 green received mouseleave
 blue received mouseover
@@ -313,14 +321,22 @@
 --- Release pointercapture for blue ---
  **** Jiggle mouse in green *****
 blue received lostpointercapture
-blue received pointermove
-blue received mousemove
- ****  Move out of grey, then release *****
 blue received pointerout
 blue received pointerleave
-grey received pointerleave
+green received pointerover
+green received pointerenter
 blue received mouseout
 blue received mouseleave
+green received mouseover
+green received mouseenter
+green received pointermove
+green received mousemove
+ ****  Move out of grey, then release *****
+green received pointerout
+green received pointerleave
+grey received pointerleave
+green received mouseout
+green received mouseleave
 grey received mouseleave
 
     ==== 'green' is capturing and then 'none' will capture ====
@@ -363,11 +379,11 @@
 green received mousemove
  **** Set initial capturing and jiggle mouse in green *****
 --- Set pointercapture for blue ---
-blue received gotpointercapture
 green received pointerout
 green received pointerleave
 blue received pointerover
 blue received pointerenter
+blue received gotpointercapture
 green received mouseout
 green received mouseleave
 blue received mouseover
@@ -377,11 +393,11 @@
 --- Set pointercapture for green ---
  **** Jiggle mouse in green *****
 blue received lostpointercapture
-green received gotpointercapture
 blue received pointerout
 blue received pointerleave
 green received pointerover
 green received pointerenter
+green received gotpointercapture
 blue received mouseout
 blue received mouseleave
 green received mouseover
@@ -417,11 +433,11 @@
 --- Set pointercapture for blue ---
  **** Jiggle mouse in green *****
 green received lostpointercapture
-blue received gotpointercapture
 green received pointerout
 green received pointerleave
 blue received pointerover
 blue received pointerenter
+blue received gotpointercapture
 green received mouseout
 green received mouseleave
 blue received mouseover
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-capture.html b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-capture.html
index 9941140b..8d10149 100644
--- a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-capture.html
+++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-capture.html
@@ -67,7 +67,7 @@
 ];
 
 function checkPointerCaptureProperties(lastPointerEvent, currentPointerEvent) {
-  if (lastPointerEvent == null)
+  if (lastPointerEvent == null || lastPointerEvent.target == document)
     return false;
 
   var isImmediateRelease = (lastPointerEvent.type == 'pointerup') &&
@@ -77,10 +77,10 @@
   if (!isImmediateRelease && !isDelayedCapture)
     return false;
 
-  for (var i = 0; i< pointereventProperties. length; i++) {
+  for (var i = 0; i < pointereventProperties.length; i++) {
     var property = pointereventProperties[i];
     if (lastPointerEvent[property] !== currentPointerEvent[property]) {
-      debug("Capture pointer event attributes are incorrect!");
+      debug("Capture pointer event attributes are incorrect! ");
       return true;
     }
   }
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/touch-capture-expected.txt b/third_party/WebKit/LayoutTests/fast/events/pointerevents/touch-capture-expected.txt
index 8f87427..5870c8e 100644
--- a/third_party/WebKit/LayoutTests/fast/events/pointerevents/touch-capture-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/touch-capture-expected.txt
@@ -283,12 +283,12 @@
 green received pointerdown 14
      --- Set pointer capture to blue 14 ---
 green received touchstart
-blue received gotpointercapture 14
 green received pointerout 14
 green received pointerleave 14
 grey received pointerleave 14
 blue received pointerover 14
 blue received pointerenter 14
+blue received gotpointercapture 14
 blue received pointermove 14
 green received touchmove
     **** Move to blue box & jiggle ****
@@ -311,12 +311,12 @@
 green received pointerdown 15
      --- Set pointer capture to blue 15 ---
 green received touchstart
-blue received gotpointercapture 15
 green received pointerout 15
 green received pointerleave 15
 grey received pointerleave 15
 blue received pointerover 15
 blue received pointerenter 15
+blue received gotpointercapture 15
 blue received pointermove 15
 green received touchmove
     **** Move to blue box & jiggle ****
@@ -343,12 +343,12 @@
 blue received pointerenter 17
 blue received pointerdown 17
 blue received touchstart
-blue received gotpointercapture 16
 green received pointerout 16
 green received pointerleave 16
 grey received pointerleave 16
 blue received pointerover 16
 blue received pointerenter 16
+blue received gotpointercapture 16
 blue received pointermove 16
 green received touchmove
 blue received gotpointercapture 17
@@ -387,12 +387,12 @@
 blue received pointerenter 19
 blue received pointerdown 19
 blue received touchstart
-blue received gotpointercapture 18
 green received pointerout 18
 green received pointerleave 18
 grey received pointerleave 18
 blue received pointerover 18
 blue received pointerenter 18
+blue received gotpointercapture 18
 blue received pointermove 18
 green received touchmove
 blue received gotpointercapture 19
diff --git a/third_party/WebKit/LayoutTests/fullscreen/api/document-exit-fullscreen-twice.html b/third_party/WebKit/LayoutTests/fullscreen/api/document-exit-fullscreen-twice.html
deleted file mode 100644
index fbf429eb..0000000
--- a/third_party/WebKit/LayoutTests/fullscreen/api/document-exit-fullscreen-twice.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<!DOCTYPE html>
-<title>Document#exitFullscreen() called twice</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../trusted-click.js"></script>
-<div id="log"></div>
-<script>
-// Adapted from https://github.com/w3c/web-platform-tests/pull/4250
-// TODO(foolip): Remove this test when the above is imported and passing.
-async_test(t => {
-  const div = document.querySelector("div");
-
-  document.onfullscreenchange = t.step_func(() => {
-    // We are now in fullscreen.
-    assert_equals(document.fullscreenElement, div);
-
-    document.onfullscreenchange = t.step_func(() => {
-      assert_equals(document.fullscreenElement, null);
-      // Done, but ensure that there's only one fullscreenchange event.
-      document.onfullscreenchange = t.unreached_func("second fullscreenchange event");
-      setTimeout(t.step_func_done(), 0);
-    });
-
-    // Exit fullscreen twice.
-    document.exitFullscreen();
-    assert_equals(document.fullscreenElement, null, "fullscreenElement after first exitFullscreen()");
-    document.exitFullscreen();
-    assert_equals(document.fullscreenElement, null, "fullscreenElement after second exitFullscreen()");
-  });
-  document.onfullscreenerror = t.unreached_func("fullscreenerror event");
-
-  trusted_request(div);
-});
-</script>
diff --git a/third_party/WebKit/LayoutTests/fullscreen/api/document-exit-fullscreen-vs-request.html b/third_party/WebKit/LayoutTests/fullscreen/api/document-exit-fullscreen-vs-request.html
index 54f2afc..2c402e5 100644
--- a/third_party/WebKit/LayoutTests/fullscreen/api/document-exit-fullscreen-vs-request.html
+++ b/third_party/WebKit/LayoutTests/fullscreen/api/document-exit-fullscreen-vs-request.html
@@ -4,12 +4,14 @@
 <script src="../../resources/testharnessreport.js"></script>
 <script src="../trusted-click.js"></script>
 <div id="log"></div>
-<div id="parent"><div></div></div>
+<div id="parent"><div><div></div></div></div>
 <script>
 // Adapted from https://github.com/w3c/web-platform-tests/pull/4250
 // TODO(foolip): Remove this test when the above is imported and passing.
 async_test(t => {
   const parent = document.getElementById("parent");
+  const child = parent.firstChild;
+  const grandChild = child.firstChild;
 
   document.onfullscreenchange = t.step_func(() => {
     // We are now in fullscreen, so exiting requires a resize but requesting
@@ -20,23 +22,26 @@
       // Request fullscreen on another element, to avoid any synchronous
       // short-circuiting on document.fullscreenElement.requestFullscreen(),
       // which used to be in the spec. Also request both before and after the
-      // exit. Both requests should be silently ignored due to the exit.
+      // exit. Both requests synchronously enqueue animation frame tasks. They
+      // may run after exiting, but still before the animation frame task for
+      // the exit, and so both will succeed, and there will be 3
+      // fullscreenchange events, but not matching the order of the calls.
 
-      let fullscreenchanges = 0;
-      document.onfullscreenchange = t.step_func((event) => {
-        assert_equals(document.fullscreenElement, child);
-        fullscreenchanges++;
-        if (fullscreenchanges == 3)
+      let i = 0;
+      const expected = [child, grandChild, null];
+      document.onfullscreenchange = t.step_func(() => {
+        assert_equals(document.fullscreenElement, expected[i], "fullscreenElement when i=" + i);
+        i++;
+        if (i == 3)
           t.done();
       });
 
-      const child = parent.firstChild;
       child.requestFullscreen();
-      assert_equals(document.fullscreenElement, child, "fullscreenElement after first requestFullscreen()");
+      assert_equals(document.fullscreenElement, parent, "fullscreenElement after first requestFullscreen()");
       document.exitFullscreen();
       assert_equals(document.fullscreenElement, parent, "fullscreenElement after exitFullscreen()");
-      child.requestFullscreen();
-      assert_equals(document.fullscreenElement, child, "fullscreenElement after second requestFullscreen()");
+      grandChild.requestFullscreen();
+      assert_equals(document.fullscreenElement, parent, "fullscreenElement after second requestFullscreen()");
     }), parent);
   });
   document.onfullscreenerror = t.unreached_func("fullscreenerror event");
diff --git a/third_party/WebKit/LayoutTests/fullscreen/api/document-fullscreen-element.html b/third_party/WebKit/LayoutTests/fullscreen/api/document-fullscreen-element.html
deleted file mode 100644
index f339c0b..0000000
--- a/third_party/WebKit/LayoutTests/fullscreen/api/document-fullscreen-element.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<!DOCTYPE html>
-<title>Document.fullscreenElement</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../trusted-click.js"></script>
-<div id="log"></div>
-<script>
-async_test(function(t)
-{
-    var div = document.querySelector("div");
-
-    document.onfullscreenchange = t.step_func(function()
-    {
-        assert_equals(document.fullscreenElement, div, "fullscreenElement before exitFullscreen()");
-        document.exitFullscreen();
-        // TODO(foolip): fullscreenElement should still be div.
-        // https://crbug.com/402421
-        assert_equals(document.fullscreenElement, null, "fullscreenElement after exitFullscreen()");
-
-        document.onfullscreenchange = t.step_func(function()
-        {
-            assert_equals(document.fullscreenElement, null, "fullscreenElement after exiting fullscreen");
-            t.done();
-        });
-    });
-
-    trusted_click(t.step_func(function()
-    {
-        assert_equals(document.fullscreenElement, null, "fullscreenElement before requestFullscreen()");
-        div.requestFullscreen();
-        // TODO(foolip): fullscreenElement should still be null.
-        // https://crbug.com/402421
-        assert_equals(document.fullscreenElement, div, "fullscreenElement after requestFullscreen()");
-    }), document.body);
-});
-</script>
diff --git a/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-and-move-to-iframe-prefixed.html b/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-and-move-to-iframe-prefixed.html
new file mode 100644
index 0000000..ef873a6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-and-move-to-iframe-prefixed.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<title>Element#webkitRequestFullscreen() followed by moving the element into an iframe</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<div id="target"></div>
+<iframe allowfullscreen></iframe>
+<script>
+async_test(t => {
+  const target = document.getElementById("target");
+  const iframeDoc = document.querySelector("iframe").contentDocument;
+
+  iframeDoc.onwebkitfullscreenchange = t.unreached_func("webkitfullscreenchange event in iframe");
+  iframeDoc.onwebkitfullscreenerror = t.unreached_func("webkitfullscreenerror event in iframe");
+  document.onwebkitfullscreenchange = t.unreached_func("webkitfullscreenchange event");
+  document.onwebkitfullscreenerror = t.step_func_done(event => {
+    assert_equals(event.target, document);
+    assert_equals(document.webkitFullscreenElement, null);
+    assert_equals(iframeDoc.webkitFullscreenElement, null);
+  });
+
+  trusted_click(t.step_func(() => {
+    target.webkitRequestFullscreen();
+    iframeDoc.body.appendChild(target);
+  }), document.body);
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-and-move-to-iframe.html b/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-and-move-to-iframe.html
deleted file mode 100644
index 1a8c72f..0000000
--- a/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-and-move-to-iframe.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!DOCTYPE html>
-<title>Element#requestFullscreen() followed by moving the element into an iframe</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../trusted-click.js"></script>
-<div id="log"></div>
-<div id="target"></div>
-<iframe allowfullscreen></iframe>
-<script>
-// Adapted from https://github.com/w3c/web-platform-tests/pull/4250
-// TODO(foolip): Remove this test when the above is imported and passing.
-async_test(t => {
-  const target = document.getElementById("target");
-  const iframeDoc = document.querySelector("iframe").contentDocument;
-
-  iframeDoc.onfullscreenchange = t.unreached_func("fullscreenchange event in iframe");
-  iframeDoc.onfullscreenerror = t.unreached_func("fullscreenerror event in iframe");
-  document.onfullscreenchange = t.step_func_done(() => {
-    assert_equals(document.fullscreenElement, null);
-    assert_equals(iframeDoc.fullscreenElement, null);
-  });
-  document.onfullscreenerror = t.unreached_func("fullscreenerror event");
-
-  trusted_click(t.step_func(() => {
-    target.requestFullscreen();
-    iframeDoc.body.appendChild(target);
-  }), document.body);
-});
-</script>
diff --git a/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-and-move.html b/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-and-move.html
deleted file mode 100644
index 5189566..0000000
--- a/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-and-move.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<!DOCTYPE html>
-<title>Element#requestFullscreen() followed by moving the element within the document</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../trusted-click.js"></script>
-<div id="log"></div>
-<div id="target"></div>
-<div id="moveto"></div>
-<script>
-// Adapted from https://github.com/w3c/web-platform-tests/pull/4250
-// TODO(foolip): Remove this test when the above is imported and passing.
-async_test(t => {
-  const target = document.getElementById("target");
-  const moveTo = document.getElementById("moveto");
-
-  document.onfullscreenchange = t.step_func_done(() => {
-    assert_equals(document.fullscreenElement, null);
-    assert_equals(target.parentNode, moveTo);
-  });
-  document.onfullscreenerror = t.unreached_func("fullscreenchange event");
-
-  trusted_click(t.step_func(() => {
-    target.requestFullscreen();
-    moveTo.appendChild(target);
-  }), document.body);
-});
-</script>
diff --git a/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-and-remove-iframe.html b/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-and-remove-iframe.html
deleted file mode 100644
index 3edb7c8..0000000
--- a/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-and-remove-iframe.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!DOCTYPE html>
-<title>Element#requestFullscreen() in iframe followed by removing the iframe</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../trusted-click.js"></script>
-<div id="log"></div>
-<iframe allowfullscreen></iframe>
-<script>
-// Adapted from https://github.com/w3c/web-platform-tests/pull/4250
-// TODO(foolip): Remove this test when the above is imported and passing.
-async_test(t => {
-  const iframe = document.querySelector("iframe");
-  const iframeDocument = iframe.contentDocument;
-
-  document.onfullscreenchange = t.step_func_done(() => {
-    assert_equals(document.fullscreenElement, null);
-    assert_equals(iframeDocument.fullscreenElement, null);
-  });
-  document.onfullscreenerror = t.unreached_func("fullscreenerror event");
-  iframeDocument.onfullscreenchange = t.unreached_func("iframe fullscreenchange event");
-  iframeDocument.onfullscreenerror = t.unreached_func("iframe fullscreenerror event");
-
-  trusted_click(t.step_func(() => {
-    iframeDocument.body.requestFullscreen();
-    iframe.remove();
-  }), document.body);
-});
-</script>
diff --git a/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-and-remove-prefixed.html b/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-and-remove-prefixed.html
new file mode 100644
index 0000000..62a78e6c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-and-remove-prefixed.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<title>Element#webkitRequestFullscreen() followed by removing the element</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<div id="target"></div>
+<script>
+async_test(t => {
+  const target = document.getElementById("target");
+
+  document.onwebkitfullscreenchange = t.unreached_func("webkitfullscreenchange event");
+  document.onwebkitfullscreenerror = t.step_func_done(event => {
+    assert_equals(event.target, document);
+    assert_equals(document.webkitFullscreenElement, null);
+  });
+
+  trusted_click(t.step_func(() => {
+    target.webkitRequestFullscreen();
+    target.remove();
+  }), document.body);
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-and-remove.html b/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-and-remove.html
deleted file mode 100644
index f5bb0e9..0000000
--- a/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-and-remove.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE html>
-<title>Element#requestFullscreen() followed by removing the element</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../trusted-click.js"></script>
-<div id="log"></div>
-<div id="target"></div>
-<script>
-// Adapted from https://github.com/w3c/web-platform-tests/pull/4250
-// TODO(foolip): Remove this test when the above is imported and passing.
-async_test(t => {
-  const target = document.getElementById("target");
-
-  document.onfullscreenchange = t.step_func_done(() => {
-    assert_equals(document.fullscreenElement, null);
-  });
-  document.onfullscreenerror = t.unreached_func("fullscreenchange event");
-
-  trusted_click(t.step_func(() => {
-    target.requestFullscreen();
-    target.remove();
-  }), document.body);
-});
-</script>
diff --git a/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-twice.html b/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-twice.html
deleted file mode 100644
index 80d1761e..0000000
--- a/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-twice.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!DOCTYPE html>
-<title>Element#requestFullscreen() twice</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../trusted-click.js"></script>
-<div id="log"></div>
-<script>
-// Adapted from https://github.com/w3c/web-platform-tests/pull/4250
-// TODO(foolip): Remove this test when the above is imported and passing.
-async_test(t => {
-  const div = document.querySelector("div");
-
-  document.onfullscreenchange = t.step_func(() => {
-    assert_equals(document.fullscreenElement, div);
-    // Done, but ensure that there's only one fullscreenchange event.
-    document.onfullscreenchange = t.unreached_func("second fullscreenchange event");
-    setTimeout(t.step_func_done(), 0);
-  });
-  document.onfullscreenerror = t.unreached_func("fullscreenerror event");
-
-  trusted_click(t.step_func(() => {
-    // Request fullscreen twice.
-    div.requestFullscreen();
-    assert_equals(document.fullscreenElement, div, "fullscreenElement after first requestFullscreen()");
-    div.requestFullscreen();
-    assert_equals(document.fullscreenElement, div, "fullscreenElement after second requestFullscreen()");
-  }), document.body);
-});
-</script>
diff --git a/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-two-iframes.html b/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-two-iframes.html
index c9b0ed6a..688e669 100644
--- a/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-two-iframes.html
+++ b/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-two-iframes.html
@@ -18,15 +18,15 @@
   // Expect first a fullscreenchange event for the second (!) request, then a
   // fullscreenerror event for the first request. TODO(foolip): Remove the
   // Fullscreen hierarchy restrictions. https://crbug.com/627792
-  a.contentDocument.onfullscreenerror = t.step_func(() => {
-    b.contentDocument.onfullscreenchange = t.step_func_done(() => {
-      assert_equals(document.fullscreenElement, b, 'fullscreenElement');
-      assert_equals(a.contentDocument.fullscreenElement, null, 'fullscreenElement in iframe a');
-      assert_equals(b.contentDocument.fullscreenElement, b.contentDocument.body, 'fullscreenElement in iframe b');
+  a.contentDocument.onfullscreenchange = t.step_func_done(() => {
+    assert_equals(document.fullscreenElement, a, 'fullscreenElement');
+    assert_equals(a.contentDocument.fullscreenElement, a.contentDocument.body, 'fullscreenElement in iframe a');
+    b.contentDocument.onfullscreenerror = t.step_func(() => {
+      assert_equals(b.contentDocument.fullscreenElement, null, 'fullscreenElement in iframe b');
     });
   });
-  a.contentDocument.onfullscreenchange = t.unreached_func('fullscreenchange event in iframe a');
-  b.contentDocument.onfullscreenerror = t.unreached_func('fullscreenerror event in iframe b');
+  a.contentDocument.onfullscreenerror = t.unreached_func('fullscreenerror event in iframe a');
+  b.contentDocument.onfullscreenchange = t.unreached_func('fullscreenchange event in iframe b');
 
   trusted_click(t.step_func(() => {
     b.contentDocument.body.requestFullscreen();
diff --git a/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-vs-exit.html b/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-vs-exit.html
index a766a6f..ad5ed1e 100644
--- a/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-vs-exit.html
+++ b/third_party/WebKit/LayoutTests/fullscreen/api/element-request-fullscreen-vs-exit.html
@@ -18,7 +18,7 @@
     document.onfullscreenerror = t.unreached_func("fullscreenerror event");
 
     target.requestFullscreen();
-    assert_equals(document.fullscreenElement, target, "fullscreenElement after requestFullscreen()");
+    assert_equals(document.fullscreenElement, null, "fullscreenElement after requestFullscreen()");
     document.exitFullscreen();
     assert_equals(document.fullscreenElement, null, "fullscreenElement after exitFullscreen()");
   }), document.body);
diff --git a/third_party/WebKit/LayoutTests/fullscreen/enter-exit-full-screen-hover-expected.txt b/third_party/WebKit/LayoutTests/fullscreen/enter-exit-full-screen-hover-expected.txt
index 93985ea..9388a98 100644
--- a/third_party/WebKit/LayoutTests/fullscreen/enter-exit-full-screen-hover-expected.txt
+++ b/third_party/WebKit/LayoutTests/fullscreen/enter-exit-full-screen-hover-expected.txt
@@ -2,8 +2,10 @@
 
 TEST COMPLETE
 PASS document.webkitIsFullScreen is true
+PASS getHoverActiveState(enterButton) is "hovered"
 PASS getHoverActiveState(enterButton) is "default"
 PASS document.webkitIsFullScreen is false
+PASS getHoverActiveState(exitButton) is "hovered"
 PASS getHoverActiveState(exitButton) is "default"
 Go full screen Exit full screen
 EVENT(webkitfullscreenchange)
diff --git a/third_party/WebKit/LayoutTests/fullscreen/enter-exit-full-screen-hover.html b/third_party/WebKit/LayoutTests/fullscreen/enter-exit-full-screen-hover.html
index 1aa60aab..85f4a27 100644
--- a/third_party/WebKit/LayoutTests/fullscreen/enter-exit-full-screen-hover.html
+++ b/third_party/WebKit/LayoutTests/fullscreen/enter-exit-full-screen-hover.html
@@ -23,22 +23,30 @@
     var enterButtonCenter = elementCenter(enterButton);
 
     waitForEventOnce(document, 'webkitfullscreenchange', function() {
-        shouldBeTrue("document.webkitIsFullScreen")
-        // After entering fullscreen, the button should lose hover
-        shouldBeDefault("getHoverActiveState(enterButton)")
+        shouldBeTrue("document.webkitIsFullScreen");
+        // After entering fullscreen + layout, the button should lose hover.
+        // TODO(foolip): Synchronize hover state changes with animation frames.
+        // https://crbug.com/668758
+        shouldBeOnlyHovered("getHoverActiveState(enterButton)");
+        testRunner.layoutAndPaintAsyncThen(function() {
+            shouldBeDefault("getHoverActiveState(enterButton)");
 
-        waitForEventOnce(document, 'webkitfullscreenchange', function() {
-            shouldBeFalse("document.webkitIsFullScreen")
-            // After leaving fullscreen, the button should lose hover
-            shouldBeDefault("getHoverActiveState(exitButton)")
-            endTest();
+            waitForEventOnce(document, 'webkitfullscreenchange', function() {
+                shouldBeFalse("document.webkitIsFullScreen");
+                // After exiting fullscreen + layout, the button should lose hover.
+                shouldBeOnlyHovered("getHoverActiveState(exitButton)");
+                testRunner.layoutAndPaintAsyncThen(function() {
+                    shouldBeDefault("getHoverActiveState(exitButton)");
+                    endTest();
+                });
+            });
+
+            var exitButtonCenter = elementCenter(exitButton);
+            // Hover on and click the "Exit fullscreen" button
+            eventSender.mouseMoveTo(exitButtonCenter.x, exitButtonCenter.y);
+            eventSender.mouseDown();
+            eventSender.mouseUp();
         });
-
-        var exitButtonCenter = elementCenter(exitButton);
-        // Hover on and click the "Exit fullscreen" button
-        eventSender.mouseMoveTo(exitButtonCenter.x, exitButtonCenter.y);
-        eventSender.mouseDown();
-        eventSender.mouseUp();
     });
 
 
diff --git a/third_party/WebKit/LayoutTests/fullscreen/full-screen-remove-ancestor-during-transition-expected.txt b/third_party/WebKit/LayoutTests/fullscreen/full-screen-remove-ancestor-during-transition-expected.txt
deleted file mode 100644
index b5c1b43d..0000000
--- a/third_party/WebKit/LayoutTests/fullscreen/full-screen-remove-ancestor-during-transition-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-PASS successfullyParsed is true
-
-TEST COMPLETE
-PASS document.webkitFullscreenElement is not null
-PASS
diff --git a/third_party/WebKit/LayoutTests/fullscreen/full-screen-remove-ancestor-during-transition.html b/third_party/WebKit/LayoutTests/fullscreen/full-screen-remove-ancestor-during-transition.html
deleted file mode 100644
index 735c520..0000000
--- a/third_party/WebKit/LayoutTests/fullscreen/full-screen-remove-ancestor-during-transition.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE html>
-<script src="../resources/js-test.js"></script>
-<script>
-if (window.testRunner) {
-    testRunner.dumpAsText();
-    testRunner.waitUntilDone();
-}
-
-function runWithKeyDown(fn)
-{
-    document.addEventListener('keydown', function() { fn(); }, false);
-    if (window.testRunner) {
-        eventSender.keyDown('a');
-    }
-}
-
-function init() {
-    runWithKeyDown(goFullScreen);
-}
-
-function goFullScreen() {
-    var iframe = document.getElementById('block1');
-    var element = iframe.contentDocument.documentElement;
-    setTimeout(function () {
-        iframe.parentNode.removeChild(iframe);
-        gc();
-        setTimeout(function () {
-            if (window.testRunner) {
-                testRunner.notifyDone();
-            }
-        }, 0);
-    }, 0);
-    element.webkitRequestFullScreen();
-    shouldNotBe("document.webkitFullscreenElement", "null");
-}
-</script>
-<body onload="init()">
-    <iframe allowfullscreen src="resources/inner.html" id="block1"></iframe>
-    PASS
-</body>
diff --git a/third_party/WebKit/LayoutTests/fullscreen/full-screen-stacking-context.html b/third_party/WebKit/LayoutTests/fullscreen/full-screen-stacking-context.html
index 34f58dfe..56bd356 100644
--- a/third_party/WebKit/LayoutTests/fullscreen/full-screen-stacking-context.html
+++ b/third_party/WebKit/LayoutTests/fullscreen/full-screen-stacking-context.html
@@ -5,7 +5,9 @@
             var runPixelTests = true;
             
             function init() {
-                waitForEventAndEnd(document, 'webkitfullscreenchange');
+                waitForEventOnce(document, 'webkitfullscreenchange', function() {
+                    testRunner.layoutAndPaintAsyncThen(endTest);
+                });
                 runWithKeyDown(goFullScreen);
             }
             
diff --git a/third_party/WebKit/LayoutTests/http/tests/budget/budget-service-mock.js b/third_party/WebKit/LayoutTests/http/tests/budget/budget-service-mock.js
index e404dbc..9e1f966 100644
--- a/third_party/WebKit/LayoutTests/http/tests/budget/budget-service-mock.js
+++ b/third_party/WebKit/LayoutTests/http/tests/budget/budget-service-mock.js
@@ -11,15 +11,15 @@
 let budgetServiceMock = loadMojoModules(
     'budgetServiceMock',
     ['third_party/WebKit/public/platform/modules/budget_service/budget_service.mojom',
-     'mojo/public/js/router'
+     'mojo/public/js/bindings'
     ]).then(mojo => {
-  const [budgetService, router] = mojo.modules;
+  const [budgetService, bindings] = mojo.modules;
 
   class BudgetServiceMock {
     constructor(interfaceProvider) {
       interfaceProvider.addInterfaceOverrideForTesting(
           budgetService.BudgetService.name,
-          handle => this.connectBudgetService_(handle));
+          handle => this.bindingSet_.addBinding(this, handle));
 
       this.interfaceProvider_ = interfaceProvider;
 
@@ -27,12 +27,7 @@
       this.cost_ = {};
       this.budget_ = [];
       this.error_ = budgetService.BudgetServiceErrorType.NONE;
-    }
-
-    connectBudgetService_(handle) {
-      this.budgetServiceStub_ = new budgetService.BudgetService.stubClass(this);
-      this.budgetServiceRouter_ = new router.Router(handle);
-      this.budgetServiceRouter_.setIncomingReceiver(this.budgetServiceStub_);
+      this.bindingSet_ = new bindings.BindingSet(budgetService.BudgetService);
     }
 
     // This is called directly from test JavaScript to set up the return value
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/static-viewport-control-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/viewport-control-expected.txt
similarity index 80%
rename from third_party/WebKit/LayoutTests/http/tests/inspector-unit/static-viewport-control-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/inspector-unit/viewport-control-expected.txt
index dbcbea7..cd00cc0 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/static-viewport-control-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/viewport-control-expected.txt
@@ -1,4 +1,4 @@
-This tests if the StaticViewportControl works properly.
+This tests if the ViewportControl works properly.
 First:0
 Last:6
 Active Items:11
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/static-viewport-control.js b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/viewport-control.js
similarity index 90%
rename from third_party/WebKit/LayoutTests/http/tests/inspector-unit/static-viewport-control.js
rename to third_party/WebKit/LayoutTests/http/tests/inspector-unit/viewport-control.js
index 0b333830..1a0b1fa 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/static-viewport-control.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/viewport-control.js
@@ -1,4 +1,4 @@
-TestRunner.addResult("This tests if the StaticViewportControl works properly.");
+TestRunner.addResult("This tests if the ViewportControl works properly.");
 
 var items = [];
 var heights = [];
@@ -7,7 +7,7 @@
     items[i].style.height = (heights[i] = (i % 4) ? 50 : 28) + "px";
     items[i].textContent = i;
 }
-var viewport = new UI.StaticViewportControl({
+var viewport = new UI.ViewportControl({
     fastItemHeight: i => heights[i],
     itemCount: _ => items.length,
     itemElement: i => items[i]
diff --git a/third_party/WebKit/LayoutTests/imagecapture/resources/mock-imagecapture.js b/third_party/WebKit/LayoutTests/imagecapture/resources/mock-imagecapture.js
index e712c32..5d543e6 100644
--- a/third_party/WebKit/LayoutTests/imagecapture/resources/mock-imagecapture.js
+++ b/third_party/WebKit/LayoutTests/imagecapture/resources/mock-imagecapture.js
@@ -4,15 +4,14 @@
   'mockImageCapture',
   ['media/capture/mojo/image_capture.mojom',
    'mojo/public/js/bindings',
-   'mojo/public/js/connection',
    'content/public/renderer/interfaces',
-  ], (imageCapture, bindings, connection, interfaces) => {
+  ], (imageCapture, bindings, interfaces) => {
 
   class MockImageCapture {
     constructor() {
       interfaces.addInterfaceOverrideForTesting(
           imageCapture.ImageCapture.name,
-          pipe => this.bindToPipe(pipe));
+          handle => this.bindingSet_.addBinding(this, handle));
 
       this.capabilities_ = { capabilities : {
           iso : { min : 100.0, max : 12000.0, current : 400.0, step : 1.0 },
@@ -34,11 +33,7 @@
           sharpness : { min : 4.0, max : 7.0, current : 7.0, step : 1.0 },
       }};
       this.settings_ = null;
-    }
-
-    bindToPipe(pipe) {
-      this.stub_ = connection.bindHandleToStub(pipe, imageCapture.ImageCapture);
-      bindings.StubBindings(this.stub_).delegate = this;
+      this.bindingSet_ = new bindings.BindingSet(imageCapture.ImageCapture);
     }
 
     getCapabilities(source_id) {
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/document-exit-fullscreen-twice-manual-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/document-exit-fullscreen-twice-manual-expected.txt
deleted file mode 100644
index 2124e08..0000000
--- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/document-exit-fullscreen-twice-manual-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Document#exitFullscreen() called twice assert_equals: fullscreenElement after first exitFullscreen() expected Element node <div id="log"></div> but got null
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/document-fullscreen-element-manual-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/document-fullscreen-element-manual-expected.txt
deleted file mode 100644
index bb1b685..0000000
--- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/document-fullscreen-element-manual-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Document#fullscreenElement assert_equals: fullscreenElement after requestFullscreen() expected null but got Element node <div id="log"></div>
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-move-manual-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-move-manual-expected.txt
deleted file mode 100644
index ddb6e01..0000000
--- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-move-manual-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Element#requestFullscreen() followed by moving the element within the document assert_equals: expected Element node <div id="target"></div> but got null
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-move-to-iframe-manual-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-move-to-iframe-manual-expected.txt
deleted file mode 100644
index bb136d07..0000000
--- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-move-to-iframe-manual-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Element#requestFullscreen() followed by moving the element into an iframe assert_unreached: fullscreenchange event Reached unreachable code
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-move-to-iframe-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-move-to-iframe-manual.html
index 006d348..255623e 100644
--- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-move-to-iframe-manual.html
+++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-move-to-iframe-manual.html
@@ -16,6 +16,7 @@
   document.onfullscreenchange = t.unreached_func("fullscreenchange event");
   document.onfullscreenerror = t.step_func_done(() => {
     assert_equals(document.fullscreenElement, null);
+    assert_equals(iframeDoc.fullscreenElement, null);
   });
 
   trusted_click(t.step_func(() => {
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-remove-iframe-manual-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-remove-iframe-manual-expected.txt
deleted file mode 100644
index a522306c..0000000
--- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-remove-iframe-manual-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Element#requestFullscreen() in iframe followed by removing the iframe assert_unreached: fullscreenchange event Reached unreachable code
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-remove-manual-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-remove-manual-expected.txt
deleted file mode 100644
index 19293294..0000000
--- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-and-remove-manual-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Element#requestFullscreen() followed by removing the element assert_unreached: fullscreenchange event Reached unreachable code
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-timing-manual-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-timing-manual-expected.txt
index 3fd3954..31216efc 100644
--- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-timing-manual-expected.txt
+++ b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-timing-manual-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-FAIL Timing of fullscreenchange and resize events assert_unreached: timer callback Reached unreachable code
+FAIL Timing of fullscreenchange and resize events assert_array_equals: event order lengths differ, expected 2 got 1
 PASS Timing of fullscreenerror event 
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-twice-manual-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-twice-manual-expected.txt
deleted file mode 100644
index a6b832f..0000000
--- a/third_party/WebKit/LayoutTests/imported/wpt/fullscreen/api/element-request-fullscreen-twice-manual-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Element#requestFullscreen() twice assert_equals: fullscreenElement after first requestFullscreen() expected null but got Element node <div id="log"></div>
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/media/mediasession/mojo/resources/mediasessionservice-mock.js b/third_party/WebKit/LayoutTests/media/mediasession/mojo/resources/mediasessionservice-mock.js
index 2a73642..963e40e0 100644
--- a/third_party/WebKit/LayoutTests/media/mediasession/mojo/resources/mediasessionservice-mock.js
+++ b/third_party/WebKit/LayoutTests/media/mediasession/mojo/resources/mediasessionservice-mock.js
@@ -42,9 +42,9 @@
 let mediaSessionServiceMock = loadMojoModules(
     'mediaSessionServiceMock',
     ['third_party/WebKit/public/platform/modules/mediasession/media_session.mojom',
-     'mojo/public/js/router',
+     'mojo/public/js/bindings',
     ]).then(mojo => {
-      let [mediaSessionService, router] = mojo.modules;
+      let [mediaSessionService, bindings] = mojo.modules;
 
       MediaSessionAction = mediaSessionService.MediaSessionAction;
       MediaSessionPlaybackState = mediaSessionService.MediaSessionPlaybackState;
@@ -53,15 +53,11 @@
         constructor(interfaceProvider) {
           interfaceProvider.addInterfaceOverrideForTesting(
               mediaSessionService.MediaSessionService.name,
-              handle => this.connectMediaSessionService_(handle));
+              handle => this.bindingSet_.addBinding(this, handle));
           this.interfaceProvider_ = interfaceProvider;
           this.pendingResponse_ = null;
-        }
-
-        connectMediaSessionService_(handle) {
-          this.mediaSessionServiceStub_ = new mediaSessionService.MediaSessionService.stubClass(this);
-          this.mediaSessionServiceRouter_ = new router.Router(handle);
-          this.mediaSessionServiceRouter_.setIncomingReceiver(this.mediaSessionServiceStub_);
+          this.bindingSet_ = new bindings.BindingSet(
+              mediaSessionService.MediaSessionService);
         }
 
         setMetadata(metadata) {
diff --git a/third_party/WebKit/LayoutTests/nfc/resources/nfc-helpers.js b/third_party/WebKit/LayoutTests/nfc/resources/nfc-helpers.js
index f9dcca2..ff8f03e 100644
--- a/third_party/WebKit/LayoutTests/nfc/resources/nfc-helpers.js
+++ b/third_party/WebKit/LayoutTests/nfc/resources/nfc-helpers.js
@@ -70,9 +70,8 @@
 function nfc_mocks(mojo) {
   return define('NFC mocks', [
     'mojo/public/js/bindings',
-    'mojo/public/js/connection',
     'device/nfc/nfc.mojom',
-  ], (bindings, connection, nfc) => {
+  ], (bindings, nfc) => {
 
     function toMojoNFCRecordType(type) {
       switch (type) {
@@ -259,6 +258,8 @@
 
     class MockNFC {
       constructor() {
+        this.bindingSet = new bindings.BindingSet(nfc.NFC);
+
         this.hw_status_ = NFCHWStatus.ENABLED;
         this.pushed_message_ = null;
         this.push_options_ = null;
@@ -270,7 +271,7 @@
         this.watchers_ = [];
       }
 
-      // NFC.stubClass delegate functions
+      // NFC delegate functions
       push(message, options) {
         let error = this.isReady();
         if (error)
@@ -338,14 +339,6 @@
         return Promise.resolve(createNFCError(null));
       }
 
-
-      // Mock utility functions
-      bindToPipe(pipe) {
-        this.stub_ = connection.bindHandleToStub(
-            pipe, nfc.NFC);
-        bindings.StubBindings(this.stub_).delegate = this;
-      }
-
       isReady() {
         if (this.hw_status_ === NFCHWStatus.DISABLED)
           return createNFCError(nfc.NFCErrorType.DEVICE_DISABLED);
@@ -408,8 +401,8 @@
     let mockNFC = new MockNFC;
     mojo.frameInterfaces.addInterfaceOverrideForTesting(
         nfc.NFC.name,
-        pipe => {
-          mockNFC.bindToPipe(pipe);
+        handle => {
+          mockNFC.bindingSet.addBinding(mockNFC, handle);
         });
 
     return Promise.resolve({
diff --git a/third_party/WebKit/LayoutTests/presentation/resources/presentation-service-mock.js b/third_party/WebKit/LayoutTests/presentation/resources/presentation-service-mock.js
index 9b2dbd0..6df94aa 100644
--- a/third_party/WebKit/LayoutTests/presentation/resources/presentation-service-mock.js
+++ b/third_party/WebKit/LayoutTests/presentation/resources/presentation-service-mock.js
@@ -8,23 +8,19 @@
     'presentationServiceMock',
     [
       'third_party/WebKit/public/platform/modules/presentation/presentation.mojom',
-      'mojo/public/js/router',
+      'mojo/public/js/bindings',
     ]).then(mojo => {
-      let [ presentationService, router ] = mojo.modules;
+      let [ presentationService, bindings ] = mojo.modules;
 
       class PresentationServiceMock {
         constructor(interfaceProvider) {
           interfaceProvider.addInterfaceOverrideForTesting(
               presentationService.PresentationService.name,
-              handle => this.connectPresentationService_(handle));
+              handle => this.bindingSet_.addBinding(this, handle));
           this.interfaceProvider_ = interfaceProvider;
           this.pendingResponse_ = null;
-        }
-
-        connectPresentationService_(handle) {
-          this.presentationServiceStub_ = new presentationService.PresentationService.stubClass(this);
-          this.presentationServiceRouter_ = new router.Router(handle);
-          this.presentationServiceRouter_.setIncomingReceiver(this.presentationServiceStub_);
+          this.bindingSet_ = new bindings.BindingSet(
+              presentationService.PresentationService);
         }
 
         startSession(urls) {
diff --git a/third_party/WebKit/LayoutTests/sensor/resources/sensor-helpers.js b/third_party/WebKit/LayoutTests/sensor/resources/sensor-helpers.js
index 262145f..03f32d9 100644
--- a/third_party/WebKit/LayoutTests/sensor/resources/sensor-helpers.js
+++ b/third_party/WebKit/LayoutTests/sensor/resources/sensor-helpers.js
@@ -21,10 +21,9 @@
   return define('Generic Sensor API mocks', [
     'mojo/public/js/core',
     'mojo/public/js/bindings',
-    'mojo/public/js/connection',
     'device/generic_sensor/public/interfaces/sensor_provider.mojom',
     'device/generic_sensor/public/interfaces/sensor.mojom',
-  ], (core, bindings, connection, sensor_provider, sensor) => {
+  ], (core, bindings, sensor_provider, sensor) => {
 
     // Helper function that returns resolved promise with result.
     function sensorResponse(success) {
@@ -33,9 +32,8 @@
 
     // Class that mocks Sensor interface defined in sensor.mojom
     class MockSensor {
-      constructor(stub, handle, offset, size, reportingMode) {
+      constructor(sensorRequest, handle, offset, size, reportingMode) {
         this.client_ = null;
-        this.stub_ = stub;
         this.expects_modified_reading_ = false;
         this.start_should_fail_ = false;
         this.reporting_mode_ = reportingMode;
@@ -52,10 +50,11 @@
         this.buffer_array_ = rv.buffer;
         this.buffer_ = new Float64Array(this.buffer_array_);
         this.resetBuffer();
-        bindings.StubBindings(this.stub_).delegate = this;
-        bindings.StubBindings(this.stub_).connectionErrorHandler = () => {
+        this.binding_ = new bindings.Binding(sensor.Sensor, this,
+                                             sensorRequest);
+        this.binding_.setConnectionErrorHandler(() => {
           this.reset();
-        };
+        });
       }
 
       // Returns default configuration.
@@ -137,7 +136,7 @@
         this.resetBuffer();
         core.unmapBuffer(this.buffer_array_);
         this.buffer_array_ = null;
-        bindings.StubBindings(this.stub_).close();
+        this.binding_.close();
       }
 
       // Zeroes shared buffer.
@@ -241,6 +240,8 @@
         this.resolve_func_ = null;
         this.is_continuous_ = false;
         this.max_frequency_ = 60;
+        this.binding_ = new bindings.Binding(sensor_provider.SensorProvider,
+                                             this);
       }
 
       // Returns initialized Sensor proxy to the client.
@@ -258,8 +259,7 @@
         }
 
         if (this.active_sensor_ == null) {
-          var stub = connection.bindHandleToStub(request.handle, sensor.Sensor);
-          let mockSensor = new MockSensor(stub, this.shared_buffer_handle_,
+          let mockSensor = new MockSensor(request, this.shared_buffer_handle_,
               offset, this.reading_size_in_bytes_, reporting_mode);
           this.active_sensor_ = mockSensor;
         }
@@ -285,21 +285,17 @@
           this.resolve_func_(this.active_sensor_);
         }
 
-        var client_request = new bindings.InterfaceRequest(
-            connection.bindProxy(proxy => {
-              this.active_sensor_.client_ = proxy;
-            }, sensor.SensorClient));
-        return getSensorResponse(init_params, client_request);
+        this.active_sensor_.client_ = new sensor.SensorClientPtr();
+        return getSensorResponse(
+            init_params, bindings.makeRequest(this.active_sensor_.client_));
       }
 
       // Binds object to mojo message pipe
       bindToPipe(pipe) {
-        this.stub_ = connection.bindHandleToStub(
-            pipe, sensor_provider.SensorProvider);
-        bindings.StubBindings(this.stub_).delegate = this;
-        bindings.StubBindings(this.stub_).connectionErrorHandler = () => {
+        this.binding_.bind(pipe);
+        this.binding_.setConnectionErrorHandler(() => {
           this.reset();
-        };
+        });
       }
 
       // Mock functions
@@ -315,8 +311,7 @@
         this.resolve_func_ = null;
         this.max_frequency_ = 60;
         this.is_continuous_ = false;
-        if (this.stub_)
-          bindings.StubBindings(this.stub_).close();
+        this.binding_.close();
       }
 
       // Sets flag that forces mock SensorProvider to fail when getSensor() is
diff --git a/third_party/WebKit/LayoutTests/shapedetection/resources/mock-barcodedetection.js b/third_party/WebKit/LayoutTests/shapedetection/resources/mock-barcodedetection.js
index ed870ba..8395550 100644
--- a/third_party/WebKit/LayoutTests/shapedetection/resources/mock-barcodedetection.js
+++ b/third_party/WebKit/LayoutTests/shapedetection/resources/mock-barcodedetection.js
@@ -4,22 +4,18 @@
   'mockBarcodeDetection',
   ['third_party/WebKit/public/platform/modules/shapedetection/barcodedetection.mojom',
    'mojo/public/js/bindings',
-   'mojo/public/js/connection',
    'mojo/public/js/core',
    'content/public/renderer/frame_interfaces',
-  ], (barcodeDetection, bindings, connection, mojo, interfaces) => {
+  ], (barcodeDetection, bindings, mojo, interfaces) => {
 
   class MockBarcodeDetection {
     constructor() {
+      this.bindingSet_ = new bindings.BindingSet(
+          barcodeDetection.BarcodeDetection);
+
       interfaces.addInterfaceOverrideForTesting(
           barcodeDetection.BarcodeDetection.name,
-          pipe => this.bindToPipe(pipe));
-    }
-
-    bindToPipe(pipe) {
-      this.stub_ = connection.bindHandleToStub(pipe,
-                                               barcodeDetection.BarcodeDetection);
-      bindings.StubBindings(this.stub_).delegate = this;
+          handle => this.bindingSet_.addBinding(this, handle));
     }
 
     detect(frame_data, width, height) {
diff --git a/third_party/WebKit/LayoutTests/shapedetection/resources/mock-facedetection.js b/third_party/WebKit/LayoutTests/shapedetection/resources/mock-facedetection.js
index c934619..62220e8 100644
--- a/third_party/WebKit/LayoutTests/shapedetection/resources/mock-facedetection.js
+++ b/third_party/WebKit/LayoutTests/shapedetection/resources/mock-facedetection.js
@@ -5,30 +5,22 @@
   ['third_party/WebKit/public/platform/modules/shapedetection/facedetection.mojom',
    'third_party/WebKit/public/platform/modules/shapedetection/facedetection_provider.mojom',
    'mojo/public/js/bindings',
-   'mojo/public/js/connection',
    'mojo/public/js/core',
    'content/public/renderer/frame_interfaces',
-  ], (faceDetection, faceDetectionProvider, bindings, connection, mojo, interfaces) => {
+  ], (faceDetection, faceDetectionProvider, bindings, mojo, interfaces) => {
 
   class MockFaceDetectionProvider {
     constructor() {
+      this.bindingSet_ = new bindings.BindingSet(
+          faceDetectionProvider.FaceDetectionProvider);
+
       interfaces.addInterfaceOverrideForTesting(
           faceDetectionProvider.FaceDetectionProvider.name,
-          pipe => this.bindToPipe(pipe));
-    }
-
-    bindToPipe(pipe) {
-      this.stub_ = connection.bindHandleToStub(
-          pipe, faceDetectionProvider.FaceDetectionProvider);
-      bindings.StubBindings(this.stub_).delegate = this;
+          handle => this.bindingSet_.addBinding(this, handle));
     }
 
     createFaceDetection(request, options) {
-      this.mock_service_ = new MockFaceDetection(options);
-      this.mock_service_.stub_ = connection.bindHandleToStub(
-          request.handle, faceDetection.FaceDetection);
-      bindings.StubBindings(this.mock_service_.stub_).delegate =
-          this.mock_service_;
+      this.mock_service_ = new MockFaceDetection(request, options);
     }
 
     getFrameData() {
@@ -45,9 +37,11 @@
   }
 
   class MockFaceDetection {
-    constructor(options) {
+    constructor(request, options) {
       this.maxDetectedFaces_ = options.max_detected_faces;
       this.fastMode_ = options.fast_mode;
+      this.binding_ = new bindings.Binding(faceDetection.FaceDetection, this,
+                                           request);
     }
 
     detect(frame_data, width, height) {
diff --git a/third_party/WebKit/LayoutTests/webaudio/automatic-pull-node-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Analyser/automatic-pull-node-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/automatic-pull-node-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Analyser/automatic-pull-node-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/automatic-pull-node.html b/third_party/WebKit/LayoutTests/webaudio/Analyser/automatic-pull-node.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/webaudio/automatic-pull-node.html
rename to third_party/WebKit/LayoutTests/webaudio/Analyser/automatic-pull-node.html
index b41376d4..a46a49c 100644
--- a/third_party/WebKit/LayoutTests/webaudio/automatic-pull-node.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Analyser/automatic-pull-node.html
@@ -2,10 +2,10 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-basic-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-basic-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-basic-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-basic-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-basic.html b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-basic.html
similarity index 90%
rename from third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-basic.html
rename to third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-basic.html
index 648218f..bb2fca3 100644
--- a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-basic.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/compatibility.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script src="../resources/compatibility.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-byte-data-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-byte-data-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-byte-data-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-byte-data-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-byte-data.html b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-byte-data.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-byte-data.html
rename to third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-byte-data.html
index 9adbf37..ee781789 100644
--- a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-byte-data.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-byte-data.html
@@ -1,10 +1,10 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
     <title>Test Analyser.getByteTimeDomainData()</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-downmix-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-downmix-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-downmix-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-downmix-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-downmix.html b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-downmix.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-downmix.html
rename to third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-downmix.html
index 5981cb0..2df48d4 100644
--- a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-downmix.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-downmix.html
@@ -1,12 +1,12 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/fft.js"></script>
-    <script src="resources/realtimeanalyser-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/fft.js"></script>
+    <script src="../resources/realtimeanalyser-testing.js"></script>
     <title>Test AnalyserNode Downmixing</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-fft-scaling-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-fft-scaling-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-fft-scaling-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-fft-scaling-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-fft-scaling.html b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-fft-scaling.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-fft-scaling.html
rename to third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-fft-scaling.html
index b0be9ce..25b6c88 100644
--- a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-fft-scaling.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-fft-scaling.html
@@ -1,10 +1,10 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-fft-sizing-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-fft-sizing-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-fft-sizing-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-fft-sizing-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-fft-sizing.html b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-fft-sizing.html
similarity index 85%
rename from third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-fft-sizing.html
rename to third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-fft-sizing.html
index cac2bc9..2d591e5 100644
--- a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-fft-sizing.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-fft-sizing.html
@@ -2,10 +2,10 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-fftsize-reset.html b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-fftsize-reset.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-fftsize-reset.html
rename to third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-fftsize-reset.html
index 3fa69ea..17ea5b6 100644
--- a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-fftsize-reset.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-fftsize-reset.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test fftSize Changes Resetting AnalyserNode State </title>
-    <script src="../resources/testharness.js"></script>
-    <script src="../resources/testharnessreport.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/testharness.js"></script>
+    <script src="../../resources/testharnessreport.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-float-data-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-float-data-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-float-data-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-float-data-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-float-data.html b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-float-data.html
similarity index 97%
rename from third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-float-data.html
rename to third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-float-data.html
index 493882a..810d530c 100644
--- a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-float-data.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-float-data.html
@@ -1,10 +1,10 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
     <title>Test AnalyserNode getFloatTimeDomainData</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-freq-data-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-freq-data-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data-smoothing-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-freq-data-smoothing-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data-smoothing-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-freq-data-smoothing-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data-smoothing.html b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-freq-data-smoothing.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data-smoothing.html
rename to third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-freq-data-smoothing.html
index da4c83d4..2bf4791 100644
--- a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data-smoothing.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-freq-data-smoothing.html
@@ -1,12 +1,12 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/realtimeanalyser-testing.js"></script>
-    <script src="resources/fft.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/realtimeanalyser-testing.js"></script>
+    <script src="../resources/fft.js"></script>
     <title>Test Analyser getFloatFrequencyData and getByteFrequencyData, Smoothing</title>
 
   </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data.html b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-freq-data.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data.html
rename to third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-freq-data.html
index ddcca7a..8228406 100644
--- a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-freq-data.html
@@ -1,12 +1,12 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/realtimeanalyser-testing.js"></script>
-    <script src="resources/fft.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/realtimeanalyser-testing.js"></script>
+    <script src="../resources/fft.js"></script>
     <title>Test Analyser getFloatFrequencyData and getByteFrequencyData, No Smoothing</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-multiple-calls-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-multiple-calls-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-multiple-calls-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-multiple-calls-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-multiple-calls.html b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-multiple-calls.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-multiple-calls.html
rename to third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-multiple-calls.html
index 50add4f..4516d26 100644
--- a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-multiple-calls.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-multiple-calls.html
@@ -1,10 +1,10 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
     <title>Test Multiple Calls to getFloatFrequencyData</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-zero-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-zero-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-zero-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-zero-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-zero.html b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-zero.html
similarity index 88%
rename from third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-zero.html
rename to third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-zero.html
index 0fcc818..31afeb0 100644
--- a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-zero.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Analyser/realtimeanalyser-zero.html
@@ -1,10 +1,10 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
     <title>Test getFloatFrequencyData With Zero Inputs</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffer-copy-channel-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-copy-channel-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffer-copy-channel-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-copy-channel-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffer-copy-channel.html b/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-copy-channel.html
similarity index 97%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffer-copy-channel.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-copy-channel.html
index 3224ac98..799f9ad13 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffer-copy-channel.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-copy-channel.html
@@ -1,10 +1,10 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
     <title>Test Basic Functionality of AudioBuffer.copyFromChannel and AudioBuffer.copyToChannel</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffer-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffer-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffer-getChannelData-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-getChannelData-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffer-getChannelData-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-getChannelData-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffer-getChannelData.html b/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-getChannelData.html
similarity index 89%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffer-getChannelData.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-getChannelData.html
index 3583cdd0..969236a 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffer-getChannelData.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-getChannelData.html
@@ -1,11 +1,11 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/audioparam-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/audioparam-testing.js"></script>
     <title>Test AudioBuffer.getChannelData() Returns the Same Object</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffer-resample-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-resample-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffer-resample-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-resample-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffer-resample.html b/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-resample.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffer-resample.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-resample.html
index 7abea8d..94a6ef61 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffer-resample.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer-resample.html
@@ -1,10 +1,10 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffer.html b/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer.html
similarity index 89%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffer.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer.html
index 3e9ad020..a437eeb5 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffer.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBuffer/audiobuffer.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/compatibility.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script src="../resources/compatibility.js"></script>
 </head>
 <body>
 <script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-channels-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-channels-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-channels-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-channels-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-channels.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-channels.html
similarity index 90%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-channels.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-channels.html
index 7b34e684..f1d11122 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-channels.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-channels.html
@@ -2,10 +2,10 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/compatibility.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script src="../resources/compatibility.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-detune-modulated-impulse-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-detune-modulated-impulse-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-detune-modulated-impulse-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-detune-modulated-impulse-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-detune-modulated-impulse.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-detune-modulated-impulse.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-detune-modulated-impulse.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-detune-modulated-impulse.html
index b5d8072..290e9c9 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-detune-modulated-impulse.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-detune-modulated-impulse.html
@@ -2,10 +2,10 @@
 <html>
 
 <head>
-  <script src="../resources/js-test.js"></script>
-  <script src="resources/compatibility.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
+  <script src="../../resources/js-test.js"></script>
+  <script src="../resources/compatibility.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-detune-modulation-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-detune-modulation-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-detune-modulation-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-detune-modulation-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-detune-modulation-expected.wav b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-detune-modulation-expected.wav
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-detune-modulation-expected.wav
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-detune-modulation-expected.wav
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-detune-modulation.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-detune-modulation.html
similarity index 89%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-detune-modulation.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-detune-modulation.html
index 916d064..c392847 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-detune-modulation.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-detune-modulation.html
@@ -2,12 +2,12 @@
 <html>
 
 <head>
-  <script src="../resources/js-test.js"></script>
-  <script src="resources/compatibility.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
-  <script src="resources/audiobuffersource-testing.js"></script>
-  <script src="resources/buffer-loader.js"></script>
+  <script src="../../resources/js-test.js"></script>
+  <script src="../resources/compatibility.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
+  <script src="../resources/audiobuffersource-testing.js"></script>
+  <script src="../resources/buffer-loader.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-ended-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-ended-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-ended-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-ended-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-ended.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-ended.html
similarity index 77%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-ended.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-ended.html
index 758b4db..39b3fd94 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-ended.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-ended.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audiobuffersource-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audiobuffersource-testing.js"></script>
     <script>
         var context;
         var source;
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-expected.wav b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-expected.wav
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-expected.wav
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-expected.wav
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-grain-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-grain-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-grain-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-grain-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-grain.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-grain.html
similarity index 88%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-grain.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-grain.html
index 94b3227..14ba0618 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-grain.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-grain.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test Start Grain with Delayed Buffer Setting </title>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-late-start-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-late-start-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-late-start-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-late-start-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-late-start.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-late-start.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-late-start.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-late-start.html
index e631e25..785b327c 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-late-start.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-late-start.html
@@ -2,10 +2,10 @@
 <html>
 
 <head>
-  <script src="../resources/js-test.js"></script>
-  <script src="resources/compatibility.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
+  <script src="../../resources/js-test.js"></script>
+  <script src="../resources/compatibility.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-loop-comprehensive-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-comprehensive-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-loop-comprehensive-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-comprehensive-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-loop-comprehensive.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-comprehensive.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-loop-comprehensive.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-comprehensive.html
index cd6e190f..7e2f951 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-loop-comprehensive.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-comprehensive.html
@@ -2,11 +2,11 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/audiobuffersource-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script src="../resources/audiobuffersource-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-loop-grain-no-duration-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-grain-no-duration-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-loop-grain-no-duration-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-grain-no-duration-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-loop-grain-no-duration.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-grain-no-duration.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-loop-grain-no-duration.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-grain-no-duration.html
index 2cde4dce..e6f4fe2 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-loop-grain-no-duration.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-grain-no-duration.html
@@ -3,10 +3,10 @@
 
 <head>
   <title>Test AudioBufferSourceNode looping without explicit duration</title>
-  <script src="../resources/js-test.js"></script>
-  <script src="resources/compatibility.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
+  <script src="../../resources/js-test.js"></script>
+  <script src="../resources/compatibility.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-loop-points-expected.wav b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-points-expected.wav
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-loop-points-expected.wav
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-points-expected.wav
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-loop-points.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-points.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-loop-points.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-points.html
index 7e066f81..acfd67b 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-loop-points.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-points.html
@@ -6,8 +6,8 @@
 
 <html>
 <head>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
 
 </head>
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-multi-channels-expected.wav b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-multi-channels-expected.wav
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-multi-channels-expected.wav
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-multi-channels-expected.wav
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-multi-channels.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-multi-channels.html
similarity index 80%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-multi-channels.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-multi-channels.html
index 14cfa62d..8fed30e 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-multi-channels.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-multi-channels.html
@@ -6,9 +6,9 @@
 
 <html>
 <head>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script type="text/javascript" src="resources/mix-testing.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script type="text/javascript" src="../resources/mix-testing.js"></script>
 </head>
 <body>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-one-sample-loop-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-one-sample-loop-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-one-sample-loop-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-one-sample-loop-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-one-sample-loop.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-one-sample-loop.html
similarity index 88%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-one-sample-loop.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-one-sample-loop.html
index 5fa1fd9..cd20529 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-one-sample-loop.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-one-sample-loop.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test AudioBufferSourceNode With Looping a Single-Sample Buffer</title>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-playbackrate-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-playbackrate-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-playbackrate-modulated-impulse-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-modulated-impulse-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-playbackrate-modulated-impulse-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-modulated-impulse-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-playbackrate-modulated-impulse.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-modulated-impulse.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-playbackrate-modulated-impulse.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-modulated-impulse.html
index f90ed4c..df50599 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-playbackrate-modulated-impulse.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-modulated-impulse.html
@@ -2,10 +2,10 @@
 <html>
 
 <head>
-  <script src="../resources/js-test.js"></script>
-  <script src="resources/compatibility.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
+  <script src="../../resources/js-test.js"></script>
+  <script src="../resources/compatibility.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-playbackrate-modulation-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-modulation-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-playbackrate-modulation-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-modulation-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-playbackrate-modulation-expected.wav b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-modulation-expected.wav
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-playbackrate-modulation-expected.wav
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-modulation-expected.wav
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-playbackrate-modulation.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-modulation.html
similarity index 89%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-playbackrate-modulation.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-modulation.html
index 339f9fd..5803fab 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-playbackrate-modulation.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-modulation.html
@@ -2,12 +2,12 @@
 <html>
 
 <head>
-  <script src="../resources/js-test.js"></script>
-  <script src="resources/compatibility.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
-  <script src="resources/audiobuffersource-testing.js"></script>
-  <script src="resources/buffer-loader.js"></script>
+  <script src="../../resources/js-test.js"></script>
+  <script src="../resources/compatibility.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
+  <script src="../resources/audiobuffersource-testing.js"></script>
+  <script src="../resources/buffer-loader.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-playbackrate-zero-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-zero-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-playbackrate-zero-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-zero-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-playbackrate-zero.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-zero.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-playbackrate-zero.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-zero.html
index 24121fef..f205937d 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-playbackrate-zero.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate-zero.html
@@ -2,10 +2,10 @@
 <html>
 
 <head>
-  <script src="../resources/js-test.js"></script>
-  <script src="resources/compatibility.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
+  <script src="../../resources/js-test.js"></script>
+  <script src="../resources/compatibility.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-playbackrate.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-playbackrate.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate.html
index d490ae2..f1afb9b6 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-playbackrate.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-playbackrate.html
@@ -2,10 +2,10 @@
 <html>
 <head>
   <title>AudioBufferSourceNode - playbackRate test</title>
-  <script src="../resources/js-test.js"></script>
-  <script src="resources/compatibility.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
+  <script src="../../resources/js-test.js"></script>
+  <script src="../resources/compatibility.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
 </head>
 <body>
   <script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-premature-loop-stop-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-premature-loop-stop-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-premature-loop-stop-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-premature-loop-stop-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-premature-loop-stop.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-premature-loop-stop.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-premature-loop-stop.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-premature-loop-stop.html
index 3c49dbc..2155a3ad 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-premature-loop-stop.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-premature-loop-stop.html
@@ -3,10 +3,10 @@
 
 <head>
   <title>Test AudioBufferSourceNode premature loop stop</title>
-  <script src="../resources/js-test.js"></script>
-  <script src="resources/compatibility.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
+  <script src="../../resources/js-test.js"></script>
+  <script src="../resources/compatibility.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-start-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-start-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-start-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-start-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-start.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-start.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource-start.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-start.html
index 353471c..77fa91f5 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-start.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-start.html
@@ -2,11 +2,11 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/audiobuffersource-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script src="../resources/audiobuffersource-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource.html
similarity index 76%
rename from third_party/WebKit/LayoutTests/webaudio/audiobuffersource.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource.html
index 75e0724..27ca96f 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiobuffersource.html
@@ -6,9 +6,10 @@
 
 <html>
 <head>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script type="text/javascript" src="resources/buffer-loader.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script type="text/javascript" src="../resources/buffer-loader.js"></script>
 
 <script>
 
@@ -30,7 +31,7 @@
     bufferLoader = new BufferLoader(
         context,
         [
-            "resources/hyper-reality/br-jam-loop.wav",
+            "../resources/hyper-reality/br-jam-loop.wav",
         ],
         finishedLoading
     );
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiosource-onended-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiosource-onended-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiosource-onended-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiosource-onended-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiosource-onended.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiosource-onended.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/webaudio/audiosource-onended.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiosource-onended.html
index 9ba0b93..13bb9ec 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiosource-onended.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiosource-onended.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test Onended Event Listener</title>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiosource-premature-gc-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiosource-premature-gc-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiosource-premature-gc-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiosource-premature-gc-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiosource-premature-gc.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiosource-premature-gc.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/webaudio/audiosource-premature-gc.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiosource-premature-gc.html
index 92f29dd..a57cf9d 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiosource-premature-gc.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiosource-premature-gc.html
@@ -2,9 +2,9 @@
 <html>
   <head>
     <title>Test premature GC upon OscillatorNode and AudioBufferSourceNode</title>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiosource-time-limits-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiosource-time-limits-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiosource-time-limits-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiosource-time-limits-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiosource-time-limits.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiosource-time-limits.html
similarity index 87%
rename from third_party/WebKit/LayoutTests/webaudio/audiosource-time-limits.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiosource-time-limits.html
index 2760110..5893bdb 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiosource-time-limits.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/audiosource-time-limits.html
@@ -1,11 +1,11 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/audioparam-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/audioparam-testing.js"></script>
     <title>Test Scheduled Sources with Huge Time Limits</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/note-grain-on-play-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/note-grain-on-play-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/note-grain-on-play-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/note-grain-on-play-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/note-grain-on-play.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/note-grain-on-play.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/webaudio/note-grain-on-play.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/note-grain-on-play.html
index 4b54255..dc8640d7 100644
--- a/third_party/WebKit/LayoutTests/webaudio/note-grain-on-play.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/note-grain-on-play.html
@@ -1,11 +1,11 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/note-grain-on-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/note-grain-on-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/note-grain-on-timing-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/note-grain-on-timing-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/note-grain-on-timing-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/note-grain-on-timing-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/note-grain-on-timing.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/note-grain-on-timing.html
similarity index 83%
rename from third_party/WebKit/LayoutTests/webaudio/note-grain-on-timing.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/note-grain-on-timing.html
index c305576..40c1cae 100644
--- a/third_party/WebKit/LayoutTests/webaudio/note-grain-on-timing.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/note-grain-on-timing.html
@@ -1,11 +1,11 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/note-grain-on-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/note-grain-on-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/sample-accurate-scheduling-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/sample-accurate-scheduling-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/sample-accurate-scheduling-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/sample-accurate-scheduling-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/sample-accurate-scheduling.html b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/sample-accurate-scheduling.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/webaudio/sample-accurate-scheduling.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/sample-accurate-scheduling.html
index f570671..3c73ba69 100644
--- a/third_party/WebKit/LayoutTests/webaudio/sample-accurate-scheduling.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioBufferSource/sample-accurate-scheduling.html
@@ -7,11 +7,11 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script type="text/javascript" src="resources/buffer-loader.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script type="text/javascript" src="../resources/buffer-loader.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiocontext-close-basic-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-close-basic-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiocontext-close-basic-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-close-basic-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiocontext-close-basic.html b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-close-basic.html
similarity index 86%
rename from third_party/WebKit/LayoutTests/webaudio/audiocontext-close-basic.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-close-basic.html
index bbb47ae3..b0dcd02 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiocontext-close-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-close-basic.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test AudioContext.close() closes many contexts</title>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiocontext-close-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-close-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiocontext-close-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-close-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiocontext-close.html b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-close.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/webaudio/audiocontext-close.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-close.html
index eb4820a..7a42ad6 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiocontext-close.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-close.html
@@ -2,10 +2,10 @@
 <html>
 <head>
   <title>Test AudioContext.close()</title>
-  <script src="../resources/js-test.js"></script>
-  <script src="resources/compatibility.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
+  <script src="../../resources/js-test.js"></script>
+  <script src="../resources/compatibility.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiocontext-listener-should-not-crash-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-listener-should-not-crash-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiocontext-listener-should-not-crash-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-listener-should-not-crash-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiocontext-listener-should-not-crash.html b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-listener-should-not-crash.html
similarity index 76%
rename from third_party/WebKit/LayoutTests/webaudio/audiocontext-listener-should-not-crash.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-listener-should-not-crash.html
index 81a13a30..04343cb 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiocontext-listener-should-not-crash.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-listener-should-not-crash.html
@@ -1,4 +1,4 @@
-<script src="../resources/js-test.js"></script>
+<script src="../../resources/js-test.js"></script>
 <script>
 var context = new AudioContext();
 context.listener;
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiocontext-lock-threading-race-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-lock-threading-race-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiocontext-lock-threading-race-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-lock-threading-race-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiocontext-lock-threading-race.html b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-lock-threading-race.html
similarity index 84%
rename from third_party/WebKit/LayoutTests/webaudio/audiocontext-lock-threading-race.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-lock-threading-race.html
index 4e0af41..f55791e8 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiocontext-lock-threading-race.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-lock-threading-race.html
@@ -1,5 +1,5 @@
 <body>
-<script src="../resources/js-test.js"></script>
+<script src="../../resources/js-test.js"></script>
 <script>
 description("TSan shouldn't complain about threading races of AudioContext::lock().");
 var jsTestAsync = true;
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiocontext-max-contexts-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-max-contexts-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiocontext-max-contexts-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-max-contexts-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiocontext-max-contexts.html b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-max-contexts.html
similarity index 77%
rename from third_party/WebKit/LayoutTests/webaudio/audiocontext-max-contexts.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-max-contexts.html
index 256f237..afbedef 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiocontext-max-contexts.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-max-contexts.html
@@ -1,8 +1,8 @@
 <!DOCTYPE html>
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
 </head>
 <body>
 <script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiocontext-properties.html b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-properties.html
similarity index 66%
rename from third_party/WebKit/LayoutTests/webaudio/audiocontext-properties.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-properties.html
index fe9b5e8..07aace2 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiocontext-properties.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-properties.html
@@ -2,11 +2,11 @@
 <html>
 <head>
   <title>Testing AudioContext properties</title>
-  <script src="../resources/testharness.js"></script>
-  <script src="../resources/testharnessreport.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
-  <script src="resources/context-properties.js"></script>
+  <script src="../../resources/testharness.js"></script>
+  <script src="../../resources/testharnessreport.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
+  <script src="../resources/context-properties.js"></script>
 </head>
 <body>
   <script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiocontext-suspend-resume-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-suspend-resume-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiocontext-suspend-resume-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-suspend-resume-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiocontext-suspend-resume.html b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-suspend-resume.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/webaudio/audiocontext-suspend-resume.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-suspend-resume.html
index a3b7bced..e7115aa 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiocontext-suspend-resume.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioContext/audiocontext-suspend-resume.html
@@ -2,10 +2,10 @@
 <html>
 <head>
   <title>Test AudioContext.suspend() and AudioContext.resume()</title>
-  <script src="../resources/js-test.js"></script>
-  <script src="resources/compatibility.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
+  <script src="../../resources/js-test.js"></script>
+  <script src="../resources/compatibility.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiolistener-automation-basic-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioListener/audiolistener-automation-basic-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiolistener-automation-basic-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioListener/audiolistener-automation-basic-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiolistener-automation-position-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioListener/audiolistener-automation-position-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiolistener-automation-position-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioListener/audiolistener-automation-position-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiolistener-automation-position.html b/third_party/WebKit/LayoutTests/webaudio/AudioListener/audiolistener-automation-position.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/webaudio/audiolistener-automation-position.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioListener/audiolistener-automation-position.html
index ca2a2be..4fe126c 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiolistener-automation-position.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioListener/audiolistener-automation-position.html
@@ -1,10 +1,10 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
     <title>Test Automation of AudioListener</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audionode-channel-rules-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-channel-rules-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audionode-channel-rules-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-channel-rules-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audionode-channel-rules.html b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-channel-rules.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/webaudio/audionode-channel-rules.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-channel-rules.html
index bf61aaa..9abd5f1 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audionode-channel-rules.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-channel-rules.html
@@ -2,11 +2,11 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/mixing-rules.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script src="../resources/mixing-rules.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audionode-connect-method-chaining-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-connect-method-chaining-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audionode-connect-method-chaining-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-connect-method-chaining-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audionode-connect-method-chaining.html b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-connect-method-chaining.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/webaudio/audionode-connect-method-chaining.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-connect-method-chaining.html
index 6a3ddb0..86ce4921 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audionode-connect-method-chaining.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-connect-method-chaining.html
@@ -2,10 +2,10 @@
 <html>
 
 <head>
-  <script src="../resources/js-test.js"></script>
-  <script src="resources/compatibility.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
+  <script src="../../resources/js-test.js"></script>
+  <script src="../resources/compatibility.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audionode-connect-order-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-connect-order-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audionode-connect-order-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-connect-order-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audionode-connect-order.html b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-connect-order.html
similarity index 89%
rename from third_party/WebKit/LayoutTests/webaudio/audionode-connect-order.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-connect-order.html
index 9c51356..8065033 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audionode-connect-order.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-connect-order.html
@@ -2,10 +2,10 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audionode-disconnect-audioparam-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-disconnect-audioparam-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audionode-disconnect-audioparam-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-disconnect-audioparam-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audionode-disconnect-audioparam.html b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-disconnect-audioparam.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/webaudio/audionode-disconnect-audioparam.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-disconnect-audioparam.html
index edddf7c..a3cbbf55 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audionode-disconnect-audioparam.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-disconnect-audioparam.html
@@ -2,10 +2,10 @@
 <html>
 
 <head>
-  <script src="../resources/js-test.js"></script>
-  <script src="resources/compatibility.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
+  <script src="../../resources/js-test.js"></script>
+  <script src="../resources/compatibility.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audionode-disconnect-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-disconnect-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audionode-disconnect-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-disconnect-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audionode-disconnect.html b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-disconnect.html
similarity index 97%
rename from third_party/WebKit/LayoutTests/webaudio/audionode-disconnect.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-disconnect.html
index 2cb04ba8..1ffa3d8b 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audionode-disconnect.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-disconnect.html
@@ -2,10 +2,10 @@
 <html>
 
 <head>
-  <script src="../resources/js-test.js"></script>
-  <script src="resources/compatibility.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
+  <script src="../../resources/js-test.js"></script>
+  <script src="../resources/compatibility.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audionode-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audionode-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audionode.html b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/webaudio/audionode.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode.html
index cd47a0a..c4dd1dc1 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audionode.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioNode/audionode.html
@@ -2,10 +2,10 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/channel-mode-interp-basic.html b/third_party/WebKit/LayoutTests/webaudio/AudioNode/channel-mode-interp-basic.html
similarity index 88%
rename from third_party/WebKit/LayoutTests/webaudio/channel-mode-interp-basic.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioNode/channel-mode-interp-basic.html
index ab11e10..6805878 100644
--- a/third_party/WebKit/LayoutTests/webaudio/channel-mode-interp-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioNode/channel-mode-interp-basic.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test Setting of channelCountMode and channelInterpretation</title>
-    <script src="../resources/testharness.js"></script>
-    <script src="../resources/testharnessreport.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/testharness.js"></script>
+    <script src="../../resources/testharnessreport.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/cycle-connection-gc-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioNode/cycle-connection-gc-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/cycle-connection-gc-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioNode/cycle-connection-gc-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/cycle-connection-gc.html b/third_party/WebKit/LayoutTests/webaudio/AudioNode/cycle-connection-gc.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/webaudio/cycle-connection-gc.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioNode/cycle-connection-gc.html
index e113145..02730502 100644
--- a/third_party/WebKit/LayoutTests/webaudio/cycle-connection-gc.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioNode/cycle-connection-gc.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<script src="../resources/js-test.js"></script>
+<script src="../../resources/js-test.js"></script>
 <script>
 description('Cycles of AudioNode connections should be collected.');
 var context = new OfflineAudioContext(2, 44100, 44100);
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-automation-clamping-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-automation-clamping-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-automation-clamping-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-automation-clamping-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-automation-clamping.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-automation-clamping.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-automation-clamping.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-automation-clamping.html
index e994fb2..80ad4c9 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-automation-clamping.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-automation-clamping.html
@@ -1,10 +1,10 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
     <title>Test Clamping of Automations</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-clamp-time-to-current-time.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-clamp-time-to-current-time.html
similarity index 97%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-clamp-time-to-current-time.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-clamp-time-to-current-time.html
index 6c1217d0..478b4e6 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-clamp-time-to-current-time.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-clamp-time-to-current-time.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test Clamping of AudioParam Time</title>
-    <script src="../resources/testharness.js"></script>
-    <script src="../resources/testharnessreport.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/testharness.js"></script>
+    <script src="../../resources/testharnessreport.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-connect-audioratesignal-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-connect-audioratesignal-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-connect-audioratesignal-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-connect-audioratesignal-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-connect-audioratesignal.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-connect-audioratesignal.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-connect-audioratesignal.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-connect-audioratesignal.html
index 083e219a..cacced01 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-connect-audioratesignal.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-connect-audioratesignal.html
@@ -11,10 +11,10 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
 
 </head>
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-exceptional-values-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-exceptional-values-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-exceptional-values-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-exceptional-values-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-exceptional-values.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-exceptional-values.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-exceptional-values.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-exceptional-values.html
index cf50a45d..c8342a3 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-exceptional-values.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-exceptional-values.html
@@ -1,8 +1,8 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
-    <script src="resources/compatibility.js"></script>
-    <script src="../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../../resources/js-test.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-exponentialRampToValueAtTime-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-exponentialRampToValueAtTime-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-exponentialRampToValueAtTime-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-exponentialRampToValueAtTime-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-exponentialRampToValueAtTime.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-exponentialRampToValueAtTime.html
similarity index 88%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-exponentialRampToValueAtTime.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-exponentialRampToValueAtTime.html
index 62a6cb2..920e90e 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-exponentialRampToValueAtTime.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-exponentialRampToValueAtTime.html
@@ -1,11 +1,11 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/audioparam-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/audioparam-testing.js"></script>
     <title>Test AudioParam.exponentialRampToValueAtTime</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-initial-event-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-initial-event-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-initial-event-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-initial-event-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-initial-event.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-initial-event.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-initial-event.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-initial-event.html
index 15b4843..dbada25 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-initial-event.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-initial-event.html
@@ -2,11 +2,11 @@
 <html>
 
 <head>
-  <script src="../resources/js-test.js"></script>
-  <script src="resources/compatibility.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
-  <script src="resources/audioparam-testing.js"></script>
+  <script src="../../resources/js-test.js"></script>
+  <script src="../resources/compatibility.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
+  <script src="../resources/audioparam-testing.js"></script>
   <title>AudioParam Initial Events </title>
 </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-large-endtime-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-large-endtime-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-large-endtime-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-large-endtime-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-large-endtime.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-large-endtime.html
similarity index 90%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-large-endtime.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-large-endtime.html
index 0e25ef62..70c56ab 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-large-endtime.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-large-endtime.html
@@ -1,10 +1,10 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
     <title>AudioParam with Huge End Time</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-linearRamp-value-attribute-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-linearRamp-value-attribute-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-linearRamp-value-attribute-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-linearRamp-value-attribute-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-linearRamp-value-attribute.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-linearRamp-value-attribute.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-linearRamp-value-attribute.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-linearRamp-value-attribute.html
index 58680ef2..cf1b4cd 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-linearRamp-value-attribute.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-linearRamp-value-attribute.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test linearRampToValue Updates the Param Value</title>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-linearRampToValueAtTime-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-linearRampToValueAtTime-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-linearRampToValueAtTime-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-linearRampToValueAtTime-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-linearRampToValueAtTime.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-linearRampToValueAtTime.html
similarity index 86%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-linearRampToValueAtTime.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-linearRampToValueAtTime.html
index 033ca06..2d8601a 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-linearRampToValueAtTime.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-linearRampToValueAtTime.html
@@ -1,11 +1,11 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/audioparam-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script src="../resources/audioparam-testing.js"></script>
 <title>Test AudioParam.linearRampToValueAtTime</title>
 </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-method-chaining-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-method-chaining-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-method-chaining-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-method-chaining-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-method-chaining.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-method-chaining.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-method-chaining.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-method-chaining.html
index 6100ebe..ebdea00 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-method-chaining.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-method-chaining.html
@@ -2,11 +2,11 @@
 <html>
 
 <head>
-  <script src="../resources/js-test.js"></script>
-  <script src="resources/compatibility.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
-  <script src="resources/audioparam-testing.js"></script>
+  <script src="../../resources/js-test.js"></script>
+  <script src="../resources/compatibility.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
+  <script src="../resources/audioparam-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-negative-exponentialRamp-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-negative-exponentialRamp-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-negative-exponentialRamp-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-negative-exponentialRamp-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-negative-exponentialRamp.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-negative-exponentialRamp.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-negative-exponentialRamp.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-negative-exponentialRamp.html
index 0d79c209..7f9788c 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-negative-exponentialRamp.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-negative-exponentialRamp.html
@@ -1,10 +1,10 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
     <title>Test Negative AudioParam.exponentialRampToValueAtTime</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-nominal-range-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-nominal-range-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-nominal-range-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-nominal-range-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-nominal-range.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-nominal-range.html
similarity index 98%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-nominal-range.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-nominal-range.html
index 0a974fa8..2d4fb750 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-nominal-range.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-nominal-range.html
@@ -1,10 +1,10 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
     <title>Test AudioParam Nominal Range Values</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-sampling-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-sampling-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-sampling-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-sampling-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-sampling.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-sampling.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-sampling.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-sampling.html
index 522ee8c..807bad8 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-sampling.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-sampling.html
@@ -1,11 +1,11 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/audioparam-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/audioparam-testing.js"></script>
     <title>Test Sampling of LinearRampToValueAtTime</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTarget-timeConstant-0.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTarget-timeConstant-0.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-setTarget-timeConstant-0.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTarget-timeConstant-0.html
index 997607eb..9445843 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTarget-timeConstant-0.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTarget-timeConstant-0.html
@@ -2,9 +2,9 @@
 <html>
   <head>
     <title>Test setTargetAtTime with timeConstant=0</title>
-    <script src="../resources/testharness.js"></script>
-    <script src="../resources/testharnessreport.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/testharness.js"></script>
+    <script src="../../resources/testharnessreport.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-continuous-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-continuous-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-continuous-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-continuous-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-continuous.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-continuous.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-continuous.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-continuous.html
index da3bce04..2ca542b2 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-continuous.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-continuous.html
@@ -1,11 +1,11 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/audioparam-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/audioparam-testing.js"></script>
     <title>SetTarget Followed by Linear or Exponential Ramp Is Continuous</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-limit-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-limit-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-limit-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-limit-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-limit.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-limit.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-limit.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-limit.html
index 2034945f2..261ffd4d 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-limit.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-limit.html
@@ -2,11 +2,11 @@
 <html>
   <head>
     <title>Test setTargetAtTime Approach to Limit</title>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/audioparam-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/audioparam-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-sampling-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-sampling-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-sampling-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-sampling-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-sampling.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-sampling.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-sampling.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-sampling.html
index 92f0b6c..b1f357b 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-sampling.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-sampling.html
@@ -1,11 +1,11 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/audioparam-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/audioparam-testing.js"></script>
     <title>Test Sampling for SetTargetAtTime</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime.html
similarity index 86%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime.html
index d8c92f72..8dc95136 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime.html
@@ -1,11 +1,11 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/audioparam-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script src="../resources/audioparam-testing.js"></script>
 <title>Test AudioParam.setTargetAtTime</title>
 </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueAtTime-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueAtTime-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-setValueAtTime-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueAtTime-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueAtTime.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueAtTime.html
similarity index 84%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-setValueAtTime.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueAtTime.html
index 142753b..b190086 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueAtTime.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueAtTime.html
@@ -1,11 +1,11 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/audioparam-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script src="../resources/audioparam-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-copy-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-copy-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-copy-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-copy-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-copy.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-copy.html
similarity index 91%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-copy.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-copy.html
index 8d9f4fe..e4626495 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-copy.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-copy.html
@@ -1,11 +1,11 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/panner-formulas.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/panner-formulas.js"></script>
     <title>Test setValueCurveAtTime Copies the Curve Data</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-duration-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-duration-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-duration-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-duration-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-duration.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-duration.html
similarity index 88%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-duration.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-duration.html
index f25eade..be8bed96 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-duration.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-duration.html
@@ -1,11 +1,11 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/audioparam-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/audioparam-testing.js"></script>
     <title>Test setValueCurveAtTime with Huge Duration</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-end-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-end-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-end-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-end-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-end.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-end.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-end.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-end.html
index 38c0dac3..8726afe 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-end.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-end.html
@@ -2,11 +2,11 @@
 <html>
   <head>
     <title>Test Automation Following setValueCurveAtTime Automations</title>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/audio-param.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/audio-param.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-exceptions-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-exceptions-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-exceptions-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-exceptions-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-exceptions.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-exceptions.html
similarity index 97%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-exceptions.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-exceptions.html
index 3b6773c..c899520 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-exceptions.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurve-exceptions.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test Exceptions from setValueCurveAtTime</title>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurveAtTime-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurveAtTime-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurveAtTime-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurveAtTime-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurveAtTime-interpolation-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurveAtTime-interpolation-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurveAtTime-interpolation-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurveAtTime-interpolation-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurveAtTime-interpolation.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurveAtTime-interpolation.html
similarity index 97%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurveAtTime-interpolation.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurveAtTime-interpolation.html
index ad3ca707..677af894 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurveAtTime-interpolation.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurveAtTime-interpolation.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test Interpolation for AudioParam.setValueCurveAtTime</title>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
     <title>Test Interpolation for AudioParam.setValueCurveAtTime</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurveAtTime.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurveAtTime.html
similarity index 88%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurveAtTime.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurveAtTime.html
index fba07e10..4af17d8 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurveAtTime.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-setValueCurveAtTime.html
@@ -1,11 +1,11 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/audioparam-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script src="../resources/audioparam-testing.js"></script>
 <title>Test AudioParam.setValueCurveAtTime</title>
 </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-summingjunction-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-summingjunction-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-summingjunction-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-summingjunction-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-summingjunction.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-summingjunction.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-summingjunction.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-summingjunction.html
index 224445a..432536a 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-summingjunction.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-summingjunction.html
@@ -7,11 +7,11 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/mix-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script src="../resources/mix-testing.js"></script>
 
 </head>
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-update-value-attribute-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-update-value-attribute-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-update-value-attribute-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-update-value-attribute-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-update-value-attribute.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-update-value-attribute.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/webaudio/audioparam-update-value-attribute.html
rename to third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-update-value-attribute.html
index 3fc45d5..4a3fefb 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-update-value-attribute.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-update-value-attribute.html
@@ -1,11 +1,11 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/audio-param.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/audio-param.js"></script>
     <title>Updating of Value Attribute from Timeline</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/baseaudiocontext-properties.html b/third_party/WebKit/LayoutTests/webaudio/BaseAudioContext/baseaudiocontext-properties.html
similarity index 66%
rename from third_party/WebKit/LayoutTests/webaudio/baseaudiocontext-properties.html
rename to third_party/WebKit/LayoutTests/webaudio/BaseAudioContext/baseaudiocontext-properties.html
index d944c78..ca7ba3305 100644
--- a/third_party/WebKit/LayoutTests/webaudio/baseaudiocontext-properties.html
+++ b/third_party/WebKit/LayoutTests/webaudio/BaseAudioContext/baseaudiocontext-properties.html
@@ -2,11 +2,11 @@
 <html>
 <head>
   <title>Testing BaseAudioContext properties</title>
-  <script src="../resources/testharness.js"></script>
-  <script src="../resources/testharnessreport.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
-  <script src="resources/context-properties.js"></script>
+  <script src="../../resources/testharness.js"></script>
+  <script src="../../resources/testharnessreport.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
+  <script src="../resources/context-properties.js"></script>
 </head>
 <body>
   <script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-allpass-expected.txt b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-allpass-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/biquad-allpass-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-allpass-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-allpass.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-allpass.html
similarity index 74%
rename from third_party/WebKit/LayoutTests/webaudio/biquad-allpass.html
rename to third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-allpass.html
index 8706e6c..6d8c9fa3 100644
--- a/third_party/WebKit/LayoutTests/webaudio/biquad-allpass.html
+++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-allpass.html
@@ -2,12 +2,12 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/biquad-filters.js"></script>
-<script src="resources/biquad-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script src="../resources/biquad-filters.js"></script>
+<script src="../resources/biquad-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-automation-expected.txt b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-automation-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/biquad-automation-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-automation-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-automation.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-automation.html
similarity index 97%
rename from third_party/WebKit/LayoutTests/webaudio/biquad-automation.html
rename to third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-automation.html
index 4d630ea..d664018 100644
--- a/third_party/WebKit/LayoutTests/webaudio/biquad-automation.html
+++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-automation.html
@@ -2,12 +2,12 @@
 <html>
   <head>
     <title>Biquad Automation Test</title>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/biquad-filters.js"></script>
-    <script src="resources/audioparam-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/biquad-filters.js"></script>
+    <script src="../resources/audioparam-testing.js"></script>
   </head>
   <body>
     <script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-bandpass-expected.txt b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-bandpass-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/biquad-bandpass-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-bandpass-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-bandpass.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-bandpass.html
similarity index 75%
rename from third_party/WebKit/LayoutTests/webaudio/biquad-bandpass.html
rename to third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-bandpass.html
index e5a101b..5dafe2a 100644
--- a/third_party/WebKit/LayoutTests/webaudio/biquad-bandpass.html
+++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-bandpass.html
@@ -2,12 +2,12 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/biquad-filters.js"></script>
-<script src="resources/biquad-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script src="../resources/biquad-filters.js"></script>
+<script src="../resources/biquad-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-getFrequencyResponse-expected.txt b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-getFrequencyResponse-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/biquad-getFrequencyResponse-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-getFrequencyResponse-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-getFrequencyResponse.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-getFrequencyResponse.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/webaudio/biquad-getFrequencyResponse.html
rename to third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-getFrequencyResponse.html
index 961c56b99..bbc1847 100644
--- a/third_party/WebKit/LayoutTests/webaudio/biquad-getFrequencyResponse.html
+++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-getFrequencyResponse.html
@@ -1,12 +1,12 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/biquad-filters.js"></script>
-<script src="resources/biquad-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script src="../resources/biquad-filters.js"></script>
+<script src="../resources/biquad-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-highpass-expected.txt b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-highpass-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/biquad-highpass-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-highpass-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-highpass.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-highpass.html
similarity index 73%
rename from third_party/WebKit/LayoutTests/webaudio/biquad-highpass.html
rename to third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-highpass.html
index 62dacd03..b0822ea 100644
--- a/third_party/WebKit/LayoutTests/webaudio/biquad-highpass.html
+++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-highpass.html
@@ -2,12 +2,12 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/biquad-filters.js"></script>
-<script src="resources/biquad-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script src="../resources/biquad-filters.js"></script>
+<script src="../resources/biquad-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-highshelf-expected.txt b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-highshelf-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/biquad-highshelf-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-highshelf-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-highshelf.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-highshelf.html
similarity index 74%
rename from third_party/WebKit/LayoutTests/webaudio/biquad-highshelf.html
rename to third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-highshelf.html
index 80058f56..3f7b806 100644
--- a/third_party/WebKit/LayoutTests/webaudio/biquad-highshelf.html
+++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-highshelf.html
@@ -2,12 +2,12 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/biquad-filters.js"></script>
-<script src="resources/biquad-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script src="../resources/biquad-filters.js"></script>
+<script src="../resources/biquad-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-lowpass-expected.txt b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-lowpass-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/biquad-lowpass-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-lowpass-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-lowpass.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-lowpass.html
similarity index 76%
rename from third_party/WebKit/LayoutTests/webaudio/biquad-lowpass.html
rename to third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-lowpass.html
index 4336e6d..79f0824 100644
--- a/third_party/WebKit/LayoutTests/webaudio/biquad-lowpass.html
+++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-lowpass.html
@@ -2,12 +2,12 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/biquad-filters.js"></script>
-<script src="resources/biquad-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script src="../resources/biquad-filters.js"></script>
+<script src="../resources/biquad-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-lowshelf-expected.txt b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-lowshelf-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/biquad-lowshelf-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-lowshelf-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-lowshelf.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-lowshelf.html
similarity index 73%
rename from third_party/WebKit/LayoutTests/webaudio/biquad-lowshelf.html
rename to third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-lowshelf.html
index eb0de694e..b2a110a 100644
--- a/third_party/WebKit/LayoutTests/webaudio/biquad-lowshelf.html
+++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-lowshelf.html
@@ -2,12 +2,12 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/biquad-filters.js"></script>
-<script src="resources/biquad-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script src="../resources/biquad-filters.js"></script>
+<script src="../resources/biquad-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-notch-expected.txt b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-notch-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/biquad-notch-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-notch-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-notch.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-notch.html
similarity index 74%
rename from third_party/WebKit/LayoutTests/webaudio/biquad-notch.html
rename to third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-notch.html
index 6de5d7b04..427f71c 100644
--- a/third_party/WebKit/LayoutTests/webaudio/biquad-notch.html
+++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-notch.html
@@ -2,12 +2,12 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/biquad-filters.js"></script>
-<script src="resources/biquad-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script src="../resources/biquad-filters.js"></script>
+<script src="../resources/biquad-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-peaking-expected.txt b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-peaking-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/biquad-peaking-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-peaking-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-peaking.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-peaking.html
similarity index 75%
rename from third_party/WebKit/LayoutTests/webaudio/biquad-peaking.html
rename to third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-peaking.html
index de04f8f5..5db5dc1 100644
--- a/third_party/WebKit/LayoutTests/webaudio/biquad-peaking.html
+++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-peaking.html
@@ -2,12 +2,12 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/biquad-filters.js"></script>
-<script src="resources/biquad-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script src="../resources/biquad-filters.js"></script>
+<script src="../resources/biquad-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-tail-expected.txt b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-tail-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/biquad-tail-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-tail-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-tail.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-tail.html
similarity index 91%
rename from third_party/WebKit/LayoutTests/webaudio/biquad-tail.html
rename to third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-tail.html
index a3972fd6..afa82f1 100644
--- a/third_party/WebKit/LayoutTests/webaudio/biquad-tail.html
+++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-tail.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test Biquad Tail Output</title>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquadfilternode-basic-expected.txt b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquadfilternode-basic-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/biquadfilternode-basic-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquadfilternode-basic-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquadfilternode-basic.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquadfilternode-basic.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/webaudio/biquadfilternode-basic.html
rename to third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquadfilternode-basic.html
index 76559951..4788e92 100644
--- a/third_party/WebKit/LayoutTests/webaudio/biquadfilternode-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquadfilternode-basic.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-basic-expected.txt b/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-basic-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-basic-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-basic-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-basic.html b/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-basic.html
similarity index 90%
rename from third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-basic.html
rename to third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-basic.html
index 4a9d26c..61c36fbc 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-basic.html
@@ -2,10 +2,10 @@
 <html>
 
 <head>
-  <script src="../resources/js-test.js"></script>
-  <script src="resources/compatibility.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
+  <script src="../../resources/js-test.js"></script>
+  <script src="../resources/compatibility.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-cycle-expected.txt b/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-cycle-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-cycle-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-cycle-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-cycle.html b/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-cycle.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-cycle.html
rename to third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-cycle.html
index 144c871..d533645ac 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-cycle.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-cycle.html
@@ -2,10 +2,10 @@
 <html>
 
 <head>
-  <script src="../resources/js-test.js"></script>
-  <script src="resources/compatibility.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
+  <script src="../../resources/js-test.js"></script>
+  <script src="../resources/compatibility.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-disconnect-expected.txt b/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-disconnect-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-disconnect-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-disconnect-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-disconnect.html b/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-disconnect.html
similarity index 91%
rename from third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-disconnect.html
rename to third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-disconnect.html
index 6ff41f8..ec4da60 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-disconnect.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-disconnect.html
@@ -2,10 +2,10 @@
 <html>
 
 <head>
-  <script src="../resources/js-test.js"></script>
-  <script src="resources/compatibility.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
+  <script src="../../resources/js-test.js"></script>
+  <script src="../resources/compatibility.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-input-expected.txt b/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-input-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-input-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-input-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-input-non-default-expected.txt b/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-input-non-default-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-input-non-default-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-input-non-default-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-input-non-default.html b/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-input-non-default.html
similarity index 89%
rename from third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-input-non-default.html
rename to third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-input-non-default.html
index d260651..4a7ced76 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-input-non-default.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-input-non-default.html
@@ -2,11 +2,11 @@
 <html>
 
 <head>
-  <script src="../resources/js-test.js"></script>
-  <script src="resources/compatibility.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
-  <script src="resources/merger-testing.js"></script>
+  <script src="../../resources/js-test.js"></script>
+  <script src="../resources/compatibility.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
+  <script src="../resources/merger-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-input.html b/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-input.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-input.html
rename to third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-input.html
index 7960e71..706d7e9 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-input.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ChannelMerger/audiochannelmerger-input.html
@@ -2,11 +2,11 @@
 <html>
 
 <head>
-  <script src="../resources/js-test.js"></script>
-  <script src="resources/compatibility.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
-  <script src="resources/merger-testing.js"></script>
+  <script src="../../resources/js-test.js"></script>
+  <script src="../resources/compatibility.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
+  <script src="../resources/merger-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiochannelsplitter-expected.txt b/third_party/WebKit/LayoutTests/webaudio/ChannelSplitter/audiochannelsplitter-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/audiochannelsplitter-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/ChannelSplitter/audiochannelsplitter-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiochannelsplitter.html b/third_party/WebKit/LayoutTests/webaudio/ChannelSplitter/audiochannelsplitter.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/webaudio/audiochannelsplitter.html
rename to third_party/WebKit/LayoutTests/webaudio/ChannelSplitter/audiochannelsplitter.html
index 9d6d75b4..c97d1ca 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiochannelsplitter.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ChannelSplitter/audiochannelsplitter.html
@@ -6,10 +6,10 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/constant-source-basic.html b/third_party/WebKit/LayoutTests/webaudio/ConstantSource/constant-source-basic.html
similarity index 91%
rename from third_party/WebKit/LayoutTests/webaudio/constant-source-basic.html
rename to third_party/WebKit/LayoutTests/webaudio/ConstantSource/constant-source-basic.html
index c24dc8c..5f05b379 100644
--- a/third_party/WebKit/LayoutTests/webaudio/constant-source-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ConstantSource/constant-source-basic.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Basic ConstantSourceNode Tests</title>
-    <script src="../resources/testharness.js"></script>
-    <script src="../resources/testharnessreport.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/testharness.js"></script>
+    <script src="../../resources/testharnessreport.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/constant-source-onended.html b/third_party/WebKit/LayoutTests/webaudio/ConstantSource/constant-source-onended.html
similarity index 79%
rename from third_party/WebKit/LayoutTests/webaudio/constant-source-onended.html
rename to third_party/WebKit/LayoutTests/webaudio/ConstantSource/constant-source-onended.html
index c9abd03..2ab18c75 100644
--- a/third_party/WebKit/LayoutTests/webaudio/constant-source-onended.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ConstantSource/constant-source-onended.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test ConstantSourceNode onended</title>
-    <script src="../resources/testharness.js"></script>
-    <script src="../resources/testharnessreport.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/testharness.js"></script>
+    <script src="../../resources/testharnessreport.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/constant-source-output.html b/third_party/WebKit/LayoutTests/webaudio/ConstantSource/constant-source-output.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/webaudio/constant-source-output.html
rename to third_party/WebKit/LayoutTests/webaudio/ConstantSource/constant-source-output.html
index 60e76c5..d5ddeec02 100644
--- a/third_party/WebKit/LayoutTests/webaudio/constant-source-output.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ConstantSource/constant-source-output.html
@@ -2,11 +2,11 @@
 <html>
   <head>
     <title>Test ConstantSourceNode Output</title>
-    <script src="../resources/testharness.js"></script>
-    <script src="../resources/testharnessreport.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/audioparam-testing.js"></script>
+    <script src="../../resources/testharness.js"></script>
+    <script src="../../resources/testharnessreport.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/audioparam-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/convolution-mono-mono-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Convolver/convolution-mono-mono-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/convolution-mono-mono-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Convolver/convolution-mono-mono-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/convolution-mono-mono.html b/third_party/WebKit/LayoutTests/webaudio/Convolver/convolution-mono-mono.html
similarity index 86%
rename from third_party/WebKit/LayoutTests/webaudio/convolution-mono-mono.html
rename to third_party/WebKit/LayoutTests/webaudio/Convolver/convolution-mono-mono.html
index 5bf291b3..bebfc00a 100644
--- a/third_party/WebKit/LayoutTests/webaudio/convolution-mono-mono.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Convolver/convolution-mono-mono.html
@@ -2,11 +2,11 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/convolution-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script src="../resources/convolution-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/convolver-channels-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Convolver/convolver-channels-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/convolver-channels-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Convolver/convolver-channels-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/convolver-channels.html b/third_party/WebKit/LayoutTests/webaudio/Convolver/convolver-channels.html
similarity index 87%
rename from third_party/WebKit/LayoutTests/webaudio/convolver-channels.html
rename to third_party/WebKit/LayoutTests/webaudio/Convolver/convolver-channels.html
index dfc37871..5c0a7bb 100644
--- a/third_party/WebKit/LayoutTests/webaudio/convolver-channels.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Convolver/convolver-channels.html
@@ -1,10 +1,10 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
     <title>Test Supported Number of Channels for ConvolverNode</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/convolver-setBuffer-null-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Convolver/convolver-setBuffer-null-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/convolver-setBuffer-null-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Convolver/convolver-setBuffer-null-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/convolver-setBuffer-null.html b/third_party/WebKit/LayoutTests/webaudio/Convolver/convolver-setBuffer-null.html
similarity index 76%
rename from third_party/WebKit/LayoutTests/webaudio/convolver-setBuffer-null.html
rename to third_party/WebKit/LayoutTests/webaudio/Convolver/convolver-setBuffer-null.html
index 778c057f..45b47a0 100644
--- a/third_party/WebKit/LayoutTests/webaudio/convolver-setBuffer-null.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Convolver/convolver-setBuffer-null.html
@@ -1,10 +1,10 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/delaynode-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/delaynode-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/delaynode-max-default-delay-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-default-delay-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/delaynode-max-default-delay-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-default-delay-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/delaynode-max-default-delay.html b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-default-delay.html
similarity index 79%
rename from third_party/WebKit/LayoutTests/webaudio/delaynode-max-default-delay.html
rename to third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-default-delay.html
index 676d9da..9895f2d 100644
--- a/third_party/WebKit/LayoutTests/webaudio/delaynode-max-default-delay.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-default-delay.html
@@ -2,11 +2,11 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/delay-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script src="../resources/delay-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/delaynode-max-nondefault-delay-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-nondefault-delay-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/delaynode-max-nondefault-delay-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-nondefault-delay-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/delaynode-max-nondefault-delay.html b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-nondefault-delay.html
similarity index 80%
rename from third_party/WebKit/LayoutTests/webaudio/delaynode-max-nondefault-delay.html
rename to third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-nondefault-delay.html
index b9e80672b..d0c54ea 100644
--- a/third_party/WebKit/LayoutTests/webaudio/delaynode-max-nondefault-delay.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-nondefault-delay.html
@@ -2,11 +2,11 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/delay-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script src="../resources/delay-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/delaynode-maxdelay-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelay-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/delaynode-maxdelay-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelay-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/delaynode-maxdelay.html b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelay.html
similarity index 82%
rename from third_party/WebKit/LayoutTests/webaudio/delaynode-maxdelay.html
rename to third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelay.html
index 5924e0f..5366aea 100644
--- a/third_party/WebKit/LayoutTests/webaudio/delaynode-maxdelay.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelay.html
@@ -2,11 +2,11 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/delay-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script src="../resources/delay-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/delaynode-maxdelaylimit-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelaylimit-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/delaynode-maxdelaylimit-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelaylimit-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/delaynode-maxdelaylimit.html b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelaylimit.html
similarity index 82%
rename from third_party/WebKit/LayoutTests/webaudio/delaynode-maxdelaylimit.html
rename to third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelaylimit.html
index b163781..58647b61 100644
--- a/third_party/WebKit/LayoutTests/webaudio/delaynode-maxdelaylimit.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelaylimit.html
@@ -2,11 +2,11 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/delay-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script src="../resources/delay-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/delaynode-scheduling-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-scheduling-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/delaynode-scheduling-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-scheduling-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/delaynode-scheduling.html b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-scheduling.html
similarity index 80%
rename from third_party/WebKit/LayoutTests/webaudio/delaynode-scheduling.html
rename to third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-scheduling.html
index ccd1d24..3b1500b 100644
--- a/third_party/WebKit/LayoutTests/webaudio/delaynode-scheduling.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-scheduling.html
@@ -2,11 +2,11 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/delay-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script src="../resources/delay-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/delaynode.html b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode.html
similarity index 82%
rename from third_party/WebKit/LayoutTests/webaudio/delaynode.html
rename to third_party/WebKit/LayoutTests/webaudio/Delay/delaynode.html
index ce6e0b74..c527071 100644
--- a/third_party/WebKit/LayoutTests/webaudio/delaynode.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode.html
@@ -2,11 +2,11 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/delay-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script src="../resources/delay-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/dynamicscompressor-basic-expected.txt b/third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-basic-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/dynamicscompressor-basic-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-basic-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/dynamicscompressor-basic.html b/third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-basic.html
similarity index 90%
rename from third_party/WebKit/LayoutTests/webaudio/dynamicscompressor-basic.html
rename to third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-basic.html
index b0771f6..7c2b8ab 100644
--- a/third_party/WebKit/LayoutTests/webaudio/dynamicscompressor-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-basic.html
@@ -2,10 +2,10 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/dynamicscompressor-clear-internal-state-expected.txt b/third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-clear-internal-state-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/dynamicscompressor-clear-internal-state-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-clear-internal-state-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/dynamicscompressor-clear-internal-state.html b/third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-clear-internal-state.html
similarity index 88%
rename from third_party/WebKit/LayoutTests/webaudio/dynamicscompressor-clear-internal-state.html
rename to third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-clear-internal-state.html
index 66e6193..c3725835 100644
--- a/third_party/WebKit/LayoutTests/webaudio/dynamicscompressor-clear-internal-state.html
+++ b/third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-clear-internal-state.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Validate Reduction Value of DynamicsComporessor after Disabling</title>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/dynamicscompressor-simple-expected.txt b/third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-simple-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/dynamicscompressor-simple-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-simple-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/dynamicscompressor-simple.html b/third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-simple.html
similarity index 91%
rename from third_party/WebKit/LayoutTests/webaudio/dynamicscompressor-simple.html
rename to third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-simple.html
index e82ffb5..c844dca 100644
--- a/third_party/WebKit/LayoutTests/webaudio/dynamicscompressor-simple.html
+++ b/third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-simple.html
@@ -1,10 +1,10 @@
 <!DOCTYPE HTML>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/gain-basic-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Gain/gain-basic-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/gain-basic-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Gain/gain-basic-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/gain-basic.html b/third_party/WebKit/LayoutTests/webaudio/Gain/gain-basic.html
similarity index 74%
rename from third_party/WebKit/LayoutTests/webaudio/gain-basic.html
rename to third_party/WebKit/LayoutTests/webaudio/Gain/gain-basic.html
index fc1d6092..4f74f97 100644
--- a/third_party/WebKit/LayoutTests/webaudio/gain-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Gain/gain-basic.html
@@ -6,10 +6,10 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
 
 </head>
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/gain-expected.wav b/third_party/WebKit/LayoutTests/webaudio/Gain/gain-expected.wav
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/gain-expected.wav
rename to third_party/WebKit/LayoutTests/webaudio/Gain/gain-expected.wav
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/webaudio/gain.html b/third_party/WebKit/LayoutTests/webaudio/Gain/gain.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/webaudio/gain.html
rename to third_party/WebKit/LayoutTests/webaudio/Gain/gain.html
index f3c7549..0a6c2b8 100644
--- a/third_party/WebKit/LayoutTests/webaudio/gain.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Gain/gain.html
@@ -8,8 +8,8 @@
 
 <html>
 <head>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
 
 </head>
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/iirfilter-basic-expected.txt b/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter-basic-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/iirfilter-basic-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter-basic-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/iirfilter-basic.html b/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter-basic.html
similarity index 97%
rename from third_party/WebKit/LayoutTests/webaudio/iirfilter-basic.html
rename to third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter-basic.html
index 267ea80..9639b2a 100644
--- a/third_party/WebKit/LayoutTests/webaudio/iirfilter-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter-basic.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test Basic IIRFilterNode Properties</title>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/iirfilter-expected.txt b/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/iirfilter-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/iirfilter-getFrequencyResponse-expected.txt b/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter-getFrequencyResponse-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/iirfilter-getFrequencyResponse-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter-getFrequencyResponse-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/iirfilter-getFrequencyResponse.html b/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter-getFrequencyResponse.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/webaudio/iirfilter-getFrequencyResponse.html
rename to third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter-getFrequencyResponse.html
index 8f1247f..27c292c 100644
--- a/third_party/WebKit/LayoutTests/webaudio/iirfilter-getFrequencyResponse.html
+++ b/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter-getFrequencyResponse.html
@@ -2,11 +2,11 @@
 <html>
   <head>
     <title>Test IIRFilter getFrequencyResponse() functionality</title>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/biquad-filters.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/biquad-filters.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/iirfilter.html b/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter.html
similarity index 98%
rename from third_party/WebKit/LayoutTests/webaudio/iirfilter.html
rename to third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter.html
index ba51e34..b027f63 100644
--- a/third_party/WebKit/LayoutTests/webaudio/iirfilter.html
+++ b/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter.html
@@ -2,11 +2,11 @@
 <html>
   <head>
     <title>Test Basic IIRFilterNode Operation</title>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/biquad-filters.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/biquad-filters.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/mediaelementaudiosourcenode-expected.txt b/third_party/WebKit/LayoutTests/webaudio/MediaElementAudioSource/mediaelementaudiosourcenode-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/mediaelementaudiosourcenode-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/MediaElementAudioSource/mediaelementaudiosourcenode-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/mediaelementaudiosourcenode-gc-expected.txt b/third_party/WebKit/LayoutTests/webaudio/MediaElementAudioSource/mediaelementaudiosourcenode-gc-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/mediaelementaudiosourcenode-gc-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/MediaElementAudioSource/mediaelementaudiosourcenode-gc-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/mediaelementaudiosourcenode-gc.html b/third_party/WebKit/LayoutTests/webaudio/MediaElementAudioSource/mediaelementaudiosourcenode-gc.html
similarity index 75%
rename from third_party/WebKit/LayoutTests/webaudio/mediaelementaudiosourcenode-gc.html
rename to third_party/WebKit/LayoutTests/webaudio/MediaElementAudioSource/mediaelementaudiosourcenode-gc.html
index 5a14ca0..c5ab59f 100644
--- a/third_party/WebKit/LayoutTests/webaudio/mediaelementaudiosourcenode-gc.html
+++ b/third_party/WebKit/LayoutTests/webaudio/MediaElementAudioSource/mediaelementaudiosourcenode-gc.html
@@ -2,10 +2,10 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/mediaelementaudiosourcenode-wrapper-expected.txt b/third_party/WebKit/LayoutTests/webaudio/MediaElementAudioSource/mediaelementaudiosourcenode-wrapper-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/mediaelementaudiosourcenode-wrapper-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/MediaElementAudioSource/mediaelementaudiosourcenode-wrapper-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/mediaelementaudiosourcenode-wrapper.html b/third_party/WebKit/LayoutTests/webaudio/MediaElementAudioSource/mediaelementaudiosourcenode-wrapper.html
similarity index 72%
rename from third_party/WebKit/LayoutTests/webaudio/mediaelementaudiosourcenode-wrapper.html
rename to third_party/WebKit/LayoutTests/webaudio/MediaElementAudioSource/mediaelementaudiosourcenode-wrapper.html
index 7859b26..3fc50ac 100644
--- a/third_party/WebKit/LayoutTests/webaudio/mediaelementaudiosourcenode-wrapper.html
+++ b/third_party/WebKit/LayoutTests/webaudio/MediaElementAudioSource/mediaelementaudiosourcenode-wrapper.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
 </head>
 <body>
 <script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/mediaelementaudiosourcenode.html b/third_party/WebKit/LayoutTests/webaudio/MediaElementAudioSource/mediaelementaudiosourcenode.html
similarity index 85%
rename from third_party/WebKit/LayoutTests/webaudio/mediaelementaudiosourcenode.html
rename to third_party/WebKit/LayoutTests/webaudio/MediaElementAudioSource/mediaelementaudiosourcenode.html
index d82393e..8fa105f1 100644
--- a/third_party/WebKit/LayoutTests/webaudio/mediaelementaudiosourcenode.html
+++ b/third_party/WebKit/LayoutTests/webaudio/MediaElementAudioSource/mediaelementaudiosourcenode.html
@@ -2,10 +2,10 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/mediastreamaudiodestinationnode-expected.txt b/third_party/WebKit/LayoutTests/webaudio/MediaStreamAudioDestination/mediastreamaudiodestinationnode-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/mediastreamaudiodestinationnode-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/MediaStreamAudioDestination/mediastreamaudiodestinationnode-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/mediastreamaudiodestinationnode.html b/third_party/WebKit/LayoutTests/webaudio/MediaStreamAudioDestination/mediastreamaudiodestinationnode.html
similarity index 87%
rename from third_party/WebKit/LayoutTests/webaudio/mediastreamaudiodestinationnode.html
rename to third_party/WebKit/LayoutTests/webaudio/MediaStreamAudioDestination/mediastreamaudiodestinationnode.html
index f1be1be..66d6c82e 100644
--- a/third_party/WebKit/LayoutTests/webaudio/mediastreamaudiodestinationnode.html
+++ b/third_party/WebKit/LayoutTests/webaudio/MediaStreamAudioDestination/mediastreamaudiodestinationnode.html
@@ -2,10 +2,10 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/mediastreamaudiosourcenode-expected.txt b/third_party/WebKit/LayoutTests/webaudio/MediaStreamAudioSource/mediastreamaudiosourcenode-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/mediastreamaudiosourcenode-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/MediaStreamAudioSource/mediastreamaudiosourcenode-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/mediastreamaudiosourcenode.html b/third_party/WebKit/LayoutTests/webaudio/MediaStreamAudioSource/mediastreamaudiosourcenode.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/webaudio/mediastreamaudiosourcenode.html
rename to third_party/WebKit/LayoutTests/webaudio/MediaStreamAudioSource/mediastreamaudiosourcenode.html
index 96fe30fb..9686de3 100644
--- a/third_party/WebKit/LayoutTests/webaudio/mediastreamaudiosourcenode.html
+++ b/third_party/WebKit/LayoutTests/webaudio/MediaStreamAudioSource/mediastreamaudiosourcenode.html
@@ -2,10 +2,10 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-constructor-expected.txt b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-constructor-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-constructor-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-constructor-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-constructor.html b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-constructor.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-constructor.html
rename to third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-constructor.html
index b80d5d1..df657ca 100644
--- a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-constructor.html
+++ b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-constructor.html
@@ -1,8 +1,8 @@
 <!DOCTYPE html>
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
 </head>
 <body>
 <script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-detached-no-crash-expected.txt b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-detached-no-crash-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-detached-no-crash-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-detached-no-crash-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-detached-no-crash.html b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-detached-no-crash.html
similarity index 84%
rename from third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-detached-no-crash.html
rename to third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-detached-no-crash.html
index 89d2c619..f893a72 100644
--- a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-detached-no-crash.html
+++ b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-detached-no-crash.html
@@ -1,10 +1,10 @@
 <!DOCTYPE HTML>
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
 </head>
 <body>
 <script>
@@ -62,7 +62,7 @@
     testRunner.setCanOpenWindows();
 }
 
-w = window.open('../resources/window-postmessage-open-close.html');
+w = window.open('../../resources/window-postmessage-open-close.html');
 window.addEventListener("message", processMessage, false);
 </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-promise-basic-expected.txt b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-promise-basic-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-promise-basic-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-promise-basic-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-promise-basic.html b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-promise-basic.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-promise-basic.html
rename to third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-promise-basic.html
index 9fff58fb..23b987818 100644
--- a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-promise-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-promise-basic.html
@@ -1,9 +1,9 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/audio-testing.js"/>
-    <script src="resources/compatibility.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/audio-testing.js"/>
+    <script src="../resources/compatibility.js"></script>
     <title>OfflineAudioContext.startRendering Promise</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-promise-expected.txt b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-promise-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-promise-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-promise-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-promise.html b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-promise.html
similarity index 89%
rename from third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-promise.html
rename to third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-promise.html
index 7782da8..cfc5aea 100644
--- a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-promise.html
+++ b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-promise.html
@@ -1,10 +1,10 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
     <title>OfflineAudioContext.startRendering Promise with oncomplete</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-properties.html b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-properties.html
similarity index 67%
rename from third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-properties.html
rename to third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-properties.html
index 43ec269..393e42d 100644
--- a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-properties.html
+++ b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-properties.html
@@ -2,11 +2,11 @@
 <html>
 <head>
   <title>Testing OfflineAudioContext properties</title>
-  <script src="../resources/testharness.js"></script>
-  <script src="../resources/testharnessreport.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
-  <script src="resources/context-properties.js"></script>
+  <script src="../../resources/testharness.js"></script>
+  <script src="../../resources/testharnessreport.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
+  <script src="../resources/context-properties.js"></script>
 </head>
 <body>
   <script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-suspend-resume-basic-expected.txt b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-basic-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-suspend-resume-basic-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-basic-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-suspend-resume-basic.html b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-basic.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-suspend-resume-basic.html
rename to third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-basic.html
index 3d2c42b..4acaf7a 100644
--- a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-suspend-resume-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-basic.html
@@ -1,10 +1,10 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-suspend-resume-eventhandler-expected.txt b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-eventhandler-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-suspend-resume-eventhandler-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-eventhandler-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-suspend-resume-eventhandler.html b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-eventhandler.html
similarity index 91%
rename from third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-suspend-resume-eventhandler.html
rename to third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-eventhandler.html
index 3621189..0ef81eba 100644
--- a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-suspend-resume-eventhandler.html
+++ b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-eventhandler.html
@@ -1,10 +1,10 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-suspend-resume-graph-manipulation-expected.txt b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-graph-manipulation-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-suspend-resume-graph-manipulation-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-graph-manipulation-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-suspend-resume-graph-manipulation.html b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-graph-manipulation.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-suspend-resume-graph-manipulation.html
rename to third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-graph-manipulation.html
index 0e922d2..ece7d86 100644
--- a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-suspend-resume-graph-manipulation.html
+++ b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-graph-manipulation.html
@@ -1,10 +1,10 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-suspend-resume-promise-expected.txt b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-promise-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-suspend-resume-promise-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-promise-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-suspend-resume-promise.html b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-promise.html
similarity index 90%
rename from third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-suspend-resume-promise.html
rename to third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-promise.html
index f38d94f..8516b428 100644
--- a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-suspend-resume-promise.html
+++ b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-promise.html
@@ -1,10 +1,10 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-suspend-resume-sequence-expected.txt b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-sequence-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-suspend-resume-sequence-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-sequence-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-suspend-resume-sequence.html b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-sequence.html
similarity index 91%
rename from third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-suspend-resume-sequence.html
rename to third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-sequence.html
index b78b130..6bcb3721 100644
--- a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-suspend-resume-sequence.html
+++ b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/offlineaudiocontext-suspend-resume-sequence.html
@@ -1,10 +1,10 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/onstatechange-expected.txt b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/onstatechange-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/onstatechange-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/onstatechange-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/onstatechange.html b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/onstatechange.html
similarity index 90%
rename from third_party/WebKit/LayoutTests/webaudio/onstatechange.html
rename to third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/onstatechange.html
index b0ee207..23c024c 100644
--- a/third_party/WebKit/LayoutTests/webaudio/onstatechange.html
+++ b/third_party/WebKit/LayoutTests/webaudio/OfflineAudioContext/onstatechange.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test statechange event</title>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/audit-util.js"/></script>
-    <script src="resources/audio-testing.js"/></script>
-    <script src="resources/compatibility.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/audit-util.js"/></script>
+    <script src="../resources/audio-testing.js"/></script>
+    <script src="../resources/compatibility.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/osc-custom-sweep-snr-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-custom-sweep-snr-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/osc-custom-sweep-snr-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-custom-sweep-snr-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/osc-custom-sweep-snr.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-custom-sweep-snr.html
similarity index 65%
rename from third_party/WebKit/LayoutTests/webaudio/osc-custom-sweep-snr.html
rename to third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-custom-sweep-snr.html
index 4b5986a..d386a49e 100644
--- a/third_party/WebKit/LayoutTests/webaudio/osc-custom-sweep-snr.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-custom-sweep-snr.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test Oscillator Node: custom</title>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/buffer-loader.js"></script>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/oscillator-testing.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/buffer-loader.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/oscillator-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/osc-low-freq-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-low-freq-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/osc-low-freq-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-low-freq-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/osc-low-freq.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-low-freq.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/webaudio/osc-low-freq.html
rename to third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-low-freq.html
index 0218e70..84f0dc65 100644
--- a/third_party/WebKit/LayoutTests/webaudio/osc-low-freq.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-low-freq.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test Custom Oscillator at Very Low Frequency</title>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/osc-negative-freq-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-negative-freq-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/osc-negative-freq-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-negative-freq-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/osc-negative-freq.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-negative-freq.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/webaudio/osc-negative-freq.html
rename to third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-negative-freq.html
index 092dea7..2b3aa76 100644
--- a/third_party/WebKit/LayoutTests/webaudio/osc-negative-freq.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-negative-freq.html
@@ -1,10 +1,10 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
     <title>Test OscillatorNode with Negative Frequency</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/osc-sawtooth-sweep-snr-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sawtooth-sweep-snr-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/osc-sawtooth-sweep-snr-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sawtooth-sweep-snr-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/osc-sawtooth-sweep-snr.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sawtooth-sweep-snr.html
similarity index 66%
rename from third_party/WebKit/LayoutTests/webaudio/osc-sawtooth-sweep-snr.html
rename to third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sawtooth-sweep-snr.html
index e60e8dd..7965e82 100644
--- a/third_party/WebKit/LayoutTests/webaudio/osc-sawtooth-sweep-snr.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sawtooth-sweep-snr.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test Oscillator Node: sawtooth</title>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/buffer-loader.js"></script>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/oscillator-testing.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/buffer-loader.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/oscillator-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/osc-sine-sweep-snr-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sine-sweep-snr-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/osc-sine-sweep-snr-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sine-sweep-snr-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/osc-sine-sweep-snr.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sine-sweep-snr.html
similarity index 65%
rename from third_party/WebKit/LayoutTests/webaudio/osc-sine-sweep-snr.html
rename to third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sine-sweep-snr.html
index 73f2bb8..89977c8 100644
--- a/third_party/WebKit/LayoutTests/webaudio/osc-sine-sweep-snr.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sine-sweep-snr.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test Oscillator Node: sine</title>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/buffer-loader.js"></script>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/oscillator-testing.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/buffer-loader.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/oscillator-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/osc-square-sweep-snr-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-square-sweep-snr-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/osc-square-sweep-snr-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-square-sweep-snr-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/osc-square-sweep-snr.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-square-sweep-snr.html
similarity index 70%
rename from third_party/WebKit/LayoutTests/webaudio/osc-square-sweep-snr.html
rename to third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-square-sweep-snr.html
index 34e1336..46508531 100644
--- a/third_party/WebKit/LayoutTests/webaudio/osc-square-sweep-snr.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-square-sweep-snr.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test Oscillator Node: square</title>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/buffer-loader.js"></script>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/oscillator-testing.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/buffer-loader.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/oscillator-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/osc-triangle-sweep-snr-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-triangle-sweep-snr-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/osc-triangle-sweep-snr-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-triangle-sweep-snr-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/osc-triangle-sweep-snr.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-triangle-sweep-snr.html
similarity index 68%
rename from third_party/WebKit/LayoutTests/webaudio/osc-triangle-sweep-snr.html
rename to third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-triangle-sweep-snr.html
index 376c6b2..e52d03b3 100644
--- a/third_party/WebKit/LayoutTests/webaudio/osc-triangle-sweep-snr.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-triangle-sweep-snr.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test Oscillator Node: triangle</title>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/buffer-loader.js"></script>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/oscillator-testing.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/buffer-loader.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/oscillator-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/oscillator-basic-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-basic-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/oscillator-basic-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-basic-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/oscillator-basic.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-basic.html
similarity index 90%
rename from third_party/WebKit/LayoutTests/webaudio/oscillator-basic.html
rename to third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-basic.html
index ce535838..dee6c686 100644
--- a/third_party/WebKit/LayoutTests/webaudio/oscillator-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-basic.html
@@ -5,10 +5,10 @@
 -->
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/oscillator-custom-expected.wav b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-custom-expected.wav
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/oscillator-custom-expected.wav
rename to third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-custom-expected.wav
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/webaudio/oscillator-ended-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-ended-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/oscillator-ended-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-ended-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/oscillator-ended.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-ended.html
similarity index 77%
rename from third_party/WebKit/LayoutTests/webaudio/oscillator-ended.html
rename to third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-ended.html
index 1463580fb..5d6c17b0 100644
--- a/third_party/WebKit/LayoutTests/webaudio/oscillator-ended.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-ended.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/audiobuffersource-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/audiobuffersource-testing.js"></script>
     <script>
         var context;
         var source;
diff --git a/third_party/WebKit/LayoutTests/webaudio/oscillator-late-start-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-late-start-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/oscillator-late-start-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-late-start-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/oscillator-late-start.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-late-start.html
similarity index 74%
rename from third_party/WebKit/LayoutTests/webaudio/oscillator-late-start.html
rename to third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-late-start.html
index df9bd7d..7796f9b 100644
--- a/third_party/WebKit/LayoutTests/webaudio/oscillator-late-start.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-late-start.html
@@ -2,11 +2,11 @@
 <html>
 
 <head>
-  <script src="../resources/js-test.js"></script>
-  <script src="resources/compatibility.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
-  <script src="resources/late-start-testing.js"></script>
+  <script src="../../resources/js-test.js"></script>
+  <script src="../resources/compatibility.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
+  <script src="../resources/late-start-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/oscillator-sawtooth-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-sawtooth-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/oscillator-sawtooth-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-sawtooth-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/oscillator-sawtooth-expected.wav b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-sawtooth-expected.wav
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/oscillator-sawtooth-expected.wav
rename to third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-sawtooth-expected.wav
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/webaudio/oscillator-sine-expected.wav b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-sine-expected.wav
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/oscillator-sine-expected.wav
rename to third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-sine-expected.wav
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/webaudio/oscillator-square-expected.wav b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-square-expected.wav
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/oscillator-square-expected.wav
rename to third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-square-expected.wav
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/webaudio/oscillator-triangle-expected.wav b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-triangle-expected.wav
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/oscillator-triangle-expected.wav
rename to third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-triangle-expected.wav
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/webaudio/distance-exponential-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Panner/distance-exponential-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/distance-exponential-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Panner/distance-exponential-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/distance-exponential.html b/third_party/WebKit/LayoutTests/webaudio/Panner/distance-exponential.html
similarity index 71%
rename from third_party/WebKit/LayoutTests/webaudio/distance-exponential.html
rename to third_party/WebKit/LayoutTests/webaudio/Panner/distance-exponential.html
index 0caa824..38b5aa46 100644
--- a/third_party/WebKit/LayoutTests/webaudio/distance-exponential.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/distance-exponential.html
@@ -1,11 +1,11 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/distance-model-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/distance-model-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/distance-inverse-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Panner/distance-inverse-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/distance-inverse-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Panner/distance-inverse-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/distance-inverse.html b/third_party/WebKit/LayoutTests/webaudio/Panner/distance-inverse.html
similarity index 71%
rename from third_party/WebKit/LayoutTests/webaudio/distance-inverse.html
rename to third_party/WebKit/LayoutTests/webaudio/Panner/distance-inverse.html
index 4e93431..56f75cd 100644
--- a/third_party/WebKit/LayoutTests/webaudio/distance-inverse.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/distance-inverse.html
@@ -1,11 +1,11 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/distance-model-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/distance-model-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/distance-linear-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Panner/distance-linear-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/distance-linear-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Panner/distance-linear-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/distance-linear.html b/third_party/WebKit/LayoutTests/webaudio/Panner/distance-linear.html
similarity index 71%
rename from third_party/WebKit/LayoutTests/webaudio/distance-linear.html
rename to third_party/WebKit/LayoutTests/webaudio/Panner/distance-linear.html
index dc7a715..26777c8 100644
--- a/third_party/WebKit/LayoutTests/webaudio/distance-linear.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/distance-linear.html
@@ -1,11 +1,11 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/distance-model-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/distance-model-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/hrtf-database.html b/third_party/WebKit/LayoutTests/webaudio/Panner/hrtf-database.html
similarity index 80%
rename from third_party/WebKit/LayoutTests/webaudio/hrtf-database.html
rename to third_party/WebKit/LayoutTests/webaudio/Panner/hrtf-database.html
index fc2dab3..31f0c3e 100644
--- a/third_party/WebKit/LayoutTests/webaudio/hrtf-database.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/hrtf-database.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test FLAC-encoded HRTF databse</title>
-    <script src="../resources/testharness.js"></script>
-    <script src="../resources/testharnessreport.js"></script>
-    <script src="resources/audit.js"></script>
-    <script src="resources/buffer-loader.js"></script>
+    <script src="../../resources/testharness.js"></script>
+    <script src="../../resources/testharnessreport.js"></script>
+    <script src="../resources/audit.js"></script>
+    <script src="../resources/buffer-loader.js"></script>
   </head>
 
   <body>
@@ -27,8 +27,8 @@
 
         var bufferLoader = new BufferLoader(
           context, [
-            "../../Source/platform/audio/resources/Composite.wav",
-            "../../Source/platform/audio/resources/Composite.flac",
+            "../../../Source/platform/audio/resources/Composite.wav",
+            "../../../Source/platform/audio/resources/Composite.flac",
           ],
           function (bufferList) {
             should(bufferList.length, "Number of buffers loaded")
diff --git a/third_party/WebKit/LayoutTests/webaudio/panner-automation-basic-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-basic-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/panner-automation-basic-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-basic-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/panner-automation-basic.html b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-basic.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/webaudio/panner-automation-basic.html
rename to third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-basic.html
index f38e5a8..27ed4a59 100644
--- a/third_party/WebKit/LayoutTests/webaudio/panner-automation-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-basic.html
@@ -1,11 +1,11 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/panner-formulas.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/panner-formulas.js"></script>
     <title>Test Basic PannerNode with Automation Position Properties</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/panner-automation-equalpower-stereo-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-equalpower-stereo-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/panner-automation-equalpower-stereo-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-equalpower-stereo-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/panner-automation-equalpower-stereo.html b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-equalpower-stereo.html
similarity index 80%
rename from third_party/WebKit/LayoutTests/webaudio/panner-automation-equalpower-stereo.html
rename to third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-equalpower-stereo.html
index b88cd86..f46c968 100644
--- a/third_party/WebKit/LayoutTests/webaudio/panner-automation-equalpower-stereo.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-equalpower-stereo.html
@@ -1,11 +1,11 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/panner-model-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/panner-model-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/panner-automation-position-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-position-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/panner-automation-position-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-position-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/panner-automation-position.html b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-position.html
similarity index 97%
rename from third_party/WebKit/LayoutTests/webaudio/panner-automation-position.html
rename to third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-position.html
index 7c62137..bcd9098 100644
--- a/third_party/WebKit/LayoutTests/webaudio/panner-automation-position.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-position.html
@@ -1,11 +1,11 @@
 <!doctype html>
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/panner-formulas.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/panner-formulas.js"></script>
     <title>Test Automation of PannerNode Positions</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/panner-distance-clamping.html b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-distance-clamping.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/webaudio/panner-distance-clamping.html
rename to third_party/WebKit/LayoutTests/webaudio/Panner/panner-distance-clamping.html
index a7f8a57..02af1e2f 100644
--- a/third_party/WebKit/LayoutTests/webaudio/panner-distance-clamping.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-distance-clamping.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test Clamping of Distance for PannerNode</title>
-    <script src="../resources/testharness.js"></script>
-    <script src="../resources/testharnessreport.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/testharness.js"></script>
+    <script src="../../resources/testharnessreport.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/panner-equalpower-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-equalpower-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/panner-equalpower-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Panner/panner-equalpower-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/panner-equalpower-stereo-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-equalpower-stereo-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/panner-equalpower-stereo-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Panner/panner-equalpower-stereo-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/panner-equalpower-stereo.html b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-equalpower-stereo.html
similarity index 80%
rename from third_party/WebKit/LayoutTests/webaudio/panner-equalpower-stereo.html
rename to third_party/WebKit/LayoutTests/webaudio/Panner/panner-equalpower-stereo.html
index 3405a7b..a296efe3 100644
--- a/third_party/WebKit/LayoutTests/webaudio/panner-equalpower-stereo.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-equalpower-stereo.html
@@ -1,11 +1,11 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/panner-model-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/panner-model-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/panner-equalpower.html b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-equalpower.html
similarity index 80%
rename from third_party/WebKit/LayoutTests/webaudio/panner-equalpower.html
rename to third_party/WebKit/LayoutTests/webaudio/Panner/panner-equalpower.html
index c80bbc05..f9616f8a 100644
--- a/third_party/WebKit/LayoutTests/webaudio/panner-equalpower.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-equalpower.html
@@ -1,11 +1,11 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/panner-model-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/panner-model-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/panner-loop-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-loop-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/panner-loop-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Panner/panner-loop-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/panner-loop.html b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-loop.html
similarity index 89%
rename from third_party/WebKit/LayoutTests/webaudio/panner-loop.html
rename to third_party/WebKit/LayoutTests/webaudio/Panner/panner-loop.html
index 51771d1..552c22a2 100644
--- a/third_party/WebKit/LayoutTests/webaudio/panner-loop.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-loop.html
@@ -1,11 +1,11 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/panner-model-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/panner-model-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/panner-rolloff-clamping.html b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-rolloff-clamping.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/webaudio/panner-rolloff-clamping.html
rename to third_party/WebKit/LayoutTests/webaudio/Panner/panner-rolloff-clamping.html
index 313b6bf..dd5a3e4 100644
--- a/third_party/WebKit/LayoutTests/webaudio/panner-rolloff-clamping.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-rolloff-clamping.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test Clamping of PannerNode rolloffFactor</title>
-    <script src="../resources/testharness.js"></script>
-    <script src="../resources/testharnessreport.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/testharness.js"></script>
+    <script src="../../resources/testharnessreport.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/pannernode-basic-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Panner/pannernode-basic-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/pannernode-basic-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/Panner/pannernode-basic-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/pannernode-basic.html b/third_party/WebKit/LayoutTests/webaudio/Panner/pannernode-basic.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/webaudio/pannernode-basic.html
rename to third_party/WebKit/LayoutTests/webaudio/Panner/pannernode-basic.html
index bbe1f40..ffa2415 100644
--- a/third_party/WebKit/LayoutTests/webaudio/pannernode-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/pannernode-basic.html
@@ -2,10 +2,10 @@
 <html>
 
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/periodicwave-contexts-expected.txt b/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-contexts-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/periodicwave-contexts-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-contexts-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/periodicwave-contexts.html b/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-contexts.html
similarity index 81%
rename from third_party/WebKit/LayoutTests/webaudio/periodicwave-contexts.html
rename to third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-contexts.html
index 80d4ae3..ff8d492 100644
--- a/third_party/WebKit/LayoutTests/webaudio/periodicwave-contexts.html
+++ b/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-contexts.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test Oscillator Node: sawtooth</title>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/buffer-loader.js"></script>
-    <script src="resources/oscillator-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/buffer-loader.js"></script>
+    <script src="../resources/oscillator-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/periodicwave-lengths-expected.txt b/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-lengths-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/periodicwave-lengths-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-lengths-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/periodicwave-lengths.html b/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-lengths.html
similarity index 97%
rename from third_party/WebKit/LayoutTests/webaudio/periodicwave-lengths.html
rename to third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-lengths.html
index b2f4aded..2bc1783 100644
--- a/third_party/WebKit/LayoutTests/webaudio/periodicwave-lengths.html
+++ b/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-lengths.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test Different PeriodicWave Lengths at Different Sample Rates</title>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/periodicwave-normalization-expected.txt b/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-normalization-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/periodicwave-normalization-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-normalization-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/periodicwave-normalization.html b/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-normalization.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/webaudio/periodicwave-normalization.html
rename to third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-normalization.html
index 4318762..4474b67 100644
--- a/third_party/WebKit/LayoutTests/webaudio/periodicwave-normalization.html
+++ b/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-normalization.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test PeriodicWave Normalization</title>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/scriptprocessor-offlineaudiocontext.html b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessor-offlineaudiocontext.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/webaudio/scriptprocessor-offlineaudiocontext.html
rename to third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessor-offlineaudiocontext.html
index 8b0b23083..fae4932 100644
--- a/third_party/WebKit/LayoutTests/webaudio/scriptprocessor-offlineaudiocontext.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessor-offlineaudiocontext.html
@@ -2,10 +2,10 @@
 <html>
 <head>
   <title>ScriptProcessorNode on OfflineAudioContext</title>
-  <script src="../resources/testharness.js"></script>
-  <script src="../resources/testharnessreport.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
+  <script src="../../resources/testharness.js"></script>
+  <script src="../../resources/testharnessreport.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
 </head>
 <body>
   <script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-0-output-channels-expected.txt b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-0-output-channels-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-0-output-channels-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-0-output-channels-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-0-output-channels.html b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-0-output-channels.html
similarity index 88%
rename from third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-0-output-channels.html
rename to third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-0-output-channels.html
index 3f23f83..c188163 100644
--- a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-0-output-channels.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-0-output-channels.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test Connecting 0-output channel ScriptProcessor to Another Node </title>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-detached-no-crash-expected.txt b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-detached-no-crash-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-detached-no-crash-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-detached-no-crash-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-detached-no-crash.html b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-detached-no-crash.html
similarity index 81%
rename from third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-detached-no-crash.html
rename to third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-detached-no-crash.html
index 1bcdfc0..1fb6bc9 100644
--- a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-detached-no-crash.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-detached-no-crash.html
@@ -1,10 +1,10 @@
 <!DOCTYPE HTML>
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
 </head>
 <body>
 <script>
@@ -52,7 +52,7 @@
     testRunner.setCanOpenWindows();
 }
 
-w = window.open('../resources/window-postmessage-open-close.html');
+w = window.open('../../resources/window-postmessage-open-close.html');
 window.addEventListener("message", processMessage, false);
 </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-downmix8-2channel-input-expected.txt b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-downmix8-2channel-input-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-downmix8-2channel-input-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-downmix8-2channel-input-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-downmix8-2channel-input.html b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-downmix8-2channel-input.html
similarity index 64%
rename from third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-downmix8-2channel-input.html
rename to third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-downmix8-2channel-input.html
index b1c0c33..0d6f5c69 100644
--- a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-downmix8-2channel-input.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-downmix8-2channel-input.html
@@ -2,11 +2,11 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script type="text/javascript" src="resources/scriptprocessornode-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script type="text/javascript" src="../resources/scriptprocessornode-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-expected.txt b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-premature-death-expected.txt b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-premature-death-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-premature-death-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-premature-death-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-premature-death.html b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-premature-death.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-premature-death.html
rename to third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-premature-death.html
index 1eafd5c..a8c00e6 100644
--- a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-premature-death.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-premature-death.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
 <body>
 <script>
 description('Tests that a script processor node is not prematurely GCed');
diff --git a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-rewrap-expected.txt b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-rewrap-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-rewrap-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-rewrap-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-rewrap.html b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-rewrap.html
similarity index 73%
rename from third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-rewrap.html
rename to third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-rewrap.html
index e42e429..931c6338 100644
--- a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-rewrap.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-rewrap.html
@@ -1,13 +1,13 @@
 <!DOCTYPE html>
 <html>
 <body>
-<script src=../resources/js-test.js></script>
-<script src="resources/compatibility.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
 <script>
 var jsTestIsAsync = true;
 description("Tests re-wrapping an AudioNode sublass after its JS wrapper is deleted wraps the node as the correct subclass. A binding integrity assert will fire otherwise.");
 </script>
-<script src=resources/scriptprocessornode-testing.js></script>
+<script src="../resources/scriptprocessornode-testing.js"></script>
 <script>
 var sampleRate = 44100.0;
 var sourceChannels = 2;
diff --git a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-upmix2-8channel-input-expected.txt b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-upmix2-8channel-input-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-upmix2-8channel-input-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-upmix2-8channel-input-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-upmix2-8channel-input.html b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-upmix2-8channel-input.html
similarity index 62%
rename from third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-upmix2-8channel-input.html
rename to third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-upmix2-8channel-input.html
index d4efc8f..c6c45f1 100644
--- a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-upmix2-8channel-input.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-upmix2-8channel-input.html
@@ -2,11 +2,11 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script type="text/javascript" src="resources/scriptprocessornode-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script type="text/javascript" src="../resources/scriptprocessornode-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-zero-input-channels-expected.txt b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-zero-input-channels-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-zero-input-channels-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-zero-input-channels-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-zero-input-channels.html b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-zero-input-channels.html
similarity index 87%
rename from third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-zero-input-channels.html
rename to third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-zero-input-channels.html
index de90d34..59efd789 100644
--- a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-zero-input-channels.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode-zero-input-channels.html
@@ -1,10 +1,10 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode.html b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/webaudio/scriptprocessornode.html
rename to third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode.html
index db7537f..d837625 100644
--- a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode.html
+++ b/third_party/WebKit/LayoutTests/webaudio/ScriptProcessor/scriptprocessornode.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/stereopannernode-basic-expected.txt b/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-basic-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/stereopannernode-basic-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-basic-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/stereopannernode-basic.html b/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-basic.html
similarity index 81%
rename from third_party/WebKit/LayoutTests/webaudio/stereopannernode-basic.html
rename to third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-basic.html
index eff3e08f..8b33293 100644
--- a/third_party/WebKit/LayoutTests/webaudio/stereopannernode-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-basic.html
@@ -2,10 +2,10 @@
 <html>
 
 <head>
-  <script src="../resources/js-test.js"></script>
-  <script src="resources/compatibility.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
+  <script src="../../resources/js-test.js"></script>
+  <script src="../resources/compatibility.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/stereopannernode-no-glitch-expected.txt b/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-no-glitch-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/stereopannernode-no-glitch-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-no-glitch-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/stereopannernode-no-glitch.html b/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-no-glitch.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/webaudio/stereopannernode-no-glitch.html
rename to third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-no-glitch.html
index 81f8594..ae9b4cd3 100644
--- a/third_party/WebKit/LayoutTests/webaudio/stereopannernode-no-glitch.html
+++ b/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-no-glitch.html
@@ -2,10 +2,10 @@
 <html>
 
 <head>
-  <script src="../resources/js-test.js"></script>
-  <script src="resources/compatibility.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
+  <script src="../../resources/js-test.js"></script>
+  <script src="../resources/compatibility.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/stereopannernode-panning-expected.txt b/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-panning-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/stereopannernode-panning-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-panning-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/stereopannernode-panning.html b/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-panning.html
similarity index 72%
rename from third_party/WebKit/LayoutTests/webaudio/stereopannernode-panning.html
rename to third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-panning.html
index 92bbe87..b833d01 100644
--- a/third_party/WebKit/LayoutTests/webaudio/stereopannernode-panning.html
+++ b/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-panning.html
@@ -2,11 +2,11 @@
 <html>
 
 <head>
-  <script src="../resources/js-test.js"></script>
-  <script src="resources/compatibility.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
-  <script src="resources/stereopanner-testing.js"></script>
+  <script src="../../resources/js-test.js"></script>
+  <script src="../resources/compatibility.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
+  <script src="../resources/stereopanner-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/waveshaper-364379-expected.txt b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-364379-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/waveshaper-364379-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-364379-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/waveshaper-364379.html b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-364379.html
similarity index 90%
rename from third_party/WebKit/LayoutTests/webaudio/waveshaper-364379.html
rename to third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-364379.html
index e19267b9c..bdbdce81 100644
--- a/third_party/WebKit/LayoutTests/webaudio/waveshaper-364379.html
+++ b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-364379.html
@@ -1,8 +1,8 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/waveshaper-copy-curve.html b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-copy-curve.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/webaudio/waveshaper-copy-curve.html
rename to third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-copy-curve.html
index f9595392..0f954056 100644
--- a/third_party/WebKit/LayoutTests/webaudio/waveshaper-copy-curve.html
+++ b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-copy-curve.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Test WaveShaper Copies Curve Data</title>
-    <script src="../resources/testharness.js"></script>
-    <script src="../resources/testharnessreport.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/testharness.js"></script>
+    <script src="../../resources/testharnessreport.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/waveshaper-expected.txt b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/waveshaper-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/waveshaper-limits-expected.txt b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-limits-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/waveshaper-limits-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-limits-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/waveshaper-limits.html b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-limits.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/webaudio/waveshaper-limits.html
rename to third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-limits.html
index f50cd4e5..320ed50 100644
--- a/third_party/WebKit/LayoutTests/webaudio/waveshaper-limits.html
+++ b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-limits.html
@@ -1,8 +1,8 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
+    <script src="../../resources/js-test.js"></script>
+    <script src="../resources/compatibility.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/waveshaper-oversample-2x-expected.txt b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-2x-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/waveshaper-oversample-2x-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-2x-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-2x.html b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-2x.html
new file mode 100644
index 0000000..1564fe0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-2x.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script type="text/javascript" src="../resources/mix-testing.js"></script>
+<script type="text/javascript" src="../resources/waveshaper-testing.js"></script>
+</head>
+
+<body>
+
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+description("Tests 2x WaveShaperNode oversampling.");
+
+var testParams = {
+    "sampleRate": 44100,
+    "oversample": "2x",
+
+    // Should generate harmonics at 9000, 18000, 27000, 36000
+    // The last two should be filtered out with the 2x oversampling.
+    "fundamentalFrequency": 9000,
+    "acceptableAliasingThresholdDecibels": -75.3
+};
+runWaveShaperOversamplingTest(testParams);
+
+</script>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/waveshaper-oversample-4x-expected.txt b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-4x-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/webaudio/waveshaper-oversample-4x-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-4x-expected.txt
diff --git a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-4x.html b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-4x.html
new file mode 100644
index 0000000..7273878
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-4x.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script type="text/javascript" src="../resources/mix-testing.js"></script>
+<script type="text/javascript" src="../resources/waveshaper-testing.js"></script>
+</head>
+
+<body>
+
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+description("Tests 4x WaveShaperNode oversampling.");
+
+var testParams = {
+    "sampleRate": 44100,
+    "oversample": "4x",
+
+    // Should generate harmonics at 18000, 36000, 54000, 72000
+    // All except for 18000 should be filtered out with the 4x oversampling.
+    "fundamentalFrequency": 18000,
+    "acceptableAliasingThresholdDecibels": -79.9
+};
+runWaveShaperOversamplingTest(testParams);
+
+</script>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/waveshaper-simple.html b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-simple.html
similarity index 85%
rename from third_party/WebKit/LayoutTests/webaudio/waveshaper-simple.html
rename to third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-simple.html
index 690ca2a..5fffb09 100644
--- a/third_party/WebKit/LayoutTests/webaudio/waveshaper-simple.html
+++ b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-simple.html
@@ -2,10 +2,10 @@
 <html>
   <head>
     <title>Simple Tests of WaveShaperNode</title>
-    <script src="../resources/testharness.js"></script>
-    <script src="../resources/testharnessreport.js"></script>
-    <script src="resources/audit-util.js"></script>
-    <script src="resources/audio-testing.js"></script>
+    <script src="../../resources/testharness.js"></script>
+    <script src="../../resources/testharnessreport.js"></script>
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audio-testing.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/waveshaper.html b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/webaudio/waveshaper.html
rename to third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper.html
index 5be96b0..45a575f 100644
--- a/third_party/WebKit/LayoutTests/webaudio/waveshaper.html
+++ b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper.html
@@ -2,11 +2,11 @@
 
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script type="text/javascript" src="resources/buffer-loader.js"></script>
+<script src="../../resources/js-test.js"></script>
+<script src="../resources/compatibility.js"></script>
+<script src="../resources/audit-util.js"></script>
+<script src="../resources/audio-testing.js"></script>
+<script type="text/javascript" src="../resources/buffer-loader.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/decode-audio-data-basic-expected.txt b/third_party/WebKit/LayoutTests/webaudio/decodeAudioData/decode-audio-data-basic-expected.txt
similarity index 88%
rename from third_party/WebKit/LayoutTests/webaudio/decode-audio-data-basic-expected.txt
rename to third_party/WebKit/LayoutTests/webaudio/decodeAudioData/decode-audio-data-basic-expected.txt
index 7064b4d8..56fc313 100644
--- a/third_party/WebKit/LayoutTests/webaudio/decode-audio-data-basic-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/decodeAudioData/decode-audio-data-basic-expected.txt
@@ -4,9 +4,9 @@
 
 
 PASS decodeAudioData(null) rejected correctly (with TypeError: Failed to execute 'decodeAudioData' on 'BaseAudioContext': parameter 1 is not of type 'ArrayBuffer'.).
-PASS Decode valid file with promise: Correctly succeeded in decoding resources/media/24bit-44khz.wav
-PASS Decode invalid file with promise: Correctly failed to decode resources/media/invalid-audio-file.txt: EncodingError: Unable to decode audio data
-PASS Decode invalid file with promise: Correctly failed to decode ../media/resources/test-live.webm: EncodingError: Unable to decode audio data
+PASS Decode valid file with promise: Correctly succeeded in decoding ../resources/media/24bit-44khz.wav
+PASS Decode invalid file with promise: Correctly failed to decode ../resources/media/invalid-audio-file.txt: EncodingError: Unable to decode audio data
+PASS Decode invalid file with promise: Correctly failed to decode ../../media/resources/test-live.webm: EncodingError: Unable to decode audio data
 PASS Decoding valid file with promise and callback: successCallback invoked correctly
 PASS Decoding valid file with promise and callback: Promise correctly fulfilled
 PASS Decoding valid file with promise and callback: Promise and successCallback returned the same buffer
diff --git a/third_party/WebKit/LayoutTests/webaudio/decode-audio-data-basic.html b/third_party/WebKit/LayoutTests/webaudio/decodeAudioData/decode-audio-data-basic.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/webaudio/decode-audio-data-basic.html
rename to third_party/WebKit/LayoutTests/webaudio/decodeAudioData/decode-audio-data-basic.html
index dd74608..83c7a5e 100644
--- a/third_party/WebKit/LayoutTests/webaudio/decode-audio-data-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/decodeAudioData/decode-audio-data-basic.html
@@ -1,10 +1,10 @@
 <!doctype html>
 <html>
 <head>
-  <script src="../resources/js-test.js"></script>
-  <script src="resources/compatibility.js"></script>
-  <script src="resources/audit-util.js"></script>
-  <script src="resources/audio-testing.js"></script>
+  <script src="../../resources/js-test.js"></script>
+  <script src="../resources/compatibility.js"></script>
+  <script src="../resources/audit-util.js"></script>
+  <script src="../resources/audio-testing.js"></script>
   <title>Test decodeAudioData promises</title>
 </head>
 
@@ -19,9 +19,9 @@
     var context = new OfflineAudioContext(1, 1, 44100);
 
     // Test files for decodeAudioData
-    var validAudioFile = "resources/media/24bit-44khz.wav";
-    var invalidAudioFile = "resources/media/invalid-audio-file.txt";
-    var invalidLiveStream = '../media/resources/test-live.webm';
+    var validAudioFile = "../resources/media/24bit-44khz.wav";
+    var invalidAudioFile = "../resources/media/invalid-audio-file.txt";
+    var invalidLiveStream = '../../media/resources/test-live.webm';
 
     // Decoded data from validAudioFile
     var referenceDecodedAudioBuffer;
diff --git a/third_party/WebKit/LayoutTests/webaudio/resources/oscillator-testing.js b/third_party/WebKit/LayoutTests/webaudio/resources/oscillator-testing.js
index 8f6cf82..49b376b 100644
--- a/third_party/WebKit/LayoutTests/webaudio/resources/oscillator-testing.js
+++ b/third_party/WebKit/LayoutTests/webaudio/resources/oscillator-testing.js
@@ -112,7 +112,7 @@
 function loadReferenceAndRunTest(oscType) {
     var bufferLoader = new BufferLoader(
         context,
-        [ "oscillator-" + oscType + "-expected.wav" ],
+        [ "../Oscillator/oscillator-" + oscType + "-expected.wav" ],
         function (bufferList) {
             reference = bufferList[0].getChannelData(0);
             generateExponentialOscillatorSweep(context, oscType);
diff --git a/third_party/WebKit/LayoutTests/webaudio/waveshaper-oversample-2x.html b/third_party/WebKit/LayoutTests/webaudio/waveshaper-oversample-2x.html
deleted file mode 100644
index 521dcd19..0000000
--- a/third_party/WebKit/LayoutTests/webaudio/waveshaper-oversample-2x.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<!DOCTYPE html>
-
-<html>
-<head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script type="text/javascript" src="resources/mix-testing.js"></script>
-<script type="text/javascript" src="resources/waveshaper-testing.js"></script>
-</head>
-
-<body>
-
-<div id="description"></div>
-<div id="console"></div>
-
-<script>
-description("Tests 2x WaveShaperNode oversampling.");
-
-var testParams = {
-    "sampleRate": 44100,
-    "oversample": "2x",
-
-    // Should generate harmonics at 9000, 18000, 27000, 36000
-    // The last two should be filtered out with the 2x oversampling.
-    "fundamentalFrequency": 9000,
-    "acceptableAliasingThresholdDecibels": -75.3
-};
-runWaveShaperOversamplingTest(testParams);
-
-</script>
-
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/waveshaper-oversample-4x.html b/third_party/WebKit/LayoutTests/webaudio/waveshaper-oversample-4x.html
deleted file mode 100644
index 2b6d965..0000000
--- a/third_party/WebKit/LayoutTests/webaudio/waveshaper-oversample-4x.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<!DOCTYPE html>
-
-<html>
-<head>
-<script src="../resources/js-test.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
-<script type="text/javascript" src="resources/mix-testing.js"></script>
-<script type="text/javascript" src="resources/waveshaper-testing.js"></script>
-</head>
-
-<body>
-
-<div id="description"></div>
-<div id="console"></div>
-
-<script>
-description("Tests 4x WaveShaperNode oversampling.");
-
-var testParams = {
-    "sampleRate": 44100,
-    "oversample": "4x",
-
-    // Should generate harmonics at 18000, 36000, 54000, 72000
-    // All except for 18000 should be filtered out with the 4x oversampling.
-    "fundamentalFrequency": 18000,
-    "acceptableAliasingThresholdDecibels": -79.9
-};
-runWaveShaperOversamplingTest(testParams);
-
-</script>
-
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/webshare/resources/mock-share-service.js b/third_party/WebKit/LayoutTests/webshare/resources/mock-share-service.js
index c1f1736..0e04983 100644
--- a/third_party/WebKit/LayoutTests/webshare/resources/mock-share-service.js
+++ b/third_party/WebKit/LayoutTests/webshare/resources/mock-share-service.js
@@ -2,17 +2,18 @@
 
 let mockShareService = loadMojoModules(
     'mockShareService',
-    ['mojo/public/js/router',
+    ['mojo/public/js/bindings',
      'third_party/WebKit/public/platform/modules/webshare/webshare.mojom',
     ]).then(mojo => {
-  let [router, webshare] = mojo.modules;
+  let [bindings, webshare] = mojo.modules;
 
-  class MockShareService extends webshare.ShareService.stubClass {
+  class MockShareService {
     constructor(interfaceProvider) {
-      super();
+      this.bindingSet_ = new bindings.BindingSet(webshare.ShareService);
+
       interfaceProvider.addInterfaceOverrideForTesting(
           webshare.ShareService.name,
-          handle => this.connect_(handle));
+          handle => this.bindingSet_.addBinding(this, handle));
     }
 
     // Returns a Promise that gets rejected if the test should fail.
@@ -23,11 +24,6 @@
       return new Promise((resolve, reject) => {this.reject_ = reject});
     }
 
-    connect_(handle) {
-      this.router_ = new router.Router(handle);
-      this.router_.setIncomingReceiver(this);
-    }
-
     share(title, text, url) {
       let callback = null;
       let result = new Promise(resolve => {callback = resolve;});
diff --git a/third_party/WebKit/Source/core/css/CSSDefaultStyleSheets.cpp b/third_party/WebKit/Source/core/css/CSSDefaultStyleSheets.cpp
index 3cee782c..0f628a2 100644
--- a/third_party/WebKit/Source/core/css/CSSDefaultStyleSheets.cpp
+++ b/third_party/WebKit/Source/core/css/CSSDefaultStyleSheets.cpp
@@ -34,7 +34,6 @@
 #include "core/css/MediaQueryEvaluator.h"
 #include "core/css/RuleSet.h"
 #include "core/css/StyleSheetContents.h"
-#include "core/dom/Fullscreen.h"
 #include "core/html/HTMLAnchorElement.h"
 #include "core/html/HTMLHtmlElement.h"
 #include "core/layout/LayoutTheme.h"
diff --git a/third_party/WebKit/Source/core/css/SelectorChecker.cpp b/third_party/WebKit/Source/core/css/SelectorChecker.cpp
index adbdbc8..46f8fe4 100644
--- a/third_party/WebKit/Source/core/css/SelectorChecker.cpp
+++ b/third_party/WebKit/Source/core/css/SelectorChecker.cpp
@@ -1010,7 +1010,7 @@
       if (isHTMLFrameElementBase(element) &&
           element.containsFullScreenElement())
         return true;
-      return Fullscreen::isCurrentFullScreenElement(element);
+      return Fullscreen::isFullscreenElement(element);
     case CSSSelector::PseudoFullScreenAncestor:
       return element.containsFullScreenElement();
     case CSSSelector::PseudoInRange:
diff --git a/third_party/WebKit/Source/core/dom/DocumentFullscreen.cpp b/third_party/WebKit/Source/core/dom/DocumentFullscreen.cpp
index 87d2577f..2f5d0d7c 100644
--- a/third_party/WebKit/Source/core/dom/DocumentFullscreen.cpp
+++ b/third_party/WebKit/Source/core/dom/DocumentFullscreen.cpp
@@ -41,8 +41,4 @@
   Fullscreen::exitFullscreen(document);
 }
 
-Element* DocumentFullscreen::currentFullScreenElement(Document& document) {
-  return Fullscreen::currentFullScreenElementForBindingFrom(document);
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/DocumentFullscreen.h b/third_party/WebKit/Source/core/dom/DocumentFullscreen.h
index aa8da741..5443a42 100644
--- a/third_party/WebKit/Source/core/dom/DocumentFullscreen.h
+++ b/third_party/WebKit/Source/core/dom/DocumentFullscreen.h
@@ -45,9 +45,6 @@
   DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(fullscreenchange);
   DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(fullscreenerror);
 
-  // Mozilla version
-  static Element* currentFullScreenElement(Document&);
-
   DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(webkitfullscreenchange);
   DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(webkitfullscreenerror);
 };
diff --git a/third_party/WebKit/Source/core/dom/DocumentFullscreen.idl b/third_party/WebKit/Source/core/dom/DocumentFullscreen.idl
index 23225e7..316ebb6 100644
--- a/third_party/WebKit/Source/core/dom/DocumentFullscreen.idl
+++ b/third_party/WebKit/Source/core/dom/DocumentFullscreen.idl
@@ -30,8 +30,8 @@
     [RuntimeEnabled=FullscreenUnprefixed] attribute EventHandler onfullscreenerror;
 
     // Mozilla version
-    [MeasureAs=PrefixedDocumentIsFullscreen, ImplementedAs=currentFullScreenElement] readonly attribute boolean webkitIsFullScreen;
-    [MeasureAs=PrefixedDocumentCurrentFullScreenElement, ImplementedAs=currentFullScreenElement] readonly attribute Element webkitCurrentFullScreenElement;
+    [MeasureAs=PrefixedDocumentIsFullscreen, ImplementedAs=fullscreenElement] readonly attribute boolean webkitIsFullScreen;
+    [MeasureAs=PrefixedDocumentCurrentFullScreenElement, ImplementedAs=fullscreenElement] readonly attribute Element webkitCurrentFullScreenElement;
     [MeasureAs=PrefixedDocumentCancelFullScreen, ImplementedAs=exitFullscreen] void webkitCancelFullScreen();
 
     // W3C version
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp
index d58a766..76f4f86 100644
--- a/third_party/WebKit/Source/core/dom/Element.cpp
+++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -1593,7 +1593,7 @@
 
   DCHECK(!hasRareData() || !elementRareData()->hasPseudoElements());
 
-  if (Fullscreen::isCurrentFullScreenElement(*this)) {
+  if (Fullscreen::isFullscreenElement(*this)) {
     setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
     if (insertionPoint->isElementNode()) {
       toElement(insertionPoint)->setContainsFullScreenElement(false);
@@ -4008,7 +4008,7 @@
     return false;
   if (hasAnimations())
     return false;
-  if (Fullscreen::isCurrentFullScreenElement(*this))
+  if (Fullscreen::isFullscreenElement(*this))
     return false;
   return true;
 }
diff --git a/third_party/WebKit/Source/core/dom/Fullscreen.cpp b/third_party/WebKit/Source/core/dom/Fullscreen.cpp
index 757f18f..40cc448 100644
--- a/third_party/WebKit/Source/core/dom/Fullscreen.cpp
+++ b/third_party/WebKit/Source/core/dom/Fullscreen.cpp
@@ -181,17 +181,26 @@
   return true;
 }
 
-bool isPrefixed(const AtomicString& type) {
-  return type == EventTypeNames::webkitfullscreenchange ||
-         type == EventTypeNames::webkitfullscreenerror;
-}
+// https://fullscreen.spec.whatwg.org/#dom-element-requestfullscreen step 4:
+bool requestFullscreenConditionsMet(Element& pending, Document& document) {
+  // |pending|'s namespace is the HTML namespace or |pending| is an SVG svg or
+  // MathML math element. Note: MathML is not supported.
+  if (!pending.isHTMLElement() && !isSVGSVGElement(pending))
+    return false;
 
-Event* createEvent(const AtomicString& type, EventTarget& target) {
-  EventInit initializer;
-  initializer.setBubbles(isPrefixed(type));
-  Event* event = Event::create(type, initializer);
-  event->setTarget(&target);
-  return event;
+  // The fullscreen element ready check for |pending| returns false.
+  if (!fullscreenElementReady(pending))
+    return false;
+
+  // Fullscreen is supported.
+  if (!fullscreenIsSupported(document))
+    return false;
+
+  // This algorithm is allowed to request fullscreen.
+  if (!allowedToRequestFullscreen(document))
+    return false;
+
+  return true;
 }
 
 // Walks the frame tree and returns the first local ancestor frame, if any.
@@ -210,7 +219,7 @@
   LocalFrame* frame = document.frame();
   if (!frame)
     return nullptr;
-  LocalFrame* next = nextLocalAncestor(*document.frame());
+  LocalFrame* next = nextLocalAncestor(*frame);
   if (!next)
     return nullptr;
   DCHECK(next->document());
@@ -228,16 +237,94 @@
   return document;
 }
 
-// Helper to find the browsing context container in |doc| that embeds the
-// |descendant| Document, possibly through multiple levels of nesting.  This
-// works even in OOPIF scenarios like A-B-A, where there may be remote frames
-// in between |doc| and |descendant|.
-HTMLFrameOwnerElement* findContainerForDescendant(const Document& doc,
-                                                  const Document& descendant) {
-  Frame* frame = descendant.frame();
-  while (frame->tree().parent() != doc.frame())
-    frame = frame->tree().parent();
-  return toHTMLFrameOwnerElement(frame->owner());
+// https://fullscreen.spec.whatwg.org/#collect-documents-to-unfullscreen
+HeapVector<Member<Document>> collectDocumentsToUnfullscreen(
+    Document& doc,
+    Fullscreen::ExitType exitType) {
+  DCHECK(Fullscreen::fullscreenElementFrom(doc));
+
+  // 1. If |doc|'s top layer consists of more than a single element that has
+  // its fullscreen flag set, return the empty set.
+  // TODO(foolip): See TODO in |fullyExitFullscreen()|.
+  if (exitType != Fullscreen::ExitType::Fully &&
+      Fullscreen::fullscreenElementStackSizeFrom(doc) > 1)
+    return HeapVector<Member<Document>>();
+
+  // 2. Let |docs| be an ordered set consisting of |doc|.
+  HeapVector<Member<Document>> docs;
+  docs.push_back(&doc);
+
+  // 3. While |docs|'s last document ...
+  //
+  // OOPIF: Skip over remote frames, assuming that they have exactly one element
+  // in their fullscreen element stacks, thereby erring on the side of exiting
+  // fullscreen. TODO(alexmos): Deal with nested fullscreen cases, see
+  // https://crbug.com/617369.
+  for (Document* document = nextLocalAncestor(doc); document;
+       document = nextLocalAncestor(*document)) {
+    // ... has a browsing context container whose node document's top layer
+    // consists of a single element that has its fullscreen flag set and does
+    // not have its iframe fullscreen flag set (if any), append that node
+    // document to |docs|.
+    // TODO(foolip): Support the iframe fullscreen flag.
+    // https://crbug.com/644695
+    if (Fullscreen::fullscreenElementStackSizeFrom(*document) == 1)
+      docs.push_back(document);
+    else
+      break;
+  }
+
+  // 4. Return |docs|.
+  return docs;
+}
+
+// Creates a non-bubbling event with |document| as its target.
+Event* createEvent(const AtomicString& type, Document& document) {
+  DCHECK(type == EventTypeNames::fullscreenchange ||
+         type == EventTypeNames::fullscreenerror);
+
+  Event* event = Event::create(type);
+  event->setTarget(&document);
+  return event;
+}
+
+// Creates a bubbling event with |element| as its target. If |element| is not
+// connected to |document|, then |document| is used as the target instead.
+Event* createPrefixedEvent(const AtomicString& type,
+                           Element& element,
+                           Document& document) {
+  DCHECK(type == EventTypeNames::webkitfullscreenchange ||
+         type == EventTypeNames::webkitfullscreenerror);
+
+  Event* event = Event::createBubble(type);
+  if (element.isConnected() && element.document() == document)
+    event->setTarget(&element);
+  else
+    event->setTarget(&document);
+  return event;
+}
+
+Event* createChangeEvent(Document& document,
+                         Element& element,
+                         Fullscreen::RequestType requestType) {
+  if (requestType == Fullscreen::RequestType::Unprefixed)
+    return createEvent(EventTypeNames::fullscreenchange, document);
+  return createPrefixedEvent(EventTypeNames::webkitfullscreenchange, element,
+                             document);
+}
+
+Event* createErrorEvent(Document& document,
+                        Element& element,
+                        Fullscreen::RequestType requestType) {
+  if (requestType == Fullscreen::RequestType::Unprefixed)
+    return createEvent(EventTypeNames::fullscreenerror, document);
+  return createPrefixedEvent(EventTypeNames::webkitfullscreenerror, element,
+                             document);
+}
+
+void dispatchEvents(const HeapVector<Member<Event>>& events) {
+  for (Event* event : events)
+    event->target()->dispatchEvent(event);
 }
 
 }  // anonymous namespace
@@ -267,6 +354,12 @@
   return nullptr;
 }
 
+size_t Fullscreen::fullscreenElementStackSizeFrom(Document& document) {
+  if (Fullscreen* found = fromIfExists(document))
+    return found->m_fullscreenElementStack.size();
+  return 0;
+}
+
 Element* Fullscreen::fullscreenElementForBindingFrom(TreeScope& scope) {
   Element* element = fullscreenElementFrom(scope.document());
   if (!element || !RuntimeEnabledFeatures::fullscreenUnprefixedEnabled())
@@ -288,63 +381,41 @@
   return scope.adjustedElement(*element);
 }
 
-Element* Fullscreen::currentFullScreenElementFrom(Document& document) {
-  if (Fullscreen* found = fromIfExists(document))
-    return found->currentFullScreenElement();
-  return nullptr;
-}
-
-Element* Fullscreen::currentFullScreenElementForBindingFrom(
-    Document& document) {
-  Element* element = currentFullScreenElementFrom(document);
-  if (!element || !RuntimeEnabledFeatures::fullscreenUnprefixedEnabled())
-    return element;
-
-  // For Shadow DOM V0 compatibility: We allow returning an element in V0 shadow
-  // tree, even though it leaks the Shadow DOM.
-  if (element->isInV0ShadowTree()) {
-    UseCounter::count(document,
-                      UseCounter::DocumentFullscreenElementInV0Shadow);
-    return element;
-  }
-  return document.adjustedElement(*element);
-}
-
 Fullscreen::Fullscreen(Document& document)
-    : ContextLifecycleObserver(&document),
-      m_fullScreenLayoutObject(nullptr),
-      m_eventQueueTimer(this, &Fullscreen::eventQueueTimerFired),
-      m_forCrossProcessDescendant(false) {
+    : ContextLifecycleObserver(&document), m_fullScreenLayoutObject(nullptr) {
   document.setHasFullscreenSupplement();
 }
 
 Fullscreen::~Fullscreen() {}
 
-inline Document* Fullscreen::document() {
+Document* Fullscreen::document() {
   return toDocument(lifecycleContext());
 }
 
 void Fullscreen::contextDestroyed() {
-  m_eventQueue.clear();
-
   if (m_fullScreenLayoutObject)
     m_fullScreenLayoutObject->destroy();
 
-  m_currentFullScreenElement = nullptr;
+  m_pendingRequests.clear();
   m_fullscreenElementStack.clear();
 }
 
 // https://fullscreen.spec.whatwg.org/#dom-element-requestfullscreen
-void Fullscreen::requestFullscreen(Element& element) {
+void Fullscreen::requestFullscreen(Element& pending) {
   // TODO(foolip): Make RequestType::Unprefixed the default when the unprefixed
   // API is enabled. https://crbug.com/383813
-  requestFullscreen(element, RequestType::Prefixed, false);
+  requestFullscreen(pending, RequestType::Prefixed);
 }
 
-void Fullscreen::requestFullscreen(Element& element,
-                                   RequestType requestType,
-                                   bool forCrossProcessDescendant) {
-  Document& document = element.document();
+void Fullscreen::requestFullscreen(Element& pending, RequestType requestType) {
+  Document& document = pending.document();
+
+  // Ignore this call if the document is not in a live frame.
+  if (!document.isActive() || !document.frame())
+    return;
+
+  bool forCrossProcessDescendant =
+      requestType == RequestType::PrefixedForCrossProcessDescendant;
 
   // Use counters only need to be incremented in the process of the actual
   // fullscreen element.
@@ -358,229 +429,326 @@
     }
   }
 
-  // Ignore this call if the document is not in a live frame.
-  if (!document.isActive() || !document.frame())
+  // 1. Let |pending| be the context object.
+
+  // 2. Let |error| be false.
+  bool error = false;
+
+  // 3. Let |promise| be a new promise.
+  // TODO(foolip): Promises. https://crbug.com/644637
+
+  // 4. If any of the following conditions are false, then set |error| to true:
+  //
+  // OOPIF: If |requestFullscreen()| was already called in a descendant frame
+  // and passed the checks, do not check again here.
+  if (!forCrossProcessDescendant &&
+      !requestFullscreenConditionsMet(pending, document))
+    error = true;
+
+  // 5. Return |promise|, and run the remaining steps in parallel.
+  // TODO(foolip): Promises. https://crbug.com/644637
+
+  // 6. If |error| is false: Resize pending's top-level browsing context's
+  // document's viewport's dimensions to match the dimensions of the screen of
+  // the output device. Optionally display a message how the end user can
+  // revert this.
+  if (!error) {
+    from(document).m_pendingRequests.push_back(
+        std::make_pair(&pending, requestType));
+    LocalFrame& frame = *document.frame();
+    frame.chromeClient().enterFullscreen(frame);
+  } else {
+    enqueueTaskForRequest(document, pending, requestType, true);
+  }
+}
+
+void Fullscreen::didEnterFullscreen() {
+  if (!document())
     return;
 
-  // If |element| is on top of |doc|'s fullscreen element stack, terminate these
-  // substeps.
-  if (&element == fullscreenElementFrom(document))
+  ElementStack requests;
+  requests.swap(m_pendingRequests);
+  for (const ElementStackEntry& request : requests)
+    enqueueTaskForRequest(*document(), *request.first, request.second, false);
+}
+
+void Fullscreen::enqueueTaskForRequest(Document& document,
+                                       Element& pending,
+                                       RequestType requestType,
+                                       bool error) {
+  // 7. As part of the next animation frame task, run these substeps:
+  document.enqueueAnimationFrameTask(
+      WTF::bind(&runTaskForRequest, wrapPersistent(&document),
+                wrapPersistent(&pending), requestType, error));
+}
+
+void Fullscreen::runTaskForRequest(Document* document,
+                                   Element* element,
+                                   RequestType requestType,
+                                   bool error) {
+  DCHECK(document);
+  DCHECK(document->isActive());
+  DCHECK(document->frame());
+  DCHECK(element);
+
+  Document& pendingDoc = *document;
+  Element& pending = *element;
+
+  // TODO(foolip): Spec something like: If |pending|'s node document is not
+  // |pendingDoc|, then set |error| to true.
+  // https://github.com/whatwg/fullscreen/issues/33
+  if (pending.document() != pendingDoc)
+    error = true;
+
+  // 7.1. If either |error| is true or the fullscreen element ready check for
+  // |pending| returns false, fire an event named fullscreenerror on
+  // |pending|'s node document, reject |promise| with a TypeError exception,
+  // and terminate these steps.
+  // TODO(foolip): Promises. https://crbug.com/644637
+  if (error || !fullscreenElementReady(pending)) {
+    Event* event = createErrorEvent(pendingDoc, pending, requestType);
+    event->target()->dispatchEvent(event);
     return;
+  }
 
-  do {
-    // 1. If any of the following conditions are false, then terminate these
-    // steps and queue a task to fire an event named fullscreenerror with its
-    // bubbles attribute set to true on the context object's node document:
+  // 7.2. Let |fullscreenElements| be an ordered set initially consisting of
+  // |pending|.
+  HeapDeque<Member<Element>> fullscreenElements;
+  fullscreenElements.append(pending);
 
-    // |element|'s namespace is the HTML namespace or |element| is an SVG
-    // svg or MathML math element.
-    // Note: MathML is not supported.
-    if (!element.isHTMLElement() && !isSVGSVGElement(element))
-      break;
+  // 7.3. While the first element in |fullscreenElements| is in a nested
+  // browsing context, prepend its browsing context container to
+  // |fullscreenElements|.
+  //
+  // OOPIF: |fullscreenElements| will only contain elements for local ancestors,
+  // and remote ancestors will be processed in their respective processes. This
+  // preserves the spec's event firing order for local ancestors, but not for
+  // remote ancestors. However, that difference shouldn't be observable in
+  // practice: a fullscreenchange event handler would need to postMessage a
+  // frame in another renderer process, where the message should be queued up
+  // and processed after the IPC that dispatches fullscreenchange.
+  for (Frame* frame = pending.document().frame(); frame;
+       frame = frame->tree().parent()) {
+    if (!frame->owner() || !frame->owner()->isLocal())
+      continue;
+    Element* element = toHTMLFrameOwnerElement(frame->owner());
+    fullscreenElements.prepend(element);
+  }
 
-    // The fullscreen element ready check for |element| returns true.
-    if (!fullscreenElementReady(element))
-      break;
+  // 7.4. Let |eventDocs| be an empty list.
+  // Note: For prefixed requests, the event target is an element, so instead
+  // let |events| be a list of events to dispatch.
+  HeapVector<Member<Event>> events;
 
-    // Fullscreen is supported.
-    if (!fullscreenIsSupported(document))
-      break;
+  // 7.5. For each |element| in |fullscreenElements|, in order, run these
+  // subsubsteps:
+  for (Element* element : fullscreenElements) {
+    // 7.5.1. Let |doc| be |element|'s node document.
+    Document& doc = element->document();
 
-    // This algorithm is allowed to request fullscreen.
-    // OOPIF: If |forCrossProcessDescendant| is true, requestFullscreen was
-    // already called on a descendant element in another process, and
-    // getting here means that it was already allowed to request fullscreen.
-    if (!forCrossProcessDescendant && !allowedToRequestFullscreen(document))
-      break;
+    // 7.5.2. If |element| is |doc|'s fullscreen element, terminate these
+    // subsubsteps.
+    if (element == fullscreenElementFrom(doc))
+      continue;
 
-    // 2. Let doc be element's node document. (i.e. "this")
+    // 7.5.3. Otherwise, append |doc| to |eventDocs|.
+    events.push_back(createChangeEvent(doc, *element, requestType));
 
-    // 3. Let docs be all doc's ancestor browsing context's documents (if any)
-    // and doc.
-    //
-    // For OOPIF scenarios, |docs| will only contain documents for local
-    // ancestors, and remote ancestors will be processed in their
-    // respective processes.  This preserves the spec's event firing order
-    // for local ancestors, but not for remote ancestors.  However, that
-    // difference shouldn't be observable in practice: a fullscreenchange
-    // event handler would need to postMessage a frame in another renderer
-    // process, where the message should be queued up and processed after
-    // the IPC that dispatches fullscreenchange.
-    HeapDeque<Member<Document>> docs;
-    for (Document* doc = &document; doc; doc = nextLocalAncestor(*doc))
-      docs.prepend(doc);
+    // 7.5.4. If |element| is |pending| and |pending| is an iframe element,
+    // set |element|'s iframe fullscreen flag.
+    // TODO(foolip): Support the iframe fullscreen flag.
+    // https://crbug.com/644695
 
-    // 4. For each document in docs, run these substeps:
-    HeapDeque<Member<Document>>::iterator current = docs.begin(),
-                                          following = docs.begin();
+    // 7.5.5. Fullscreen |element| within |doc|.
+    // TODO(foolip): Merge fullscreen element stack into top layer.
+    // https://crbug.com/627790
+    from(doc).pushFullscreenElementStack(*element, requestType);
+  }
 
-    do {
-      ++following;
+  // 7.6. For each |doc| in |eventDocs|, in order, fire an event named
+  // fullscreenchange on |doc|.
+  dispatchEvents(events);
 
-      // 1. Let following document be the document after document in docs, or
-      // null if there is no such document.
-      Document* currentDoc = *current;
-      Document* followingDoc = following != docs.end() ? *following : nullptr;
-
-      // 2. If following document is null, push context object on document's
-      // fullscreen element stack, and queue a task to fire an event named
-      // fullscreenchange with its bubbles attribute set to true on the
-      // document.
-      if (!followingDoc) {
-        from(*currentDoc).pushFullscreenElementStack(element, requestType);
-        from(document).enqueueChangeEvent(*currentDoc, requestType);
-        continue;
-      }
-
-      // 3. Otherwise, if document's fullscreen element stack is either empty or
-      // its top element is not following document's browsing context container,
-      Element* topElement = fullscreenElementFrom(*currentDoc);
-      HTMLFrameOwnerElement* followingOwner =
-          findContainerForDescendant(*currentDoc, *followingDoc);
-      if (!topElement || topElement != followingOwner) {
-        // ...push following document's browsing context container on document's
-        // fullscreen element stack, and queue a task to fire an event named
-        // fullscreenchange with its bubbles attribute set to true on document.
-        from(*currentDoc)
-            .pushFullscreenElementStack(*followingOwner, requestType);
-        from(document).enqueueChangeEvent(*currentDoc, requestType);
-        continue;
-      }
-
-      // 4. Otherwise, do nothing for this document. It stays the same.
-    } while (++current != docs.end());
-
-    from(document).m_forCrossProcessDescendant = forCrossProcessDescendant;
-
-    // 5. Return, and run the remaining steps asynchronously.
-    // 6. Optionally, perform some animation.
-    from(document).m_pendingFullscreenElement = &element;
-    document.frame()->chromeClient().enterFullscreen(*document.frame());
-
-    // 7. Optionally, display a message indicating how the user can exit
-    // displaying the context object fullscreen.
-    return;
-  } while (false);
-
-  from(document).enqueueErrorEvent(element, requestType);
+  // 7.7. Fulfill |promise| with undefined.
+  // TODO(foolip): Promises. https://crbug.com/644637
 }
 
 // https://fullscreen.spec.whatwg.org/#fully-exit-fullscreen
 void Fullscreen::fullyExitFullscreen(Document& document) {
-  // To fully exit fullscreen, run these steps:
+  // 1. If |document|'s fullscreen element is null, terminate these steps.
 
-  // 1. Let |doc| be the top-level browsing context's document.
-  //
-  // Since the top-level browsing context's document might be unavailable in
-  // OOPIF scenarios (i.e., when the top frame is remote), this actually uses
-  // the Document of the topmost local ancestor frame.  Without OOPIF, this
-  // will be the top frame's document.  With OOPIF, each renderer process for
-  // the current page will separately call fullyExitFullscreen to cover all
-  // local frames in each process.
-  Document& doc = topmostLocalAncestor(document);
+  // 2. Unfullscreen elements whose fullscreen flag is set, within
+  // |document|'s top layer, except for |document|'s fullscreen element.
 
-  // 2. If |doc|'s fullscreen element stack is empty, terminate these steps.
-  if (!fullscreenElementFrom(doc))
-    return;
+  // 3. Exit fullscreen |document|.
 
-  // 3. Remove elements from |doc|'s fullscreen element stack until only the top
-  // element is left.
-  size_t stackSize = from(doc).m_fullscreenElementStack.size();
-  from(doc).m_fullscreenElementStack.remove(0, stackSize - 1);
-  DCHECK_EQ(from(doc).m_fullscreenElementStack.size(), 1u);
-
-  // 4. Act as if the exitFullscreen() method was invoked on |doc|.
-  exitFullscreen(doc);
+  // TODO(foolip): Change the spec. To remove elements from |document|'s top
+  // layer as in step 2 could leave descendant frames in fullscreen. It may work
+  // to give the "exit fullscreen" algorithm a |fully| flag that's used in the
+  // animation frame task after exit. Here, retain the old behavior of fully
+  // exiting fullscreen for the topmost local ancestor:
+  exitFullscreen(topmostLocalAncestor(document), ExitType::Fully);
 }
 
 // https://fullscreen.spec.whatwg.org/#exit-fullscreen
-void Fullscreen::exitFullscreen(Document& document) {
-  // The exitFullscreen() method must run these steps:
-
-  // Ignore this call if the document is not in a live frame.
-  if (!document.isActive() || !document.frame())
+void Fullscreen::exitFullscreen(Document& doc, ExitType exitType) {
+  if (!doc.isActive() || !doc.frame())
     return;
 
-  // 1. Let doc be the context object. (i.e. "this")
-  // 2. If doc's fullscreen element stack is empty, terminate these steps.
-  if (!fullscreenElementFrom(document))
+  // 1. Let |promise| be a new promise.
+  // 2. If |doc|'s fullscreen element is null, reject |promise| with a
+  // TypeError exception, and return |promise|.
+  // TODO(foolip): Promises. https://crbug.com/644637
+  if (!fullscreenElementFrom(doc))
     return;
 
-  // 3. Let descendants be all the doc's descendant browsing context's documents
-  // with a non-empty fullscreen element stack (if any), ordered so that the
-  // child of the doc is last and the document furthest away from the doc is
-  // first.
-  HeapDeque<Member<Document>> descendants;
-  for (Frame* descendant = document.frame()->tree().traverseNext(); descendant;
-       descendant = descendant->tree().traverseNext()) {
+  // 3. Let |resize| be false.
+  bool resize = false;
+
+  // 4. Let |docs| be the result of collecting documents to unfullscreen given
+  // |doc|.
+  HeapVector<Member<Document>> docs =
+      collectDocumentsToUnfullscreen(doc, exitType);
+
+  // 5. Let |topLevelDoc| be |doc|'s top-level browsing context's document.
+  //
+  // OOPIF: Let |topLevelDoc| be the topmost local ancestor instead. If the main
+  // frame is in another process, we will still fully exit fullscreen even
+  // though that's wrong if the main frame was in nested fullscreen.
+  // TODO(alexmos): Deal with nested fullscreen cases, see
+  // https://crbug.com/617369.
+  Document& topLevelDoc = topmostLocalAncestor(doc);
+
+  // 6. If |topLevelDoc| is in |docs|, set |resize| to true.
+  if (!docs.isEmpty() && docs.back() == &topLevelDoc)
+    resize = true;
+
+  // 7. Return |promise|, and run the remaining steps in parallel.
+  // TODO(foolip): Promises. https://crbug.com/644637
+
+  // Note: |ExitType::Fully| is only used together with the topmost local
+  // ancestor in |fullyExitFullscreen()|, and so implies that |resize| is true.
+  // This would change if matching the spec for "fully exit fullscreen".
+  if (exitType == ExitType::Fully)
+    DCHECK(resize);
+
+  // 8. If |resize| is true, resize |topLevelDoc|'s viewport to its "normal"
+  // dimensions.
+  if (resize) {
+    LocalFrame& frame = *doc.frame();
+    frame.chromeClient().exitFullscreen(frame);
+  } else {
+    enqueueTaskForExit(doc, exitType);
+  }
+}
+
+void Fullscreen::didExitFullscreen() {
+  if (!document())
+    return;
+
+  DCHECK_EQ(document(), &topmostLocalAncestor(*document()));
+
+  enqueueTaskForExit(*document(), ExitType::Fully);
+}
+
+void Fullscreen::enqueueTaskForExit(Document& document, ExitType exitType) {
+  // 9. As part of the next animation frame task, run these substeps:
+  document.enqueueAnimationFrameTask(
+      WTF::bind(&runTaskForExit, wrapPersistent(&document), exitType));
+}
+
+void Fullscreen::runTaskForExit(Document* document, ExitType exitType) {
+  DCHECK(document);
+  DCHECK(document->isActive());
+  DCHECK(document->frame());
+
+  Document& doc = *document;
+
+  if (!fullscreenElementFrom(doc))
+    return;
+
+  // 9.1. Let |exitDocs| be the result of collecting documents to unfullscreen
+  // given |doc|.
+
+  // 9.2. If |resize| is true and |topLevelDoc| is not in |exitDocs|, fully
+  // exit fullscreen |topLevelDoc|, reject promise with a TypeError exception,
+  // and terminate these steps.
+
+  // TODO(foolip): See TODO in |fullyExitFullscreen()|. Instead of using "fully
+  // exit fullscreen" in step 9.2 (which is async), give "exit fullscreen" a
+  // |fully| flag which is always true if |resize| was true.
+
+  HeapVector<Member<Document>> exitDocs =
+      collectDocumentsToUnfullscreen(doc, exitType);
+
+  // 9.3. If |exitDocs| is the empty set, append |doc| to |exitDocs|.
+  if (exitDocs.isEmpty())
+    exitDocs.push_back(&doc);
+
+  // 9.4. If |exitDocs|'s last document has a browsing context container,
+  // append that browsing context container's node document to |exitDocs|.
+  //
+  // OOPIF: Skip over remote frames, assuming that they have exactly one element
+  // in their fullscreen element stacks, thereby erring on the side of exiting
+  // fullscreen. TODO(alexmos): Deal with nested fullscreen cases, see
+  // https://crbug.com/617369.
+  if (Document* document = nextLocalAncestor(*exitDocs.back()))
+    exitDocs.push_back(document);
+
+  // 9.5. Let |descendantDocs| be an ordered set consisting of |doc|'s
+  // descendant browsing contexts' documents whose fullscreen element is
+  // non-null, if any, in *reverse* tree order.
+  HeapDeque<Member<Document>> descendantDocs;
+  for (Frame* descendant = doc.frame()->tree().firstChild(); descendant;
+       descendant = descendant->tree().traverseNext(doc.frame())) {
     if (!descendant->isLocalFrame())
       continue;
     DCHECK(toLocalFrame(descendant)->document());
     if (fullscreenElementFrom(*toLocalFrame(descendant)->document()))
-      descendants.prepend(toLocalFrame(descendant)->document());
+      descendantDocs.prepend(toLocalFrame(descendant)->document());
   }
 
-  // 4. For each descendant in descendants, empty descendant's fullscreen
-  // element stack, and queue a task to fire an event named fullscreenchange
-  // with its bubbles attribute set to true on descendant.
-  for (auto& descendant : descendants) {
-    DCHECK(descendant);
-    RequestType requestType =
-        from(*descendant).m_fullscreenElementStack.back().second;
-    from(*descendant).clearFullscreenElementStack();
-    from(document).enqueueChangeEvent(*descendant, requestType);
+  // Note: For prefixed requests, the event target is an element, so let
+  // |events| be a list of events to dispatch.
+  HeapVector<Member<Event>> events;
+
+  // 9.6. For each |descendantDoc| in |descendantDocs|, in order, unfullscreen
+  // |descendantDoc|.
+  for (Document* descendantDoc : descendantDocs) {
+    Fullscreen& fullscreen = from(*descendantDoc);
+    ElementStack& stack = fullscreen.m_fullscreenElementStack;
+    DCHECK(!stack.isEmpty());
+    events.push_back(createChangeEvent(*descendantDoc, *stack.back().first,
+                                       stack.back().second));
+    while (!stack.isEmpty())
+      fullscreen.popFullscreenElementStack();
   }
 
-  // 5. While doc is not null, run these substeps:
-  Element* newTop = nullptr;
-  for (Document* currentDoc = &document; currentDoc;) {
-    RequestType requestType =
-        from(*currentDoc).m_fullscreenElementStack.back().second;
+  // 9.7. For each |exitDoc| in |exitDocs|, in order, unfullscreen |exitDoc|'s
+  // fullscreen element.
+  for (Document* exitDoc : exitDocs) {
+    Fullscreen& fullscreen = from(*exitDoc);
+    ElementStack& stack = fullscreen.m_fullscreenElementStack;
+    DCHECK(!stack.isEmpty());
+    events.push_back(
+        createChangeEvent(*exitDoc, *stack.back().first, stack.back().second));
+    fullscreen.popFullscreenElementStack();
 
-    // 1. Pop the top element of doc's fullscreen element stack.
-    from(*currentDoc).popFullscreenElementStack();
-
-    //    If doc's fullscreen element stack is non-empty and the element now at
-    //    the top is either not in a document or its node document is not doc,
-    //    repeat this substep.
-    newTop = fullscreenElementFrom(*currentDoc);
-    if (newTop && (!newTop->isConnected() || newTop->document() != currentDoc))
-      continue;
-
-    // 2. Queue a task to fire an event named fullscreenchange with its bubbles
-    // attribute set to true on doc.
-    from(document).enqueueChangeEvent(*currentDoc, requestType);
-
-    // 3. If doc's fullscreen element stack is empty and doc's browsing context
-    // has a browsing context container, set doc to that browsing context
-    // container's node document.
-    //
-    // OOPIF: If browsing context container's document is in another
-    // process, keep moving up the ancestor chain and looking for a
-    // browsing context container with a local document.
-    // TODO(alexmos): Deal with nested fullscreen cases, see
-    // https://crbug.com/617369.
-    if (!newTop) {
-      currentDoc = nextLocalAncestor(*currentDoc);
-      continue;
+    // TODO(foolip): See TODO in |fullyExitFullscreen()|.
+    if (exitDoc == &doc && exitType == ExitType::Fully) {
+      while (!stack.isEmpty())
+        fullscreen.popFullscreenElementStack();
     }
-
-    // 4. Otherwise, set doc to null.
-    currentDoc = nullptr;
   }
 
-  // 6. Return, and run the remaining steps asynchronously.
-  // 7. Optionally, perform some animation.
+  // 9.8. For each |descendantDoc| in |descendantDocs|, in order, fire an
+  // event named fullscreenchange on |descendantDoc|.
+  // 9.9. For each |exitDoc| in |exitDocs|, in order, fire an event named
+  // fullscreenchange on |exitDoc|.
+  dispatchEvents(events);
 
-  // Only exit fullscreen mode if the fullscreen element stack is empty.
-  if (!newTop) {
-    document.frame()->chromeClient().exitFullscreen(*document.frame());
-    return;
-  }
-
-  // Otherwise, enter fullscreen for the fullscreen element stack's top element.
-  from(document).m_pendingFullscreenElement = newTop;
-  from(document).didEnterFullscreen();
+  // 9.10. Fulfill |promise| with undefined.
+  // TODO(foolip): Promises. https://crbug.com/644637
 }
 
 // https://fullscreen.spec.whatwg.org/#dom-document-fullscreenenabled
@@ -592,123 +760,6 @@
          fullscreenIsSupported(document);
 }
 
-void Fullscreen::didEnterFullscreen() {
-  if (!document()->isActive() || !document()->frame())
-    return;
-
-  // Start the timer for events enqueued by |requestFullscreen()|. The hover
-  // state update is scheduled first so that it's done when the events fire.
-  document()->frame()->eventHandler().scheduleHoverStateUpdate();
-  m_eventQueueTimer.startOneShot(0, BLINK_FROM_HERE);
-
-  Element* element = m_pendingFullscreenElement.release();
-  if (!element)
-    return;
-
-  if (m_currentFullScreenElement == element)
-    return;
-
-  if (!element->isConnected() || &element->document() != document()) {
-    // The element was removed or has moved to another document since the
-    // |requestFullscreen()| call. Exit fullscreen again to recover.
-    // TODO(foolip): Fire a fullscreenerror event. This is currently difficult
-    // because the fullscreenchange event has already been enqueued and possibly
-    // even fired. https://crbug.com/402376
-    LocalFrame& frame = *document()->frame();
-    frame.chromeClient().exitFullscreen(frame);
-    return;
-  }
-
-  if (m_fullScreenLayoutObject)
-    m_fullScreenLayoutObject->unwrapLayoutObject();
-
-  Element* previousElement = m_currentFullScreenElement;
-  m_currentFullScreenElement = element;
-
-  // Create a placeholder block for a the full-screen element, to keep the page
-  // from reflowing when the element is removed from the normal flow. Only do
-  // this for a LayoutBox, as only a box will have a frameRect. The placeholder
-  // will be created in setFullScreenLayoutObject() during layout.
-  LayoutObject* layoutObject = m_currentFullScreenElement->layoutObject();
-  bool shouldCreatePlaceholder = layoutObject && layoutObject->isBox();
-  if (shouldCreatePlaceholder) {
-    m_savedPlaceholderFrameRect = toLayoutBox(layoutObject)->frameRect();
-    m_savedPlaceholderComputedStyle =
-        ComputedStyle::clone(layoutObject->styleRef());
-  }
-
-  // TODO(alexmos): When |m_forCrossProcessDescendant| is true, some of
-  // this layout work has already been done in another process, so it should
-  // not be necessary to repeat it here.
-  if (m_currentFullScreenElement != document()->documentElement())
-    LayoutFullScreen::wrapLayoutObject(
-        layoutObject, layoutObject ? layoutObject->parent() : 0, document());
-
-  // When |m_forCrossProcessDescendant| is true, m_currentFullScreenElement
-  // corresponds to the HTMLFrameOwnerElement for the out-of-process iframe
-  // that contains the actual fullscreen element.   Hence, it must also set
-  // the ContainsFullScreenElement flag (so that it gains the
-  // -webkit-full-screen-ancestor style).
-  if (m_forCrossProcessDescendant) {
-    DCHECK(m_currentFullScreenElement->isFrameOwnerElement());
-    DCHECK(toHTMLFrameOwnerElement(m_currentFullScreenElement)
-               ->contentFrame()
-               ->isRemoteFrame());
-    m_currentFullScreenElement->setContainsFullScreenElement(true);
-  }
-
-  m_currentFullScreenElement
-      ->setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(true);
-
-  document()->styleEngine().ensureUAStyleForFullscreen();
-  m_currentFullScreenElement->pseudoStateChanged(CSSSelector::PseudoFullScreen);
-
-  // FIXME: This should not call updateStyleAndLayoutTree.
-  document()->updateStyleAndLayoutTree();
-
-  document()->frame()->chromeClient().fullscreenElementChanged(previousElement,
-                                                               element);
-}
-
-void Fullscreen::didExitFullscreen() {
-  if (!document()->isActive() || !document()->frame())
-    return;
-
-  // Start the timer for events enqueued by |exitFullscreen()|. The hover state
-  // update is scheduled first so that it's done when the events fire.
-  document()->frame()->eventHandler().scheduleHoverStateUpdate();
-  m_eventQueueTimer.startOneShot(0, BLINK_FROM_HERE);
-
-  // If fullscreen was canceled by the browser, e.g. if the user pressed Esc,
-  // then |exitFullscreen()| was never called. Let |fullyExitFullscreen()| clear
-  // the fullscreen element stack and fire any events as necessary.
-  // TODO(foolip): Remove this when state changes and events are synchronized
-  // with animation frames. https://crbug.com/402376
-  fullyExitFullscreen(*document());
-
-  if (!m_currentFullScreenElement)
-    return;
-
-  if (m_forCrossProcessDescendant)
-    m_currentFullScreenElement->setContainsFullScreenElement(false);
-
-  m_currentFullScreenElement
-      ->setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
-
-  if (m_fullScreenLayoutObject)
-    LayoutFullScreenItem(m_fullScreenLayoutObject).unwrapLayoutObject();
-
-  document()->styleEngine().ensureUAStyleForFullscreen();
-  m_currentFullScreenElement->pseudoStateChanged(CSSSelector::PseudoFullScreen);
-  Element* previousElement = m_currentFullScreenElement;
-  m_currentFullScreenElement = nullptr;
-
-  m_forCrossProcessDescendant = false;
-
-  document()->frame()->chromeClient().fullscreenElementChanged(previousElement,
-                                                               nullptr);
-}
-
 void Fullscreen::setFullScreenLayoutObject(LayoutFullScreen* layoutObject) {
   if (layoutObject == m_fullScreenLayoutObject)
     return;
@@ -735,56 +786,9 @@
   m_fullScreenLayoutObject = nullptr;
 }
 
-void Fullscreen::enqueueChangeEvent(Document& document,
-                                    RequestType requestType) {
-  Event* event;
-  if (requestType == RequestType::Unprefixed) {
-    event = createEvent(EventTypeNames::fullscreenchange, document);
-  } else {
-    DCHECK(document.hasFullscreenSupplement());
-    Fullscreen& fullscreen = from(document);
-    EventTarget* target = fullscreen.fullscreenElement();
-    if (!target)
-      target = fullscreen.currentFullScreenElement();
-    if (!target)
-      target = &document;
-    event = createEvent(EventTypeNames::webkitfullscreenchange, *target);
-  }
-  m_eventQueue.append(event);
-  // NOTE: The timer is started in didEnterFullscreen/didExitFullscreen.
-}
-
-void Fullscreen::enqueueErrorEvent(Element& element, RequestType requestType) {
-  Event* event;
-  if (requestType == RequestType::Unprefixed)
-    event = createEvent(EventTypeNames::fullscreenerror, element.document());
-  else
-    event = createEvent(EventTypeNames::webkitfullscreenerror, element);
-  m_eventQueue.append(event);
-  m_eventQueueTimer.startOneShot(0, BLINK_FROM_HERE);
-}
-
-void Fullscreen::eventQueueTimerFired(TimerBase*) {
-  HeapDeque<Member<Event>> eventQueue;
-  m_eventQueue.swap(eventQueue);
-
-  while (!eventQueue.isEmpty()) {
-    Event* event = eventQueue.takeFirst();
-    Node* target = event->target()->toNode();
-
-    // If the element was removed from our tree, also message the
-    // documentElement.
-    if (!target->isConnected() && document()->documentElement()) {
-      DCHECK(isPrefixed(event->type()));
-      eventQueue.append(
-          createEvent(event->type(), *document()->documentElement()));
-    }
-
-    target->dispatchEvent(event);
-  }
-}
-
 void Fullscreen::elementRemoved(Element& oldNode) {
+  DCHECK_EQ(document(), &oldNode.document());
+
   // Whenever the removing steps run with an |oldNode| and |oldNode| is in its
   // node document's fullscreen element stack, run these steps:
 
@@ -807,27 +811,98 @@
   // NOTE: |oldNode| was not in the fullscreen element stack.
 }
 
-void Fullscreen::clearFullscreenElementStack() {
-  m_fullscreenElementStack.clear();
-}
-
 void Fullscreen::popFullscreenElementStack() {
-  if (m_fullscreenElementStack.isEmpty())
-    return;
+  DCHECK(!m_fullscreenElementStack.isEmpty());
 
+  Element* previousElement = fullscreenElement();
   m_fullscreenElementStack.pop_back();
+
+  // Note: |requestType| is only used if |fullscreenElement()| is non-null.
+  RequestType requestType = m_fullscreenElementStack.isEmpty()
+                                ? RequestType::Unprefixed
+                                : m_fullscreenElementStack.back().second;
+  fullscreenElementChanged(previousElement, fullscreenElement(), requestType);
 }
 
 void Fullscreen::pushFullscreenElementStack(Element& element,
                                             RequestType requestType) {
+  Element* previousElement = fullscreenElement();
   m_fullscreenElementStack.push_back(std::make_pair(&element, requestType));
+
+  fullscreenElementChanged(previousElement, &element, requestType);
+}
+
+void Fullscreen::fullscreenElementChanged(Element* fromElement,
+                                          Element* toElement,
+                                          RequestType toRequestType) {
+  DCHECK_NE(fromElement, toElement);
+
+  if (!document())
+    return;
+
+  document()->styleEngine().ensureUAStyleForFullscreen();
+
+  if (m_fullScreenLayoutObject)
+    m_fullScreenLayoutObject->unwrapLayoutObject();
+  DCHECK(!m_fullScreenLayoutObject);
+
+  if (fromElement) {
+    DCHECK_NE(fromElement, fullscreenElement());
+
+    fromElement->pseudoStateChanged(CSSSelector::PseudoFullScreen);
+
+    fromElement->setContainsFullScreenElement(false);
+    fromElement->setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(
+        false);
+  }
+
+  if (toElement) {
+    DCHECK_EQ(toElement, fullscreenElement());
+
+    toElement->pseudoStateChanged(CSSSelector::PseudoFullScreen);
+
+    // OOPIF: For RequestType::PrefixedForCrossProcessDescendant, |toElement| is
+    // the iframe element for the out-of-process frame that contains the
+    // fullscreen element. Hence, it must match :-webkit-full-screen-ancestor.
+    if (toRequestType == RequestType::PrefixedForCrossProcessDescendant) {
+      DCHECK(isHTMLIFrameElement(toElement));
+      toElement->setContainsFullScreenElement(true);
+    }
+    toElement->setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(
+        true);
+
+    // Create a placeholder block for the fullscreen element, to keep the page
+    // from reflowing when the element is removed from the normal flow. Only do
+    // this for a LayoutBox, as only a box will have a frameRect. The
+    // placeholder will be created in setFullScreenLayoutObject() during layout.
+    LayoutObject* layoutObject = toElement->layoutObject();
+    bool shouldCreatePlaceholder = layoutObject && layoutObject->isBox();
+    if (shouldCreatePlaceholder) {
+      m_savedPlaceholderFrameRect = toLayoutBox(layoutObject)->frameRect();
+      m_savedPlaceholderComputedStyle =
+          ComputedStyle::clone(layoutObject->styleRef());
+    }
+
+    if (toElement != document()->documentElement()) {
+      LayoutFullScreen::wrapLayoutObject(
+          layoutObject, layoutObject ? layoutObject->parent() : 0, document());
+    }
+  }
+
+  if (LocalFrame* frame = document()->frame()) {
+    // TODO(foolip): Synchronize hover state changes with animation frames.
+    // https://crbug.com/668758
+    frame->eventHandler().scheduleHoverStateUpdate();
+    frame->chromeClient().fullscreenElementChanged(fromElement, toElement);
+  }
+
+  // TODO(foolip): This should not call updateStyleAndLayoutTree.
+  document()->updateStyleAndLayoutTree();
 }
 
 DEFINE_TRACE(Fullscreen) {
-  visitor->trace(m_pendingFullscreenElement);
+  visitor->trace(m_pendingRequests);
   visitor->trace(m_fullscreenElementStack);
-  visitor->trace(m_currentFullScreenElement);
-  visitor->trace(m_eventQueue);
   Supplement<Document>::trace(visitor);
   ContextLifecycleObserver::trace(visitor);
 }
diff --git a/third_party/WebKit/Source/core/dom/Fullscreen.h b/third_party/WebKit/Source/core/dom/Fullscreen.h
index a93806d..7bc3a7f 100644
--- a/third_party/WebKit/Source/core/dom/Fullscreen.h
+++ b/third_party/WebKit/Source/core/dom/Fullscreen.h
@@ -35,7 +35,6 @@
 #include "core/dom/Document.h"
 #include "core/dom/Element.h"
 #include "platform/Supplementable.h"
-#include "platform/Timer.h"
 #include "platform/geometry/LayoutRect.h"
 #include "wtf/Deque.h"
 #include "wtf/RefPtr.h"
@@ -59,9 +58,8 @@
   static Fullscreen* fromIfExists(Document&);
   static Element* fullscreenElementFrom(Document&);
   static Element* fullscreenElementForBindingFrom(TreeScope&);
-  static Element* currentFullScreenElementFrom(Document&);
-  static Element* currentFullScreenElementForBindingFrom(Document&);
-  static bool isCurrentFullScreenElement(const Element&);
+  static size_t fullscreenElementStackSizeFrom(Document&);
+  static bool isFullscreenElement(const Element&);
 
   enum class RequestType {
     // Element.requestFullscreen()
@@ -69,25 +67,26 @@
     // Element.webkitRequestFullscreen()/webkitRequestFullScreen() and
     // HTMLVideoElement.webkitEnterFullscreen()/webkitEnterFullScreen()
     Prefixed,
+    // For WebRemoteFrameImpl to notify that a cross-process descendant frame
+    // has requested and is about to enter fullscreen.
+    PrefixedForCrossProcessDescendant,
   };
 
   static void requestFullscreen(Element&);
-
-  // |forCrossProcessDescendant| is used in OOPIF scenarios and is set to
-  // true when fullscreen is requested for an out-of-process descendant
-  // element.
-  static void requestFullscreen(Element&,
-                                RequestType,
-                                bool forCrossProcessDescendant = false);
+  static void requestFullscreen(Element&, RequestType);
 
   static void fullyExitFullscreen(Document&);
-  static void exitFullscreen(Document&);
+
+  enum class ExitType {
+    // Exits fullscreen for one element in the document.
+    Default,
+    // Fully exits fullscreen for the document.
+    Fully,
+  };
+
+  static void exitFullscreen(Document&, ExitType = ExitType::Default);
 
   static bool fullscreenEnabled(Document&);
-  // TODO(foolip): The fullscreen element stack is modified synchronously in
-  // requestFullscreen(), which is not per spec and means that
-  // |fullscreenElement()| is not always the same as
-  // |currentFullScreenElement()|, see https://crbug.com/402421.
   Element* fullscreenElement() const {
     return !m_fullscreenElementStack.isEmpty()
                ? m_fullscreenElementStack.back().first.get()
@@ -107,20 +106,6 @@
 
   void elementRemoved(Element&);
 
-  // Returns true if the current fullscreen element stack corresponds to a
-  // container for an actual fullscreen element in a descendant
-  // out-of-process iframe.
-  bool forCrossProcessDescendant() { return m_forCrossProcessDescendant; }
-
-  // Mozilla API
-  // TODO(foolip): |currentFullScreenElement()| is a remnant from before the
-  // fullscreen element stack. It is still maintained separately from the
-  // stack and is is what the :-webkit-full-screen pseudo-class depends on. It
-  // should be removed, see https://crbug.com/402421.
-  Element* currentFullScreenElement() const {
-    return m_currentFullScreenElement.get();
-  }
-
   // ContextLifecycleObserver:
   void contextDestroyed() override;
 
@@ -133,33 +118,30 @@
 
   Document* document();
 
+  static void enqueueTaskForRequest(Document&,
+                                    Element&,
+                                    RequestType,
+                                    bool error);
+  static void runTaskForRequest(Document*, Element*, RequestType, bool error);
+
+  static void enqueueTaskForExit(Document&, ExitType);
+  static void runTaskForExit(Document*, ExitType);
+
   void clearFullscreenElementStack();
   void popFullscreenElementStack();
   void pushFullscreenElementStack(Element&, RequestType);
+  void fullscreenElementChanged(Element* fromElement,
+                                Element* toElement,
+                                RequestType toRequestType);
 
-  void enqueueChangeEvent(Document&, RequestType);
-  void enqueueErrorEvent(Element&, RequestType);
-  void eventQueueTimerFired(TimerBase*);
+  using ElementStackEntry = std::pair<Member<Element>, RequestType>;
+  using ElementStack = HeapVector<ElementStackEntry>;
+  ElementStack m_pendingRequests;
+  ElementStack m_fullscreenElementStack;
 
-  Member<Element> m_pendingFullscreenElement;
-  HeapVector<std::pair<Member<Element>, RequestType>> m_fullscreenElementStack;
-  Member<Element> m_currentFullScreenElement;
   LayoutFullScreen* m_fullScreenLayoutObject;
-  Timer<Fullscreen> m_eventQueueTimer;
-  HeapDeque<Member<Event>> m_eventQueue;
   LayoutRect m_savedPlaceholderFrameRect;
   RefPtr<ComputedStyle> m_savedPlaceholderComputedStyle;
-
-  // TODO(alexmos, dcheng): Currently, this assumes that if fullscreen was
-  // entered for an element in an out-of-process iframe, then it's not
-  // possible to re-enter fullscreen for a different element in this
-  // document, since that requires a user gesture, which can't be obtained
-  // since nothing in this document is visible, and since user gestures can't
-  // be forwarded across processes. However, the latter assumption could
-  // change if https://crbug.com/161068 is fixed so that cross-process
-  // postMessage can carry user gestures.  If that happens, this should be
-  // moved to be part of |m_fullscreenElementStack|.
-  bool m_forCrossProcessDescendant;
 };
 
 inline Fullscreen* Fullscreen::fromIfExists(Document& document) {
@@ -168,9 +150,9 @@
   return fromIfExistsSlow(document);
 }
 
-inline bool Fullscreen::isCurrentFullScreenElement(const Element& element) {
+inline bool Fullscreen::isFullscreenElement(const Element& element) {
   if (Fullscreen* found = fromIfExists(element.document()))
-    return found->currentFullScreenElement() == &element;
+    return found->fullscreenElement() == &element;
   return false;
 }
 
diff --git a/third_party/WebKit/Source/core/dom/LayoutTreeBuilder.cpp b/third_party/WebKit/Source/core/dom/LayoutTreeBuilder.cpp
index 77046c3..5b16dac 100644
--- a/third_party/WebKit/Source/core/dom/LayoutTreeBuilder.cpp
+++ b/third_party/WebKit/Source/core/dom/LayoutTreeBuilder.cpp
@@ -143,7 +143,7 @@
   newLayoutObject->setStyle(
       &style);  // setStyle() can depend on layoutObject() already being set.
 
-  if (Fullscreen::isCurrentFullScreenElement(*m_node)) {
+  if (Fullscreen::isFullscreenElement(*m_node)) {
     newLayoutObject = LayoutFullScreen::wrapLayoutObject(
         newLayoutObject, parentLayoutObject, &m_node->document());
     if (!newLayoutObject)
diff --git a/third_party/WebKit/Source/core/editing/Editor.cpp b/third_party/WebKit/Source/core/editing/Editor.cpp
index 8c1574d..29548912 100644
--- a/third_party/WebKit/Source/core/editing/Editor.cpp
+++ b/third_party/WebKit/Source/core/editing/Editor.cpp
@@ -1257,18 +1257,16 @@
   return m_undoStack->canUndo();
 }
 
-// TODO(chongz): Fire 'beforeinput' for user triggered undo.
-void Editor::undo(EditCommandSource) {
-  m_undoStack->undo();
+void Editor::undo(EditCommandSource source) {
+  m_undoStack->undo(source);
 }
 
 bool Editor::canRedo() {
   return m_undoStack->canRedo();
 }
 
-// TODO(chongz): Fire 'beforeinput' for user triggered redo.
-void Editor::redo(EditCommandSource) {
-  m_undoStack->redo();
+void Editor::redo(EditCommandSource source) {
+  m_undoStack->redo(source);
 }
 
 void Editor::setBaseWritingDirection(WritingDirection direction) {
diff --git a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
index e5bd64d..ee81dce2 100644
--- a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
@@ -105,11 +105,14 @@
   return m_document->frame() == &frame;
 }
 
-void EditCommandComposition::unapply() {
+void EditCommandComposition::unapply(EditCommandSource source) {
   DCHECK(m_document);
   LocalFrame* frame = m_document->frame();
   DCHECK(frame);
 
+  if (!willUnapply(source))
+    return;
+
   // Changes to the document may have been made since the last editing operation
   // that require a layout, as in <rdar://problem/5658603>. Low level
   // operations, like RemoveNodeCommand, don't require a layout because the high
@@ -126,11 +129,14 @@
   frame->editor().unappliedEditing(this);
 }
 
-void EditCommandComposition::reapply() {
+void EditCommandComposition::reapply(EditCommandSource source) {
   DCHECK(m_document);
   LocalFrame* frame = m_document->frame();
   DCHECK(frame);
 
+  if (!willReapply(source))
+    return;
+
   // Changes to the document may have been made since the last editing operation
   // that require a layout, as in <rdar://problem/5658603>. Low level
   // operations, like RemoveNodeCommand, don't require a layout because the high
@@ -146,6 +152,16 @@
   frame->editor().reappliedEditing(this);
 }
 
+bool EditCommandComposition::willUnapply(EditCommandSource) {
+  // TODO(chongz): Fire 'beforeinput' for 'historyUndo'.
+  return true;
+}
+
+bool EditCommandComposition::willReapply(EditCommandSource) {
+  // TODO(chongz): Fire 'beforeinput' for 'historyRedo'.
+  return true;
+}
+
 InputEvent::InputType EditCommandComposition::inputType() const {
   return m_inputType;
 }
@@ -187,8 +203,7 @@
   DCHECK(isTopLevelCommand() || !m_composition);
 }
 
-// TODO(chongz): Fire 'beforeinput' based on |EditCommandSource|.
-bool CompositeEditCommand::apply(EditCommandSource) {
+bool CompositeEditCommand::apply(EditCommandSource source) {
   DCHECK(!isCommandGroupWrapper());
   if (!endingSelection().isContentRichlyEditable()) {
     switch (inputType()) {
@@ -224,6 +239,9 @@
   // the creation of VisiblePositions).
   document().updateStyleAndLayoutIgnorePendingStylesheets();
 
+  if (!willApplyEditing(source))
+    return false;
+
   LocalFrame* frame = document().frame();
   DCHECK(frame);
   EditingState editingState;
@@ -250,6 +268,11 @@
   return command->m_composition.get();
 }
 
+bool CompositeEditCommand::willApplyEditing(EditCommandSource) {
+  // TODO(chongz): Move all the 'beforeinput' dispatching logic here.
+  return true;
+}
+
 bool CompositeEditCommand::preservesTypingStyle() const {
   return false;
 }
diff --git a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.h b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.h
index f2d7317e..39ffedf1 100644
--- a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.h
+++ b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.h
@@ -52,8 +52,8 @@
                                         InputEvent::InputType);
 
   bool belongsTo(const LocalFrame&) const override;
-  void unapply() override;
-  void reapply() override;
+  void unapply(EditCommandSource) override;
+  void reapply(EditCommandSource) override;
   InputEvent::InputType inputType() const override;
   void append(SimpleEditCommand*);
   void append(EditCommandComposition*);
@@ -79,6 +79,14 @@
                          const VisibleSelection& endingSelection,
                          InputEvent::InputType);
 
+  // TODO(chongz): Implement "beforeinput" as described below:
+  // Fires "beforeinput" and will returns |false| to cancel unapply / reapply if
+  //   * "beforeinput" was canceled, or
+  //   * |frame| was destroyed by event handlers.
+  // Note: Undo stack will always get popped.
+  bool willUnapply(EditCommandSource);
+  bool willReapply(EditCommandSource);
+
   Member<Document> m_document;
   VisibleSelection m_startingSelection;
   VisibleSelection m_endingSelection;
@@ -118,6 +126,15 @@
  protected:
   explicit CompositeEditCommand(Document&);
 
+  // TODO(chongz): Implement "beforeinput" as described below:
+  // Fires "beforeinput" and will return |false| to cancel applying editing if
+  //   * "beforeinput" was canceled, or
+  //   * |frame| was destroyed by event handlers.
+  // |willApplyEditing()| should be called from
+  //   * |CompositeEditCommand::apply()|, and
+  //   * |TypingCommand::willAddTypingToOpenCommand()|.
+  bool willApplyEditing(EditCommandSource);
+
   //
   // sugary-sweet convenience functions to help create and apply edit commands
   // in composite commands
diff --git a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
index 6f61e14..c7c0ecd 100644
--- a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
@@ -122,6 +122,39 @@
   return event->text().length();
 }
 
+InputEvent::InputType inputTypeForTypingCommand(
+    TypingCommand::ETypingCommand commandType,
+    TextGranularity granularity,
+    TypingCommand::TextCompositionType compositionType) {
+  using InputType = InputEvent::InputType;
+
+  switch (commandType) {
+    // TODO(chongz): |DeleteSelection| is used by IME but we don't have
+    // direction info.
+    case TypingCommand::DeleteSelection:
+      return InputType::DeleteContentBackward;
+    case TypingCommand::DeleteKey:
+      if (compositionType != TypingCommand::TextCompositionNone)
+        return InputType::DeleteComposedCharacterBackward;
+      return deletionInputTypeFromTextGranularity(DeleteDirection::Backward,
+                                                  granularity);
+    case TypingCommand::ForwardDeleteKey:
+      if (compositionType != TypingCommand::TextCompositionNone)
+        return InputType::DeleteComposedCharacterForward;
+      return deletionInputTypeFromTextGranularity(DeleteDirection::Forward,
+                                                  granularity);
+    case TypingCommand::InsertText:
+      return InputType::InsertText;
+    case TypingCommand::InsertLineBreak:
+      return InputType::InsertLineBreak;
+    case TypingCommand::InsertParagraphSeparator:
+    case TypingCommand::InsertParagraphSeparatorInQuotedContent:
+      return InputType::InsertParagraph;
+    default:
+      return InputType::None;
+  }
+}
+
 }  // anonymous namespace
 
 using namespace HTMLNames;
@@ -145,6 +178,8 @@
       m_shouldRetainAutocorrectionIndicator(options &
                                             RetainAutocorrectionIndicator),
       m_shouldPreventSpellChecking(options & PreventSpellChecking) {
+  m_inputType = inputTypeForTypingCommand(m_commandType, m_granularity,
+                                          m_compositionType);
   updatePreservesTypingStyle(m_commandType);
 }
 
@@ -163,6 +198,9 @@
 
     lastTypingCommand->setShouldPreventSpellChecking(options &
                                                      PreventSpellChecking);
+    if (!lastTypingCommand->willAddTypingToOpenCommand(
+            source, InputEvent::InputType::DeleteContentBackward))
+      return;
     // InputMethodController uses this function to delete composition
     // selection.  It won't be aborted.
     lastTypingCommand->deleteSelection(options & SmartDelete,
@@ -189,6 +227,9 @@
                                                        frame);
         lastTypingCommand->setShouldPreventSpellChecking(options &
                                                          PreventSpellChecking);
+        if (!lastTypingCommand->willAddTypingToOpenCommand(
+                source, InputEvent::InputType::DeleteContentBackward))
+          return;
         EditingState editingState;
         lastTypingCommand->deleteKeyPressed(granularity, options & KillRing,
                                             &editingState);
@@ -215,6 +256,9 @@
       updateSelectionIfDifferentFromCurrentSelection(lastTypingCommand, frame);
       lastTypingCommand->setShouldPreventSpellChecking(options &
                                                        PreventSpellChecking);
+      if (!lastTypingCommand->willAddTypingToOpenCommand(
+              source, InputEvent::InputType::DeleteContentForward))
+        return;
       lastTypingCommand->forwardDeleteKeyPressed(
           granularity, options & KillRing, editingState);
       return;
@@ -226,9 +270,9 @@
 }
 
 String TypingCommand::textDataForInputEvent() const {
-  if (m_commands.isEmpty() || isIncrementalInsertion())
+  if (m_inputType == InputEvent::InputType::InsertText)
     return m_textToInsert;
-  return m_commands.back()->textDataForInputEvent();
+  return CompositeEditCommand::textDataForInputEvent();
 }
 
 void TypingCommand::updateSelectionIfDifferentFromCurrentSelection(
@@ -331,8 +375,11 @@
         options & RetainAutocorrectionIndicator);
     lastTypingCommand->setShouldPreventSpellChecking(options &
                                                      PreventSpellChecking);
-    EditingState editingState;
     lastTypingCommand->m_isIncrementalInsertion = isIncrementalInsertion;
+    if (!lastTypingCommand->willAddTypingToOpenCommand(
+            source, InputEvent::InputType::InsertText, newText))
+      return;
+    EditingState editingState;
     lastTypingCommand->insertText(newText, options & SelectInsertedText,
                                   &editingState);
 
@@ -383,6 +430,9 @@
   if (TypingCommand* lastTypingCommand =
           lastTypingCommandIfStillOpenForTyping(document.frame())) {
     lastTypingCommand->setShouldRetainAutocorrectionIndicator(false);
+    if (!lastTypingCommand->willAddTypingToOpenCommand(
+            source, InputEvent::InputType::InsertLineBreak))
+      return false;
     EditingState editingState;
     lastTypingCommand->insertLineBreak(&editingState);
     return !editingState.isAborted();
@@ -396,6 +446,9 @@
     EditCommandSource source) {
   if (TypingCommand* lastTypingCommand =
           lastTypingCommandIfStillOpenForTyping(document.frame())) {
+    if (!lastTypingCommand->willAddTypingToOpenCommand(
+            source, InputEvent::InputType::InsertParagraph))
+      return false;
     EditingState editingState;
     lastTypingCommand->insertParagraphSeparatorInQuotedContent(&editingState);
     return !editingState.isAborted();
@@ -411,6 +464,9 @@
   if (TypingCommand* lastTypingCommand =
           lastTypingCommandIfStillOpenForTyping(document.frame())) {
     lastTypingCommand->setShouldRetainAutocorrectionIndicator(false);
+    if (!lastTypingCommand->willAddTypingToOpenCommand(
+            source, InputEvent::InputType::InsertParagraph))
+      return false;
     EditingState editingState;
     lastTypingCommand->insertParagraphSeparator(&editingState);
     return !editingState.isAborted();
@@ -475,33 +531,15 @@
 }
 
 InputEvent::InputType TypingCommand::inputType() const {
-  using InputType = InputEvent::InputType;
+  return m_inputType;
+}
 
-  switch (m_commandType) {
-    // TODO(chongz): |DeleteSelection| is used by IME but we don't have
-    // direction info.
-    case DeleteSelection:
-      return InputType::DeleteContentBackward;
-    case DeleteKey:
-      if (m_compositionType != TextCompositionNone)
-        return InputType::DeleteComposedCharacterBackward;
-      return deletionInputTypeFromTextGranularity(DeleteDirection::Backward,
-                                                  m_granularity);
-    case ForwardDeleteKey:
-      if (m_compositionType != TextCompositionNone)
-        return InputType::DeleteComposedCharacterForward;
-      return deletionInputTypeFromTextGranularity(DeleteDirection::Forward,
-                                                  m_granularity);
-    case InsertText:
-      return InputType::InsertText;
-    case InsertLineBreak:
-      return InputType::InsertLineBreak;
-    case InsertParagraphSeparator:
-    case InsertParagraphSeparatorInQuotedContent:
-      return InputType::InsertParagraph;
-    default:
-      return InputType::None;
-  }
+bool TypingCommand::willAddTypingToOpenCommand(EditCommandSource source,
+                                               InputEvent::InputType inputType,
+                                               const String& text) {
+  m_inputType = inputType;
+  m_textToInsert = text;
+  return willApplyEditing(source);
 }
 
 void TypingCommand::typingAddedToOpenCommand(
diff --git a/third_party/WebKit/Source/core/editing/commands/TypingCommand.h b/third_party/WebKit/Source/core/editing/commands/TypingCommand.h
index 49242a6b..ecc6a3d 100644
--- a/third_party/WebKit/Source/core/editing/commands/TypingCommand.h
+++ b/third_party/WebKit/Source/core/editing/commands/TypingCommand.h
@@ -107,8 +107,7 @@
 
   ETypingCommand commandTypeOfOpenCommand() const { return m_commandType; }
   TextCompositionType compositionType() const { return m_compositionType; }
-  // |TypingCommand| may contain multiple |InsertTextCommand|, should return
-  // |textDataForInputEvent()| of the last one.
+  // Returns text data of the last added typing.
   String textDataForInputEvent() const final;
 
  private:
@@ -160,6 +159,10 @@
                                                              LocalFrame*);
 
   void updatePreservesTypingStyle(ETypingCommand);
+  // Returns |false| to cancel adding typing.
+  bool willAddTypingToOpenCommand(EditCommandSource,
+                                  InputEvent::InputType,
+                                  const String& text = nullAtom);
   void typingAddedToOpenCommand(ETypingCommand);
   bool makeEditableRootEmpty(EditingState*);
 
@@ -171,6 +174,7 @@
 
   ETypingCommand m_commandType;
   String m_textToInsert;
+  InputEvent::InputType m_inputType;
   bool m_openForMoreTyping;
   bool m_selectInsertedText;
   bool m_smartDelete;
diff --git a/third_party/WebKit/Source/core/editing/commands/UndoStack.cpp b/third_party/WebKit/Source/core/editing/commands/UndoStack.cpp
index 7f435982..c334074 100644
--- a/third_party/WebKit/Source/core/editing/commands/UndoStack.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/UndoStack.cpp
@@ -64,17 +64,17 @@
   return !m_redoStack.isEmpty();
 }
 
-void UndoStack::undo() {
+void UndoStack::undo(EditCommandSource source) {
   if (canUndo()) {
     UndoStepStack::iterator back = --m_undoStack.end();
     UndoStep* step(back->get());
     m_undoStack.remove(back);
-    step->unapply();
+    step->unapply(source);
     // unapply will call us back to push this command onto the redo stack.
   }
 }
 
-void UndoStack::redo() {
+void UndoStack::redo(EditCommandSource source) {
   if (canRedo()) {
     UndoStepStack::iterator back = --m_redoStack.end();
     UndoStep* step(back->get());
@@ -82,7 +82,7 @@
 
     DCHECK(!m_inRedo);
     AutoReset<bool> redoScope(&m_inRedo, true);
-    step->reapply();
+    step->reapply(source);
     // reapply will call us back to push this command onto the undo stack.
   }
 }
diff --git a/third_party/WebKit/Source/core/editing/commands/UndoStack.h b/third_party/WebKit/Source/core/editing/commands/UndoStack.h
index 8f7e3c83..2ed2a58 100644
--- a/third_party/WebKit/Source/core/editing/commands/UndoStack.h
+++ b/third_party/WebKit/Source/core/editing/commands/UndoStack.h
@@ -37,6 +37,7 @@
 
 namespace blink {
 
+enum class EditCommandSource;
 class LocalFrame;
 class UndoStep;
 
@@ -52,8 +53,8 @@
   void registerRedoStep(UndoStep*);
   bool canUndo() const;
   bool canRedo() const;
-  void undo();
-  void redo();
+  void undo(EditCommandSource);
+  void redo(EditCommandSource);
   void clear();
 
   DECLARE_TRACE();
diff --git a/third_party/WebKit/Source/core/editing/commands/UndoStep.h b/third_party/WebKit/Source/core/editing/commands/UndoStep.h
index 4aa7689..08011f0 100644
--- a/third_party/WebKit/Source/core/editing/commands/UndoStep.h
+++ b/third_party/WebKit/Source/core/editing/commands/UndoStep.h
@@ -36,6 +36,7 @@
 
 namespace blink {
 
+enum class EditCommandSource;
 class LocalFrame;
 
 class UndoStep : public GarbageCollectedFinalized<UndoStep> {
@@ -44,8 +45,8 @@
   DEFINE_INLINE_VIRTUAL_TRACE() {}
 
   virtual bool belongsTo(const LocalFrame&) const = 0;
-  virtual void unapply() = 0;
-  virtual void reapply() = 0;
+  virtual void unapply(EditCommandSource) = 0;
+  virtual void reapply(EditCommandSource) = 0;
   virtual InputEvent::InputType inputType() const = 0;
 };
 
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
index a6d00fd..fbe421b 100644
--- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
@@ -850,6 +850,8 @@
   return true;
 }
 
+namespace {
+
 class UnacceleratedSurfaceFactory
     : public RecordingImageBufferFallbackSurfaceFactory {
  public:
@@ -865,6 +867,8 @@
   virtual ~UnacceleratedSurfaceFactory() {}
 };
 
+}  // namespace
+
 bool HTMLCanvasElement::shouldUseDisplayList(const IntSize& deviceSize) {
   if (m_context->colorSpace() != kLegacyCanvasColorSpace)
     return false;
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
index 23c2a4e0..1ddf9ba 100644
--- a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
@@ -3427,7 +3427,7 @@
 }
 
 bool HTMLMediaElement::isFullscreen() const {
-  return Fullscreen::isCurrentFullScreenElement(*this);
+  return Fullscreen::isFullscreenElement(*this);
 }
 
 void HTMLMediaElement::didEnterFullscreen() {
diff --git a/third_party/WebKit/Source/core/html/shadow/MediaControlsOrientationLockDelegateTest.cpp b/third_party/WebKit/Source/core/html/shadow/MediaControlsOrientationLockDelegateTest.cpp
index 11b878b..e0ccfd7 100644
--- a/third_party/WebKit/Source/core/html/shadow/MediaControlsOrientationLockDelegateTest.cpp
+++ b/third_party/WebKit/Source/core/html/shadow/MediaControlsOrientationLockDelegateTest.cpp
@@ -170,13 +170,13 @@
 
     Fullscreen::requestFullscreen(video());
     Fullscreen::from(document()).didEnterFullscreen();
-    testing::runPendingTasks();
+    document().serviceScriptedAnimations(WTF::monotonicallyIncreasingTime());
   }
 
   void simulateExitFullscreen() {
     Fullscreen::exitFullscreen(document());
     Fullscreen::from(document()).didExitFullscreen();
-    testing::runPendingTasks();
+    document().serviceScriptedAnimations(WTF::monotonicallyIncreasingTime());
   }
 
   void simulateOrientationLock() {
diff --git a/third_party/WebKit/Source/core/input/EventHandler.cpp b/third_party/WebKit/Source/core/input/EventHandler.cpp
index 920215c..e5213ef 100644
--- a/third_party/WebKit/Source/core/input/EventHandler.cpp
+++ b/third_party/WebKit/Source/core/input/EventHandler.cpp
@@ -1184,12 +1184,7 @@
 Node* EventHandler::updateMouseEventTargetNode(Node* targetNode) {
   Node* newNodeUnderMouse = targetNode;
 
-  // If we're capturing, we always go right to that node.
-  if (EventTarget* mousePointerCapturingNode =
-          m_pointerEventManager->getMouseCapturingNode()) {
-    newNodeUnderMouse = mousePointerCapturingNode->toNode();
-    DCHECK(newNodeUnderMouse);
-  } else if (m_capturingMouseEventsNode) {
+  if (m_capturingMouseEventsNode) {
     newNodeUnderMouse = m_capturingMouseEventsNode.get();
   } else {
     // If the target node is a text node, dispatch on the parent node -
diff --git a/third_party/WebKit/Source/core/input/PointerEventManager.cpp b/third_party/WebKit/Source/core/input/PointerEventManager.cpp
index 8fb5bccc..f4cf8f7f 100644
--- a/third_party/WebKit/Source/core/input/PointerEventManager.cpp
+++ b/third_party/WebKit/Source/core/input/PointerEventManager.cpp
@@ -575,16 +575,16 @@
                          m_pointerEventFactory.createPointerCaptureEvent(
                              pointerEvent, EventTypeNames::lostpointercapture));
   }
-  // Note that If pendingPointerCaptureTarget is null dispatchPointerEvent
-  // automatically does nothing.
-  dispatchPointerEvent(pendingPointerCaptureTarget,
-                       m_pointerEventFactory.createPointerCaptureEvent(
-                           pointerEvent, EventTypeNames::gotpointercapture));
 
-  if (pendingPointerCaptureTarget)
+  if (pendingPointerCaptureTarget) {
+    setNodeUnderPointer(pointerEvent, pendingPointerCaptureTarget);
+    dispatchPointerEvent(pendingPointerCaptureTarget,
+                         m_pointerEventFactory.createPointerCaptureEvent(
+                             pointerEvent, EventTypeNames::gotpointercapture));
     m_pointerCaptureTarget.set(pointerId, pendingPointerCaptureTarget);
-  else
+  } else {
     m_pointerCaptureTarget.remove(pointerId);
+  }
 }
 
 void PointerEventManager::removeTargetFromPointerCapturingMapping(
@@ -698,8 +698,4 @@
   return false;
 }
 
-EventTarget* PointerEventManager::getMouseCapturingNode() {
-  return getCapturingNode(PointerEventFactory::s_mouseId);
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/input/PointerEventManager.h b/third_party/WebKit/Source/core/input/PointerEventManager.h
index ea97e540..f316334 100644
--- a/third_party/WebKit/Source/core/input/PointerEventManager.h
+++ b/third_party/WebKit/Source/core/input/PointerEventManager.h
@@ -76,10 +76,6 @@
   // the last event was sent to the given frame.
   bool isTouchPointerIdActiveOnFrame(int, LocalFrame*) const;
 
-  // TODO(crbug.com/625843): This can be hidden when mouse refactoring in
-  // EventHandler is done.
-  EventTarget* getMouseCapturingNode();
-
   // Returns true if the primary pointerdown corresponding to the given
   // |uniqueTouchEventId| was canceled. Also drops stale ids from
   // |m_touchIdsForCanceledPointerdowns|.
diff --git a/third_party/WebKit/Source/core/layout/LayoutInline.cpp b/third_party/WebKit/Source/core/layout/LayoutInline.cpp
index 7e8f2d7..93cb104 100644
--- a/third_party/WebKit/Source/core/layout/LayoutInline.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutInline.cpp
@@ -402,9 +402,9 @@
   // not its parent. Since the splitting logic expects |this| to be the parent,
   // set |beforeChild| to be the LayoutFullScreen.
   if (Fullscreen* fullscreen = Fullscreen::fromIfExists(document())) {
-    const Element* fullScreenElement = fullscreen->currentFullScreenElement();
-    if (fullScreenElement && beforeChild &&
-        beforeChild->node() == fullScreenElement)
+    const Element* fullscreenElement = fullscreen->fullscreenElement();
+    if (fullscreenElement && beforeChild &&
+        beforeChild->node() == fullscreenElement)
       beforeChild = fullscreen->fullScreenLayoutObject();
   }
 
diff --git a/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp b/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp
index 37ab648..d129904 100644
--- a/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp
+++ b/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp
@@ -170,11 +170,6 @@
       return nullptr;
     fullscreenElement = Fullscreen::fullscreenElementFrom(*contentDocument);
   }
-  // Get the current fullscreen element from the document.
-  // TODO(foolip): When |currentFullScreenElementFrom| is removed, this will
-  // become a no-op and can be removed. https://crbug.com/402421
-  fullscreenElement =
-      Fullscreen::currentFullScreenElementFrom(*contentDocument);
   if (!isHTMLVideoElement(fullscreenElement))
     return nullptr;
   LayoutObject* layoutObject = fullscreenElement->layoutObject();
diff --git a/third_party/WebKit/Source/core/page/ChromeClient.h b/third_party/WebKit/Source/core/page/ChromeClient.h
index 8ffda58e2..4651003 100644
--- a/third_party/WebKit/Source/core/page/ChromeClient.h
+++ b/third_party/WebKit/Source/core/page/ChromeClient.h
@@ -247,7 +247,8 @@
 
   virtual void enterFullscreen(LocalFrame&) {}
   virtual void exitFullscreen(LocalFrame&) {}
-  virtual void fullscreenElementChanged(Element*, Element*) {}
+  virtual void fullscreenElementChanged(Element* fromElement,
+                                        Element* toElement) {}
 
   virtual void clearCompositedSelection(LocalFrame*) {}
   virtual void updateCompositedSelection(LocalFrame*,
diff --git a/third_party/WebKit/Source/core/page/DragController.cpp b/third_party/WebKit/Source/core/page/DragController.cpp
index da3319e..0be7eae 100644
--- a/third_party/WebKit/Source/core/page/DragController.cpp
+++ b/third_party/WebKit/Source/core/page/DragController.cpp
@@ -213,11 +213,7 @@
 
   FrameView* frameView(localRoot.view());
   if (frameView) {
-    DataTransferAccessPolicy policy =
-        (!m_documentUnderMouse ||
-         m_documentUnderMouse->getSecurityOrigin()->isLocal())
-            ? DataTransferReadable
-            : DataTransferTypesReadable;
+    DataTransferAccessPolicy policy = DataTransferTypesReadable;
     DataTransfer* dataTransfer = createDraggingDataTransfer(policy, dragData);
     dataTransfer->setSourceOperation(dragData->draggingSourceOperationMask());
     localRoot.eventHandler().cancelDragAndDrop(createMouseEvent(dragData),
@@ -718,10 +714,7 @@
   if (!localRoot.view())
     return false;
 
-  DataTransferAccessPolicy policy =
-      m_documentUnderMouse->getSecurityOrigin()->isLocal()
-          ? DataTransferReadable
-          : DataTransferTypesReadable;
+  DataTransferAccessPolicy policy = DataTransferTypesReadable;
   DataTransfer* dataTransfer = createDraggingDataTransfer(policy, dragData);
   DragOperation srcOpMask = dragData->draggingSourceOperationMask();
   dataTransfer->setSourceOperation(srcOpMask);
diff --git a/third_party/WebKit/Source/core/paint/ObjectPaintProperties.h b/third_party/WebKit/Source/core/paint/ObjectPaintProperties.h
index a85f4ab..3c30b99c 100644
--- a/third_party/WebKit/Source/core/paint/ObjectPaintProperties.h
+++ b/third_party/WebKit/Source/core/paint/ObjectPaintProperties.h
@@ -20,13 +20,28 @@
 
 namespace blink {
 
-// This class stores property tree related information associated with a
-// LayoutObject.
-// Currently there are two groups of information:
-// 1. The set of property nodes created locally by this LayoutObject.
+// This class stores the paint property nodes associated with a LayoutObject.
+// The object owns each of the property nodes directly set here (e.g, m_cssClip,
+// m_paintOffsetTranslation, etc.) and RefPtrs are only used to harden against
+// use-after-free bugs. These paint properties are built/updated by
+// PaintPropertyTreeBuilder during the PrePaint lifecycle step.
+//
+// There are two groups of information stored on ObjectPaintProperties:
+// 1. The set of property nodes created locally and owned by this LayoutObject.
 // 2. The set of property nodes (inherited, or created locally) and paint offset
 //    that can be used to paint the border box of this LayoutObject (see:
 //    localBorderBoxProperties).
+//
+// [update & clear implementation note] This class has update[property](...) and
+// clear[property]() helper functions for efficiently creating and updating
+// properties. These functions return true if the property tree structure
+// changes (e.g., a node is added or removed), and false otherwise. Property
+// nodes store parent pointers but not child pointers and these return values
+// are important for catching property tree structure changes which require
+// updating descendant's parent pointers. The update functions use a
+// create-or-update pattern of re-using existing properties for efficiency:
+// 1. It avoids extra allocations.
+// 2. It preserves existing child->parent pointers.
 class CORE_EXPORT ObjectPaintProperties {
   WTF_MAKE_NONCOPYABLE(ObjectPaintProperties);
   USING_FAST_MALLOC(ObjectPaintProperties);
@@ -124,6 +139,14 @@
   const PropertyTreeStateWithOffset* localBorderBoxProperties() const {
     return m_localBorderBoxProperties.get();
   }
+
+  // This is the complete set of property nodes and paint offset that can be
+  // used to paint the contents of this object. It is similar to
+  // localBorderBoxProperties but includes properties (e.g., overflow clip,
+  // scroll translation) that apply to contents. This is suitable for paint
+  // invalidation.
+  ObjectPaintProperties::PropertyTreeStateWithOffset contentsProperties() const;
+
   void updateLocalBorderBoxProperties(
       LayoutPoint& paintOffset,
       const TransformPaintPropertyNode* transform,
@@ -144,56 +167,41 @@
   }
   void clearLocalBorderBoxProperties() { m_localBorderBoxProperties = nullptr; }
 
-  // This is the complete set of property nodes and paint offset that can be
-  // used to paint the contents of this object. It is similar to
-  // localBorderBoxProperties but includes properties (e.g., overflow clip,
-  // scroll translation) that apply to contents. This is suitable for paint
-  // invalidation.
-  ObjectPaintProperties::PropertyTreeStateWithOffset contentsProperties() const;
-
-  // True if an existing property was deleted, false otherwise.
+  // The following clear* functions return true if the property tree structure
+  // changes (an existing node was deleted), and false otherwise. See the
+  // class-level comment ("update & clear implementation note") for details
+  // about why this is needed for efficient updates.
   bool clearPaintOffsetTranslation() { return clear(m_paintOffsetTranslation); }
-  // True if an existing property was deleted, false otherwise.
   bool clearTransform() { return clear(m_transform); }
-  // True if an existing property was deleted, false otherwise.
   bool clearEffect() { return clear(m_effect); }
-  // True if an existing property was deleted, false otherwise.
   bool clearCssClip() { return clear(m_cssClip); }
-  // True if an existing property was deleted, false otherwise.
   bool clearCssClipFixedPosition() { return clear(m_cssClipFixedPosition); }
-  // True if an existing property was deleted, false otherwise.
   bool clearInnerBorderRadiusClip() { return clear(m_innerBorderRadiusClip); }
-  // True if an existing property was deleted, false otherwise.
   bool clearOverflowClip() { return clear(m_overflowClip); }
-  // True if an existing property was deleted, false otherwise.
   bool clearPerspective() { return clear(m_perspective); }
-  // True if an existing property was deleted, false otherwise.
   bool clearSvgLocalToBorderBoxTransform() {
     return clear(m_svgLocalToBorderBoxTransform);
   }
-  // True if an existing property was deleted, false otherwise.
   bool clearScrollTranslation() { return clear(m_scrollTranslation); }
-  // True if an existing property was deleted, false otherwise.
   bool clearScrollbarPaintOffset() { return clear(m_scrollbarPaintOffset); }
-  // True if an existing property was deleted, false otherwise.
   bool clearScroll() { return clear(m_scroll); }
 
-  // True if a new property was created, false if an existing one was updated.
+  // The following update* functions return true if the property tree structure
+  // changes (a new node was created), and false otherwise. See the class-level
+  // comment ("update & clear implementation note") for details about why this
+  // is needed for efficient updates.
   template <typename... Args>
   bool updatePaintOffsetTranslation(Args&&... args) {
     return update(m_paintOffsetTranslation, std::forward<Args>(args)...);
   }
-  // True if a new property was created, false if an existing one was updated.
   template <typename... Args>
   bool updateTransform(Args&&... args) {
     return update(m_transform, std::forward<Args>(args)...);
   }
-  // True if a new property was created, false if an existing one was updated.
   template <typename... Args>
   bool updatePerspective(Args&&... args) {
     return update(m_perspective, std::forward<Args>(args)...);
   }
-  // True if a new property was created, false if an existing one was updated.
   template <typename... Args>
   bool updateSvgLocalToBorderBoxTransform(Args&&... args) {
     DCHECK(!scrollTranslation()) << "SVG elements cannot scroll so there "
@@ -201,7 +209,6 @@
                                     "and an SVG local to border box transform.";
     return update(m_svgLocalToBorderBoxTransform, std::forward<Args>(args)...);
   }
-  // True if a new property was created, false if an existing one was updated.
   template <typename... Args>
   bool updateScrollTranslation(Args&&... args) {
     DCHECK(!svgLocalToBorderBoxTransform())
@@ -209,37 +216,30 @@
            "translation and an SVG local to border box transform.";
     return update(m_scrollTranslation, std::forward<Args>(args)...);
   }
-  // True if a new property was created, false if an existing one was updated.
   template <typename... Args>
   bool updateScrollbarPaintOffset(Args&&... args) {
     return update(m_scrollbarPaintOffset, std::forward<Args>(args)...);
   }
-  // True if a new property was created, false if an existing one was updated.
   template <typename... Args>
   bool updateScroll(Args&&... args) {
     return update(m_scroll, std::forward<Args>(args)...);
   }
-  // True if a new property was created, false if an existing one was updated.
   template <typename... Args>
   bool updateEffect(Args&&... args) {
     return update(m_effect, std::forward<Args>(args)...);
   }
-  // True if a new property was created, false if an existing one was updated.
   template <typename... Args>
   bool updateCssClip(Args&&... args) {
     return update(m_cssClip, std::forward<Args>(args)...);
   }
-  // True if a new property was created, false if an existing one was updated.
   template <typename... Args>
   bool updateCssClipFixedPosition(Args&&... args) {
     return update(m_cssClipFixedPosition, std::forward<Args>(args)...);
   }
-  // True if a new property was created, false if an existing one was updated.
   template <typename... Args>
   bool updateInnerBorderRadiusClip(Args&&... args) {
     return update(m_innerBorderRadiusClip, std::forward<Args>(args)...);
   }
-  // True if a new property was created, false if an existing one was updated.
   template <typename... Args>
   bool updateOverflowClip(Args&&... args) {
     return update(m_overflowClip, std::forward<Args>(args)...);
@@ -290,7 +290,9 @@
  private:
   ObjectPaintProperties() {}
 
-  // True if an existing property was deleted, false otherwise.
+  // Return true if the property tree structure changes (an existing node was
+  // deleted), and false otherwise. See the class-level comment ("update & clear
+  // implementation note") for details about why this is needed for efficiency.
   template <typename PaintPropertyNode>
   bool clear(RefPtr<PaintPropertyNode>& field) {
     if (field) {
@@ -300,7 +302,9 @@
     return false;
   }
 
-  // True if a new property was created, false if an existing one was updated.
+  // Return true if the property tree structure changes (a new node was
+  // created), and false otherwise. See the class-level comment ("update & clear
+  // implementation note") for details about why this is needed for efficiency.
   template <typename PaintPropertyNode, typename... Args>
   bool update(RefPtr<PaintPropertyNode>& field, Args&&... args) {
     if (field) {
diff --git a/third_party/WebKit/Source/devtools/BUILD.gn b/third_party/WebKit/Source/devtools/BUILD.gn
index c11fe6b..39f3038 100644
--- a/third_party/WebKit/Source/devtools/BUILD.gn
+++ b/third_party/WebKit/Source/devtools/BUILD.gn
@@ -286,7 +286,6 @@
   "front_end/ui/UIUtils.js",
   "front_end/ui/View.js",
   "front_end/ui/ViewportControl.js",
-  "front_end/ui/StaticViewportControl.js",
   "front_end/ui/Widget.js",
   "front_end/ui/ZoomManager.js",
   "front_end/ui/treeoutline.js",
@@ -417,6 +416,7 @@
   "front_end/console/ConsolePrompt.js",
   "front_end/console/ConsoleView.js",
   "front_end/console/ConsoleViewMessage.js",
+  "front_end/console/ConsoleViewport.js",
 ]
 devtools_css_tracker_js_files = [
   "front_end/css_tracker/cssTrackerView.css",
diff --git a/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js b/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js
index 326d8305..cb7b1fe 100644
--- a/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js
+++ b/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js
@@ -29,7 +29,7 @@
 /**
  * @implements {UI.Searchable}
  * @implements {SDK.TargetManager.Observer}
- * @implements {UI.ViewportControl.Provider}
+ * @implements {Console.ConsoleViewportProvider}
  * @unrestricted
  */
 Console.ConsoleView = class extends UI.VBox {
@@ -80,7 +80,7 @@
     this._filterBar.show(this._contentsElement);
     this._filter.addFilters(this._filterBar);
 
-    this._viewport = new UI.ViewportControl(this);
+    this._viewport = new Console.ConsoleViewport(this);
     this._viewport.setStickToBottom(true);
     this._viewport.contentElement().classList.add('console-group', 'console-group-messages');
     this._contentsElement.appendChild(this._viewport.element);
@@ -241,7 +241,7 @@
   /**
    * @override
    * @param {number} index
-   * @return {?UI.ViewportElement}
+   * @return {?Console.ConsoleViewportElement}
    */
   itemElement(index) {
     return this._visibleViewMessages[index];
diff --git a/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js b/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js
index e2780ee..884af2c 100644
--- a/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js
+++ b/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js
@@ -28,7 +28,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 /**
- * @implements {UI.ViewportElement}
+ * @implements {Console.ConsoleViewportElement}
  * @unrestricted
  */
 Console.ConsoleViewMessage = class {
diff --git a/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewport.js b/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewport.js
new file mode 100644
index 0000000..3388cd7
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewport.js
@@ -0,0 +1,627 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @unrestricted
+ */
+Console.ConsoleViewport = class {
+  /**
+   * @param {!Console.ConsoleViewportProvider} provider
+   */
+  constructor(provider) {
+    this.element = createElement('div');
+    this.element.style.overflow = 'auto';
+    this._topGapElement = this.element.createChild('div');
+    this._topGapElement.style.height = '0px';
+    this._topGapElement.style.color = 'transparent';
+    this._contentElement = this.element.createChild('div');
+    this._bottomGapElement = this.element.createChild('div');
+    this._bottomGapElement.style.height = '0px';
+    this._bottomGapElement.style.color = 'transparent';
+
+    // Text content needed for range intersection checks in _updateSelectionModel.
+    // Use Unicode ZERO WIDTH NO-BREAK SPACE, which avoids contributing any height to the element's layout overflow.
+    this._topGapElement.textContent = '\uFEFF';
+    this._bottomGapElement.textContent = '\uFEFF';
+
+    this._provider = provider;
+    this.element.addEventListener('scroll', this._onScroll.bind(this), false);
+    this.element.addEventListener('copy', this._onCopy.bind(this), false);
+    this.element.addEventListener('dragstart', this._onDragStart.bind(this), false);
+
+    this._firstActiveIndex = 0;
+    this._lastActiveIndex = -1;
+    this._renderedItems = [];
+    this._anchorSelection = null;
+    this._headSelection = null;
+    this._itemCount = 0;
+
+    // Listen for any changes to descendants and trigger a refresh. This ensures
+    // that items updated asynchronously will not break stick-to-bottom behavior
+    // if they change the scroll height.
+    this._observer = new MutationObserver(this.refresh.bind(this));
+    this._observerConfig = {childList: true, subtree: true};
+  }
+
+  /**
+   * @return {boolean}
+   */
+  stickToBottom() {
+    return this._stickToBottom;
+  }
+
+  /**
+   * @param {boolean} value
+   */
+  setStickToBottom(value) {
+    this._stickToBottom = value;
+    if (this._stickToBottom)
+      this._observer.observe(this._contentElement, this._observerConfig);
+    else
+      this._observer.disconnect();
+  }
+
+  /**
+   * @param {!Event} event
+   */
+  _onCopy(event) {
+    var text = this._selectedText();
+    if (!text)
+      return;
+    event.preventDefault();
+    event.clipboardData.setData('text/plain', text);
+  }
+
+  /**
+   * @param {!Event} event
+   */
+  _onDragStart(event) {
+    var text = this._selectedText();
+    if (!text)
+      return false;
+    event.dataTransfer.clearData();
+    event.dataTransfer.setData('text/plain', text);
+    event.dataTransfer.effectAllowed = 'copy';
+    return true;
+  }
+
+  /**
+   * @return {!Element}
+   */
+  contentElement() {
+    return this._contentElement;
+  }
+
+  invalidate() {
+    delete this._cumulativeHeights;
+    delete this._cachedProviderElements;
+    this._itemCount = this._provider.itemCount();
+    this.refresh();
+  }
+
+  /**
+   * @param {number} index
+   * @return {?Console.ConsoleViewportElement}
+   */
+  _providerElement(index) {
+    if (!this._cachedProviderElements)
+      this._cachedProviderElements = new Array(this._itemCount);
+    var element = this._cachedProviderElements[index];
+    if (!element) {
+      element = this._provider.itemElement(index);
+      this._cachedProviderElements[index] = element;
+    }
+    return element;
+  }
+
+  _rebuildCumulativeHeightsIfNeeded() {
+    if (this._cumulativeHeights)
+      return;
+    if (!this._itemCount)
+      return;
+    var firstActiveIndex = this._firstActiveIndex;
+    var lastActiveIndex = this._lastActiveIndex;
+    var height = 0;
+    this._cumulativeHeights = new Int32Array(this._itemCount);
+    for (var i = 0; i < this._itemCount; ++i) {
+      if (firstActiveIndex <= i && i <= lastActiveIndex)
+        height += this._renderedItems[i - firstActiveIndex].element().offsetHeight;
+      else
+        height += this._provider.fastHeight(i);
+      this._cumulativeHeights[i] = height;
+    }
+  }
+
+  /**
+   * @param {number} index
+   * @return {number}
+   */
+  _cachedItemHeight(index) {
+    return index === 0 ? this._cumulativeHeights[0] :
+                         this._cumulativeHeights[index] - this._cumulativeHeights[index - 1];
+  }
+
+  /**
+   * @param {?Selection} selection
+   * @suppressGlobalPropertiesCheck
+   */
+  _isSelectionBackwards(selection) {
+    if (!selection || !selection.rangeCount)
+      return false;
+    var range = document.createRange();
+    range.setStart(selection.anchorNode, selection.anchorOffset);
+    range.setEnd(selection.focusNode, selection.focusOffset);
+    return range.collapsed;
+  }
+
+  /**
+   * @param {number} itemIndex
+   * @param {!Node} node
+   * @param {number} offset
+   * @return {!{item: number, node: !Node, offset: number}}
+   */
+  _createSelectionModel(itemIndex, node, offset) {
+    return {item: itemIndex, node: node, offset: offset};
+  }
+
+  /**
+   * @param {?Selection} selection
+   */
+  _updateSelectionModel(selection) {
+    var range = selection && selection.rangeCount ? selection.getRangeAt(0) : null;
+    if (!range || selection.isCollapsed || !this.element.hasSelection()) {
+      this._headSelection = null;
+      this._anchorSelection = null;
+      return false;
+    }
+
+    var firstSelected = Number.MAX_VALUE;
+    var lastSelected = -1;
+
+    var hasVisibleSelection = false;
+    for (var i = 0; i < this._renderedItems.length; ++i) {
+      if (range.intersectsNode(this._renderedItems[i].element())) {
+        var index = i + this._firstActiveIndex;
+        firstSelected = Math.min(firstSelected, index);
+        lastSelected = Math.max(lastSelected, index);
+        hasVisibleSelection = true;
+      }
+    }
+    if (hasVisibleSelection) {
+      firstSelected =
+          this._createSelectionModel(firstSelected, /** @type {!Node} */ (range.startContainer), range.startOffset);
+      lastSelected =
+          this._createSelectionModel(lastSelected, /** @type {!Node} */ (range.endContainer), range.endOffset);
+    }
+    var topOverlap = range.intersectsNode(this._topGapElement) && this._topGapElement._active;
+    var bottomOverlap = range.intersectsNode(this._bottomGapElement) && this._bottomGapElement._active;
+    if (!topOverlap && !bottomOverlap && !hasVisibleSelection) {
+      this._headSelection = null;
+      this._anchorSelection = null;
+      return false;
+    }
+
+    if (!this._anchorSelection || !this._headSelection) {
+      this._anchorSelection = this._createSelectionModel(0, this.element, 0);
+      this._headSelection = this._createSelectionModel(this._itemCount - 1, this.element, this.element.children.length);
+      this._selectionIsBackward = false;
+    }
+
+    var isBackward = this._isSelectionBackwards(selection);
+    var startSelection = this._selectionIsBackward ? this._headSelection : this._anchorSelection;
+    var endSelection = this._selectionIsBackward ? this._anchorSelection : this._headSelection;
+    if (topOverlap && bottomOverlap && hasVisibleSelection) {
+      firstSelected = firstSelected.item < startSelection.item ? firstSelected : startSelection;
+      lastSelected = lastSelected.item > endSelection.item ? lastSelected : endSelection;
+    } else if (!hasVisibleSelection) {
+      firstSelected = startSelection;
+      lastSelected = endSelection;
+    } else if (topOverlap) {
+      firstSelected = isBackward ? this._headSelection : this._anchorSelection;
+    } else if (bottomOverlap) {
+      lastSelected = isBackward ? this._anchorSelection : this._headSelection;
+    }
+
+    if (isBackward) {
+      this._anchorSelection = lastSelected;
+      this._headSelection = firstSelected;
+    } else {
+      this._anchorSelection = firstSelected;
+      this._headSelection = lastSelected;
+    }
+    this._selectionIsBackward = isBackward;
+    return true;
+  }
+
+  /**
+   * @param {?Selection} selection
+   */
+  _restoreSelection(selection) {
+    var anchorElement = null;
+    var anchorOffset;
+    if (this._firstActiveIndex <= this._anchorSelection.item && this._anchorSelection.item <= this._lastActiveIndex) {
+      anchorElement = this._anchorSelection.node;
+      anchorOffset = this._anchorSelection.offset;
+    } else {
+      if (this._anchorSelection.item < this._firstActiveIndex)
+        anchorElement = this._topGapElement;
+      else if (this._anchorSelection.item > this._lastActiveIndex)
+        anchorElement = this._bottomGapElement;
+      anchorOffset = this._selectionIsBackward ? 1 : 0;
+    }
+
+    var headElement = null;
+    var headOffset;
+    if (this._firstActiveIndex <= this._headSelection.item && this._headSelection.item <= this._lastActiveIndex) {
+      headElement = this._headSelection.node;
+      headOffset = this._headSelection.offset;
+    } else {
+      if (this._headSelection.item < this._firstActiveIndex)
+        headElement = this._topGapElement;
+      else if (this._headSelection.item > this._lastActiveIndex)
+        headElement = this._bottomGapElement;
+      headOffset = this._selectionIsBackward ? 0 : 1;
+    }
+
+    selection.setBaseAndExtent(anchorElement, anchorOffset, headElement, headOffset);
+  }
+
+  refresh() {
+    this._observer.disconnect();
+    this._innerRefresh();
+    if (this._stickToBottom)
+      this._observer.observe(this._contentElement, this._observerConfig);
+  }
+
+  _innerRefresh() {
+    if (!this._visibleHeight())
+      return;  // Do nothing for invisible controls.
+
+    if (!this._itemCount) {
+      for (var i = 0; i < this._renderedItems.length; ++i)
+        this._renderedItems[i].willHide();
+      this._renderedItems = [];
+      this._contentElement.removeChildren();
+      this._topGapElement.style.height = '0px';
+      this._bottomGapElement.style.height = '0px';
+      this._firstActiveIndex = -1;
+      this._lastActiveIndex = -1;
+      return;
+    }
+
+    var selection = this.element.getComponentSelection();
+    var shouldRestoreSelection = this._updateSelectionModel(selection);
+
+    var visibleFrom = this.element.scrollTop;
+    var visibleHeight = this._visibleHeight();
+    var isInvalidating = !this._cumulativeHeights;
+
+    for (var i = 0; i < this._renderedItems.length; ++i) {
+      // Tolerate 1-pixel error due to double-to-integer rounding errors.
+      if (this._cumulativeHeights &&
+          Math.abs(this._cachedItemHeight(this._firstActiveIndex + i) - this._renderedItems[i].element().offsetHeight) >
+              1)
+        delete this._cumulativeHeights;
+    }
+    this._rebuildCumulativeHeightsIfNeeded();
+    var oldFirstActiveIndex = this._firstActiveIndex;
+    var oldLastActiveIndex = this._lastActiveIndex;
+    var activeHeight = visibleHeight * 2;
+    // When the viewport is scrolled to the bottom, using the cumulative heights estimate is not
+    // precise enough to determine next visible indices. This stickToBottom check avoids extra
+    // calls to refresh in those cases.
+    if (this._stickToBottom) {
+      this._firstActiveIndex =
+          Math.max(this._itemCount - Math.ceil(activeHeight / this._provider.minimumRowHeight()), 0);
+      this._lastActiveIndex = this._itemCount - 1;
+    } else {
+      this._firstActiveIndex = Math.max(
+          Array.prototype.lowerBound.call(
+              this._cumulativeHeights, visibleFrom + 1 - (activeHeight - visibleHeight) / 2),
+          0);
+      // Proactively render more rows in case some of them will be collapsed without triggering refresh. @see crbug.com/390169
+      this._lastActiveIndex = this._firstActiveIndex + Math.ceil(activeHeight / this._provider.minimumRowHeight()) - 1;
+      this._lastActiveIndex = Math.min(this._lastActiveIndex, this._itemCount - 1);
+    }
+
+    var topGapHeight = this._cumulativeHeights[this._firstActiveIndex - 1] || 0;
+    var bottomGapHeight =
+        this._cumulativeHeights[this._cumulativeHeights.length - 1] - this._cumulativeHeights[this._lastActiveIndex];
+
+    /**
+     * @this {Console.ConsoleViewport}
+     */
+    function prepare() {
+      this._topGapElement.style.height = topGapHeight + 'px';
+      this._bottomGapElement.style.height = bottomGapHeight + 'px';
+      this._topGapElement._active = !!topGapHeight;
+      this._bottomGapElement._active = !!bottomGapHeight;
+      this._contentElement.style.setProperty('height', '10000000px');
+    }
+
+    if (isInvalidating)
+      this._fullViewportUpdate(prepare.bind(this));
+    else
+      this._partialViewportUpdate(oldFirstActiveIndex, oldLastActiveIndex, prepare.bind(this));
+    this._contentElement.style.removeProperty('height');
+    // Should be the last call in the method as it might force layout.
+    if (shouldRestoreSelection)
+      this._restoreSelection(selection);
+    if (this._stickToBottom)
+      this.element.scrollTop = 10000000;
+  }
+
+  /**
+   * @param {function()} prepare
+   */
+  _fullViewportUpdate(prepare) {
+    for (var i = 0; i < this._renderedItems.length; ++i)
+      this._renderedItems[i].willHide();
+    prepare();
+    this._renderedItems = [];
+    this._contentElement.removeChildren();
+    for (var i = this._firstActiveIndex; i <= this._lastActiveIndex; ++i) {
+      var viewportElement = this._providerElement(i);
+      this._contentElement.appendChild(viewportElement.element());
+      this._renderedItems.push(viewportElement);
+    }
+    for (var i = 0; i < this._renderedItems.length; ++i)
+      this._renderedItems[i].wasShown();
+  }
+
+  /**
+   * @param {number} oldFirstActiveIndex
+   * @param {number} oldLastActiveIndex
+   * @param {function()} prepare
+   */
+  _partialViewportUpdate(oldFirstActiveIndex, oldLastActiveIndex, prepare) {
+    var willBeHidden = [];
+    for (var i = 0; i < this._renderedItems.length; ++i) {
+      var index = oldFirstActiveIndex + i;
+      if (index < this._firstActiveIndex || this._lastActiveIndex < index)
+        willBeHidden.push(this._renderedItems[i]);
+    }
+    for (var i = 0; i < willBeHidden.length; ++i)
+      willBeHidden[i].willHide();
+    prepare();
+    for (var i = 0; i < willBeHidden.length; ++i)
+      willBeHidden[i].element().remove();
+
+    this._renderedItems = [];
+    var anchor = this._contentElement.firstChild;
+    var wasShown = [];
+    for (var i = this._firstActiveIndex; i <= this._lastActiveIndex; ++i) {
+      var viewportElement = this._providerElement(i);
+      var element = viewportElement.element();
+      if (element !== anchor) {
+        this._contentElement.insertBefore(element, anchor);
+        wasShown.push(viewportElement);
+      } else {
+        anchor = anchor.nextSibling;
+      }
+      this._renderedItems.push(viewportElement);
+    }
+    for (var i = 0; i < wasShown.length; ++i)
+      wasShown[i].wasShown();
+  }
+
+  /**
+   * @return {?string}
+   */
+  _selectedText() {
+    this._updateSelectionModel(this.element.getComponentSelection());
+    if (!this._headSelection || !this._anchorSelection)
+      return null;
+
+    var startSelection = null;
+    var endSelection = null;
+    if (this._selectionIsBackward) {
+      startSelection = this._headSelection;
+      endSelection = this._anchorSelection;
+    } else {
+      startSelection = this._anchorSelection;
+      endSelection = this._headSelection;
+    }
+
+    var textLines = [];
+    for (var i = startSelection.item; i <= endSelection.item; ++i)
+      textLines.push(this._providerElement(i).element().deepTextContent());
+
+    var endSelectionElement = this._providerElement(endSelection.item).element();
+    if (endSelection.node && endSelection.node.isSelfOrDescendant(endSelectionElement)) {
+      var itemTextOffset = this._textOffsetInNode(endSelectionElement, endSelection.node, endSelection.offset);
+      textLines[textLines.length - 1] = textLines.peekLast().substring(0, itemTextOffset);
+    }
+
+    var startSelectionElement = this._providerElement(startSelection.item).element();
+    if (startSelection.node && startSelection.node.isSelfOrDescendant(startSelectionElement)) {
+      var itemTextOffset = this._textOffsetInNode(startSelectionElement, startSelection.node, startSelection.offset);
+      textLines[0] = textLines[0].substring(itemTextOffset);
+    }
+
+    return textLines.join('\n');
+  }
+
+  /**
+   * @param {!Element} itemElement
+   * @param {!Node} container
+   * @param {number} offset
+   * @return {number}
+   */
+  _textOffsetInNode(itemElement, container, offset) {
+    var chars = 0;
+    var node = itemElement;
+    while ((node = node.traverseNextTextNode()) && !node.isSelfOrDescendant(container))
+      chars += node.textContent.length;
+    return chars + offset;
+  }
+
+  /**
+   * @param {!Event} event
+   */
+  _onScroll(event) {
+    this.refresh();
+  }
+
+  /**
+   * @return {number}
+   */
+  firstVisibleIndex() {
+    var firstVisibleIndex =
+        Math.max(Array.prototype.lowerBound.call(this._cumulativeHeights, this.element.scrollTop + 1), 0);
+    return Math.max(firstVisibleIndex, this._firstActiveIndex);
+  }
+
+  /**
+   * @return {number}
+   */
+  lastVisibleIndex() {
+    var lastVisibleIndex;
+    if (this._stickToBottom) {
+      lastVisibleIndex = this._itemCount - 1;
+    } else {
+      lastVisibleIndex =
+          this.firstVisibleIndex() + Math.ceil(this._visibleHeight() / this._provider.minimumRowHeight()) - 1;
+    }
+    return Math.min(lastVisibleIndex, this._lastActiveIndex);
+  }
+
+  /**
+   * @return {?Element}
+   */
+  renderedElementAt(index) {
+    if (index < this._firstActiveIndex)
+      return null;
+    if (index > this._lastActiveIndex)
+      return null;
+    return this._renderedItems[index - this._firstActiveIndex].element();
+  }
+
+  /**
+   * @param {number} index
+   * @param {boolean=} makeLast
+   */
+  scrollItemIntoView(index, makeLast) {
+    var firstVisibleIndex = this.firstVisibleIndex();
+    var lastVisibleIndex = this.lastVisibleIndex();
+    if (index > firstVisibleIndex && index < lastVisibleIndex)
+      return;
+    if (makeLast)
+      this.forceScrollItemToBeLast(index);
+    else if (index <= firstVisibleIndex)
+      this.forceScrollItemToBeFirst(index);
+    else if (index >= lastVisibleIndex)
+      this.forceScrollItemToBeLast(index);
+  }
+
+  /**
+   * @param {number} index
+   */
+  forceScrollItemToBeFirst(index) {
+    this.setStickToBottom(false);
+    this._rebuildCumulativeHeightsIfNeeded();
+    this.element.scrollTop = index > 0 ? this._cumulativeHeights[index - 1] : 0;
+    if (this.element.isScrolledToBottom())
+      this.setStickToBottom(true);
+    this.refresh();
+  }
+
+  /**
+   * @param {number} index
+   */
+  forceScrollItemToBeLast(index) {
+    this.setStickToBottom(false);
+    this._rebuildCumulativeHeightsIfNeeded();
+    this.element.scrollTop = this._cumulativeHeights[index] - this._visibleHeight();
+    if (this.element.isScrolledToBottom())
+      this.setStickToBottom(true);
+    this.refresh();
+  }
+
+  /**
+   * @return {number}
+   */
+  _visibleHeight() {
+    // Use offsetHeight instead of clientHeight to avoid being affected by horizontal scroll.
+    return this.element.offsetHeight;
+  }
+};
+
+/**
+ * @interface
+ */
+Console.ConsoleViewportProvider = function() {};
+
+Console.ConsoleViewportProvider.prototype = {
+  /**
+   * @param {number} index
+   * @return {number}
+   */
+  fastHeight(index) {
+    return 0;
+  },
+
+  /**
+   * @return {number}
+   */
+  itemCount() {
+    return 0;
+  },
+
+  /**
+   * @return {number}
+   */
+  minimumRowHeight() {
+    return 0;
+  },
+
+  /**
+   * @param {number} index
+   * @return {?Console.ConsoleViewportElement}
+   */
+  itemElement(index) {
+    return null;
+  }
+};
+
+/**
+ * @interface
+ */
+Console.ConsoleViewportElement = function() {};
+Console.ConsoleViewportElement.prototype = {
+  willHide() {},
+
+  wasShown() {},
+
+  /**
+   * @return {!Element}
+   */
+  element() {},
+};
diff --git a/third_party/WebKit/Source/devtools/front_end/console/module.json b/third_party/WebKit/Source/devtools/front_end/console/module.json
index deac0c6..bce912f 100644
--- a/third_party/WebKit/Source/devtools/front_end/console/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/console/module.json
@@ -119,6 +119,7 @@
     ],
     "scripts": [
         "ConsoleContextSelector.js",
+        "ConsoleViewport.js",
         "ConsoleViewMessage.js",
         "ConsolePrompt.js",
         "ConsoleView.js",
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js b/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
index d8fe76b..89508e0f 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
@@ -91,7 +91,6 @@
       var weights = {};
       var types = Sources.NavigatorView.Types;
       weights[types.Root] = 1;
-      weights[types.Category] = 1;
       weights[types.Domain] = 10;
       weights[types.FileSystemFolder] = 1;
       weights[types.NetworkFolder] = 1;
@@ -822,7 +821,6 @@
 };
 
 Sources.NavigatorView.Types = {
-  Category: 'category',
   Domain: 'domain',
   File: 'file',
   FileSystem: 'fs',
@@ -834,7 +832,6 @@
   Worker: 'worker'
 };
 
-
 /**
  * @unrestricted
  */
@@ -851,9 +848,16 @@
     this._nodeType = type;
     this.title = title;
     this.tooltip = title;
-    this.createIcon();
     this._navigatorView = navigatorView;
     this._hoverCallback = hoverCallback;
+    var iconType = 'largeicon-navigator-folder';
+    if (type === Sources.NavigatorView.Types.Domain)
+      iconType = 'largeicon-navigator-domain';
+    else if (type === Sources.NavigatorView.Types.Frame)
+      iconType = 'largeicon-navigator-frame';
+    else if (type === Sources.NavigatorView.Types.Worker)
+      iconType = 'largeicon-navigator-worker';
+    this.setLeadingIcons([UI.Icon.create(iconType, 'icon')]);
   }
 
   /**
@@ -937,7 +941,10 @@
     this.listItemElement.classList.add(
         'navigator-' + uiSourceCode.contentType().name() + '-tree-item', 'navigator-file-tree-item');
     this.tooltip = uiSourceCode.url();
-    this.createIcon();
+    var iconType = 'largeicon-navigator-file';
+    if (uiSourceCode.contentType() === Common.resourceTypes.Snippet)
+      iconType = 'largeicon-navigator-snippet';
+    this.setLeadingIcons([UI.Icon.create(iconType, 'icon')]);
 
     this._navigatorView = navigatorView;
     this._uiSourceCode = uiSourceCode;
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/navigatorTree.css b/third_party/WebKit/Source/devtools/front_end/sources/navigatorTree.css
index e7a45e3b..2dc4815 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/navigatorTree.css
+++ b/third_party/WebKit/Source/devtools/front_end/sources/navigatorTree.css
@@ -28,21 +28,10 @@
  */
 
 .icon {
-    -webkit-mask-image: url(Images/toolbarButtonGlyphs.png);
-    -webkit-mask-size: 352px 168px;
-    width: 32px;
-    height: 24px;
-    margin: -3px -3px -3px -7px;
+    margin: -3px -7px -3px -7px;
 }
 
-@media (-webkit-min-device-pixel-ratio: 1.1) {
-.icon {
-    -webkit-mask-image: url(Images/toolbarButtonGlyphs_2x.png);
-}
-} /* media */
-
 .navigator-file-tree-item .icon {
-    -webkit-mask-position: -224px -72px;
     background: linear-gradient(45deg, hsl(0, 0%, 50%), hsl(0, 0%, 70%));
 }
 
@@ -52,14 +41,6 @@
     opacity: 0.5;
 }
 
-:focus .navigator-file-tree-item.selected .icon {
-    background: white !important;
-}
-
-:focus .navigator-folder-tree-item.selected .icon {
-    background: white !important;
-}
-
 .tree-outline li {
     min-height: 20px;
 }
@@ -70,18 +51,9 @@
 }
 
 .navigator-folder-tree-item .icon {
-    -webkit-mask-position: -64px -120px;
     background-color: #555;
 }
 
-.navigator-domain-tree-item .icon  {
-    -webkit-mask-position: -160px -144px;
-}
-
-.navigator-frame-tree-item .icon {
-    -webkit-mask-position: -256px -144px;
-}
-
 .navigator-sm-folder-tree-item .icon,
 .navigator-fs-tree-item .icon,
 .navigator-fs-folder-tree-item .icon {
@@ -92,20 +64,12 @@
     background: linear-gradient(45deg, hsl(210, 82%, 65%), hsl(210, 82%, 80%));
 }
 
-.navigator-worker-tree-item .icon {
-    -webkit-mask-position: -320px -144px;
-}
-
 .navigator-sm-script-tree-item .icon,
 .navigator-script-tree-item .icon,
 .navigator-snippet-tree-item .icon {
     background: linear-gradient(45deg, hsl(48, 70%, 50%), hsl(48, 70%, 70%));
 }
 
-.navigator-snippet-tree-item .icon {
-    -webkit-mask-position: -224px -96px;
-}
-
 .navigator-sm-stylesheet-tree-item .icon,
 .navigator-stylesheet-tree-item .icon {
     background: linear-gradient(45deg, hsl(256, 50%, 50%), hsl(256, 50%, 70%));
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/Icon.js b/third_party/WebKit/Source/devtools/front_end/ui/Icon.js
index 45cd812..f7789b72 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/Icon.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/Icon.js
@@ -207,4 +207,10 @@
     isMask: true,
     transform: 'translate(4px, 1px) rotate(-90deg)'
   },
+  'largeicon-navigator-file': {x: -224, y: -72, width: 32, height: 24, spritesheet: 'largeicons', isMask: true},
+  'largeicon-navigator-folder': {x: -64, y: -120, width: 32, height: 24, spritesheet: 'largeicons', isMask: true},
+  'largeicon-navigator-domain': {x: -160, y: -144, width: 32, height: 24, spritesheet: 'largeicons', isMask: true},
+  'largeicon-navigator-frame': {x: -256, y: -144, width: 32, height: 24, spritesheet: 'largeicons', isMask: true},
+  'largeicon-navigator-worker': {x: -320, y: -144, width: 32, height: 24, spritesheet: 'largeicons', isMask: true},
+  'largeicon-navigator-snippet': {x: -224, y: -96, width: 32, height: 24, spritesheet: 'largeicons', isMask: true},
 };
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/StaticViewportControl.js b/third_party/WebKit/Source/devtools/front_end/ui/StaticViewportControl.js
deleted file mode 100644
index c0125520..0000000
--- a/third_party/WebKit/Source/devtools/front_end/ui/StaticViewportControl.js
+++ /dev/null
@@ -1,169 +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.
-/**
- * @unrestricted
- */
-UI.StaticViewportControl = class {
-  /**
-   * @param {!UI.StaticViewportControl.Provider} provider
-   */
-  constructor(provider) {
-    this.element = createElement('div');
-    this.element.style.overflow = 'auto';
-    this._innerElement = this.element.createChild('div');
-    this._innerElement.style.height = '0px';
-    this._innerElement.style.position = 'relative';
-    this._innerElement.style.overflow = 'hidden';
-
-    this._provider = provider;
-    this.element.addEventListener('scroll', this._update.bind(this), false);
-    this._itemCount = 0;
-    this._indexSymbol = Symbol('UI.StaticViewportControl._indexSymbol');
-  }
-
-  refresh() {
-    this._itemCount = this._provider.itemCount();
-    this._innerElement.removeChildren();
-
-    var height = 0;
-    this._cumulativeHeights = new Int32Array(this._itemCount);
-    for (var i = 0; i < this._itemCount; ++i) {
-      height += this._provider.fastItemHeight(i);
-      this._cumulativeHeights[i] = height;
-    }
-    this._innerElement.style.height = height + 'px';
-
-    this._update();
-  }
-
-  _update() {
-    if (!this._cumulativeHeights) {
-      this.refresh();
-      return;
-    }
-
-    var visibleHeight = this._visibleHeight();
-    var visibleFrom = this.element.scrollTop;
-    var activeHeight = visibleHeight * 2;
-    var firstActiveIndex = Math.max(
-        Array.prototype.lowerBound.call(this._cumulativeHeights, visibleFrom + 1 - (activeHeight - visibleHeight) / 2),
-        0);
-    var lastActiveIndex = Math.min(
-        Array.prototype.lowerBound.call(
-            this._cumulativeHeights, visibleFrom + visibleHeight + (activeHeight - visibleHeight) / 2),
-        this._itemCount - 1);
-
-    var children = this._innerElement.children;
-    for (var i = children.length - 1; i >= 0; --i) {
-      var element = children[i];
-      if (element[this._indexSymbol] < firstActiveIndex || element[this._indexSymbol] > lastActiveIndex)
-        element.remove();
-    }
-
-    for (var i = firstActiveIndex; i <= lastActiveIndex; ++i)
-      this._insertElement(i);
-  }
-
-  /**
-   * @param {number} index
-   */
-  _insertElement(index) {
-    var element = this._provider.itemElement(index);
-    if (!element || element.parentElement === this._innerElement)
-      return;
-
-    element.style.position = 'absolute';
-    element.style.top = (this._cumulativeHeights[index - 1] || 0) + 'px';
-    element.style.left = '0';
-    element.style.right = '0';
-    element[this._indexSymbol] = index;
-    this._innerElement.appendChild(element);
-  }
-
-  /**
-   * @return {number}
-   */
-  firstVisibleIndex() {
-    return Math.max(Array.prototype.lowerBound.call(this._cumulativeHeights, this.element.scrollTop + 1), 0);
-  }
-
-  /**
-   * @return {number}
-   */
-  lastVisibleIndex() {
-    return Math.min(
-        Array.prototype.lowerBound.call(this._cumulativeHeights, this.element.scrollTop + this._visibleHeight()),
-        this._itemCount);
-  }
-
-  /**
-   * @param {number} index
-   * @param {boolean=} makeLast
-   */
-  scrollItemIntoView(index, makeLast) {
-    var firstVisibleIndex = this.firstVisibleIndex();
-    var lastVisibleIndex = this.lastVisibleIndex();
-    if (index > firstVisibleIndex && index < lastVisibleIndex)
-      return;
-    if (makeLast)
-      this.forceScrollItemToBeLast(index);
-    else if (index <= firstVisibleIndex)
-      this.forceScrollItemToBeFirst(index);
-    else if (index >= lastVisibleIndex)
-      this.forceScrollItemToBeLast(index);
-  }
-
-  /**
-   * @param {number} index
-   */
-  forceScrollItemToBeFirst(index) {
-    this.element.scrollTop = index > 0 ? this._cumulativeHeights[index - 1] : 0;
-    this._update();
-  }
-
-  /**
-   * @param {number} index
-   */
-  forceScrollItemToBeLast(index) {
-    this.element.scrollTop = this._cumulativeHeights[index] - this._visibleHeight();
-    this._update();
-  }
-
-  /**
-   * @return {number}
-   */
-  _visibleHeight() {
-    return this.element.offsetHeight;
-  }
-};
-
-/**
- * @interface
- */
-UI.StaticViewportControl.Provider = function() {};
-
-UI.StaticViewportControl.Provider.prototype = {
-  /**
-   * @param {number} index
-   * @return {number}
-   */
-  fastItemHeight(index) {
-    return 0;
-  },
-
-  /**
-   * @return {number}
-   */
-  itemCount() {
-    return 0;
-  },
-
-  /**
-   * @param {number} index
-   * @return {?Element}
-   */
-  itemElement(index) {
-    return null;
-  }
-};
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/SuggestBox.js b/third_party/WebKit/Source/devtools/front_end/ui/SuggestBox.js
index 98960a8..1b20de2 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/SuggestBox.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/SuggestBox.js
@@ -46,7 +46,7 @@
 };
 
 /**
- * @implements {UI.StaticViewportControl.Provider}
+ * @implements {UI.ViewportControl.Provider}
  * @unrestricted
  */
 UI.SuggestBox = class {
@@ -63,7 +63,7 @@
     this._maxItemsHeight = maxItemsHeight;
     this._maybeHideBound = this._maybeHide.bind(this);
     this._container = createElementWithClass('div', 'suggest-box-container');
-    this._viewport = new UI.StaticViewportControl(this);
+    this._viewport = new UI.ViewportControl(this);
     this._element = this._viewport.element;
     this._element.classList.add('suggest-box');
     this._container.appendChild(this._element);
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/ViewportControl.js b/third_party/WebKit/Source/devtools/front_end/ui/ViewportControl.js
index b3f40d4..dbd3600 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/ViewportControl.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/ViewportControl.js
@@ -1,33 +1,6 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
+// 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.
 /**
  * @unrestricted
  */
@@ -38,490 +11,90 @@
   constructor(provider) {
     this.element = createElement('div');
     this.element.style.overflow = 'auto';
-    this._topGapElement = this.element.createChild('div');
-    this._topGapElement.style.height = '0px';
-    this._topGapElement.style.color = 'transparent';
-    this._contentElement = this.element.createChild('div');
-    this._bottomGapElement = this.element.createChild('div');
-    this._bottomGapElement.style.height = '0px';
-    this._bottomGapElement.style.color = 'transparent';
-
-    // Text content needed for range intersection checks in _updateSelectionModel.
-    // Use Unicode ZERO WIDTH NO-BREAK SPACE, which avoids contributing any height to the element's layout overflow.
-    this._topGapElement.textContent = '\uFEFF';
-    this._bottomGapElement.textContent = '\uFEFF';
+    this._innerElement = this.element.createChild('div');
+    this._innerElement.style.height = '0px';
+    this._innerElement.style.position = 'relative';
+    this._innerElement.style.overflow = 'hidden';
 
     this._provider = provider;
-    this.element.addEventListener('scroll', this._onScroll.bind(this), false);
-    this.element.addEventListener('copy', this._onCopy.bind(this), false);
-    this.element.addEventListener('dragstart', this._onDragStart.bind(this), false);
-
-    this._firstActiveIndex = 0;
-    this._lastActiveIndex = -1;
-    this._renderedItems = [];
-    this._anchorSelection = null;
-    this._headSelection = null;
+    this.element.addEventListener('scroll', this._update.bind(this), false);
     this._itemCount = 0;
-
-    // Listen for any changes to descendants and trigger a refresh. This ensures
-    // that items updated asynchronously will not break stick-to-bottom behavior
-    // if they change the scroll height.
-    this._observer = new MutationObserver(this.refresh.bind(this));
-    this._observerConfig = {childList: true, subtree: true};
-  }
-
-  /**
-   * @return {boolean}
-   */
-  stickToBottom() {
-    return this._stickToBottom;
-  }
-
-  /**
-   * @param {boolean} value
-   */
-  setStickToBottom(value) {
-    this._stickToBottom = value;
-    if (this._stickToBottom)
-      this._observer.observe(this._contentElement, this._observerConfig);
-    else
-      this._observer.disconnect();
-  }
-
-  /**
-   * @param {!Event} event
-   */
-  _onCopy(event) {
-    var text = this._selectedText();
-    if (!text)
-      return;
-    event.preventDefault();
-    event.clipboardData.setData('text/plain', text);
-  }
-
-  /**
-   * @param {!Event} event
-   */
-  _onDragStart(event) {
-    var text = this._selectedText();
-    if (!text)
-      return false;
-    event.dataTransfer.clearData();
-    event.dataTransfer.setData('text/plain', text);
-    event.dataTransfer.effectAllowed = 'copy';
-    return true;
-  }
-
-  /**
-   * @return {!Element}
-   */
-  contentElement() {
-    return this._contentElement;
-  }
-
-  invalidate() {
-    delete this._cumulativeHeights;
-    delete this._cachedProviderElements;
-    this._itemCount = this._provider.itemCount();
-    this.refresh();
-  }
-
-  /**
-   * @param {number} index
-   * @return {?UI.ViewportElement}
-   */
-  _providerElement(index) {
-    if (!this._cachedProviderElements)
-      this._cachedProviderElements = new Array(this._itemCount);
-    var element = this._cachedProviderElements[index];
-    if (!element) {
-      element = this._provider.itemElement(index);
-      this._cachedProviderElements[index] = element;
-    }
-    return element;
-  }
-
-  _rebuildCumulativeHeightsIfNeeded() {
-    if (this._cumulativeHeights)
-      return;
-    if (!this._itemCount)
-      return;
-    var firstActiveIndex = this._firstActiveIndex;
-    var lastActiveIndex = this._lastActiveIndex;
-    var height = 0;
-    this._cumulativeHeights = new Int32Array(this._itemCount);
-    for (var i = 0; i < this._itemCount; ++i) {
-      if (firstActiveIndex <= i && i <= lastActiveIndex)
-        height += this._renderedItems[i - firstActiveIndex].element().offsetHeight;
-      else
-        height += this._provider.fastHeight(i);
-      this._cumulativeHeights[i] = height;
-    }
-  }
-
-  /**
-   * @param {number} index
-   * @return {number}
-   */
-  _cachedItemHeight(index) {
-    return index === 0 ? this._cumulativeHeights[0] :
-                         this._cumulativeHeights[index] - this._cumulativeHeights[index - 1];
-  }
-
-  /**
-   * @param {?Selection} selection
-   * @suppressGlobalPropertiesCheck
-   */
-  _isSelectionBackwards(selection) {
-    if (!selection || !selection.rangeCount)
-      return false;
-    var range = document.createRange();
-    range.setStart(selection.anchorNode, selection.anchorOffset);
-    range.setEnd(selection.focusNode, selection.focusOffset);
-    return range.collapsed;
-  }
-
-  /**
-   * @param {number} itemIndex
-   * @param {!Node} node
-   * @param {number} offset
-   * @return {!{item: number, node: !Node, offset: number}}
-   */
-  _createSelectionModel(itemIndex, node, offset) {
-    return {item: itemIndex, node: node, offset: offset};
-  }
-
-  /**
-   * @param {?Selection} selection
-   */
-  _updateSelectionModel(selection) {
-    var range = selection && selection.rangeCount ? selection.getRangeAt(0) : null;
-    if (!range || selection.isCollapsed || !this.element.hasSelection()) {
-      this._headSelection = null;
-      this._anchorSelection = null;
-      return false;
-    }
-
-    var firstSelected = Number.MAX_VALUE;
-    var lastSelected = -1;
-
-    var hasVisibleSelection = false;
-    for (var i = 0; i < this._renderedItems.length; ++i) {
-      if (range.intersectsNode(this._renderedItems[i].element())) {
-        var index = i + this._firstActiveIndex;
-        firstSelected = Math.min(firstSelected, index);
-        lastSelected = Math.max(lastSelected, index);
-        hasVisibleSelection = true;
-      }
-    }
-    if (hasVisibleSelection) {
-      firstSelected =
-          this._createSelectionModel(firstSelected, /** @type {!Node} */ (range.startContainer), range.startOffset);
-      lastSelected =
-          this._createSelectionModel(lastSelected, /** @type {!Node} */ (range.endContainer), range.endOffset);
-    }
-    var topOverlap = range.intersectsNode(this._topGapElement) && this._topGapElement._active;
-    var bottomOverlap = range.intersectsNode(this._bottomGapElement) && this._bottomGapElement._active;
-    if (!topOverlap && !bottomOverlap && !hasVisibleSelection) {
-      this._headSelection = null;
-      this._anchorSelection = null;
-      return false;
-    }
-
-    if (!this._anchorSelection || !this._headSelection) {
-      this._anchorSelection = this._createSelectionModel(0, this.element, 0);
-      this._headSelection = this._createSelectionModel(this._itemCount - 1, this.element, this.element.children.length);
-      this._selectionIsBackward = false;
-    }
-
-    var isBackward = this._isSelectionBackwards(selection);
-    var startSelection = this._selectionIsBackward ? this._headSelection : this._anchorSelection;
-    var endSelection = this._selectionIsBackward ? this._anchorSelection : this._headSelection;
-    if (topOverlap && bottomOverlap && hasVisibleSelection) {
-      firstSelected = firstSelected.item < startSelection.item ? firstSelected : startSelection;
-      lastSelected = lastSelected.item > endSelection.item ? lastSelected : endSelection;
-    } else if (!hasVisibleSelection) {
-      firstSelected = startSelection;
-      lastSelected = endSelection;
-    } else if (topOverlap) {
-      firstSelected = isBackward ? this._headSelection : this._anchorSelection;
-    } else if (bottomOverlap) {
-      lastSelected = isBackward ? this._anchorSelection : this._headSelection;
-    }
-
-    if (isBackward) {
-      this._anchorSelection = lastSelected;
-      this._headSelection = firstSelected;
-    } else {
-      this._anchorSelection = firstSelected;
-      this._headSelection = lastSelected;
-    }
-    this._selectionIsBackward = isBackward;
-    return true;
-  }
-
-  /**
-   * @param {?Selection} selection
-   */
-  _restoreSelection(selection) {
-    var anchorElement = null;
-    var anchorOffset;
-    if (this._firstActiveIndex <= this._anchorSelection.item && this._anchorSelection.item <= this._lastActiveIndex) {
-      anchorElement = this._anchorSelection.node;
-      anchorOffset = this._anchorSelection.offset;
-    } else {
-      if (this._anchorSelection.item < this._firstActiveIndex)
-        anchorElement = this._topGapElement;
-      else if (this._anchorSelection.item > this._lastActiveIndex)
-        anchorElement = this._bottomGapElement;
-      anchorOffset = this._selectionIsBackward ? 1 : 0;
-    }
-
-    var headElement = null;
-    var headOffset;
-    if (this._firstActiveIndex <= this._headSelection.item && this._headSelection.item <= this._lastActiveIndex) {
-      headElement = this._headSelection.node;
-      headOffset = this._headSelection.offset;
-    } else {
-      if (this._headSelection.item < this._firstActiveIndex)
-        headElement = this._topGapElement;
-      else if (this._headSelection.item > this._lastActiveIndex)
-        headElement = this._bottomGapElement;
-      headOffset = this._selectionIsBackward ? 0 : 1;
-    }
-
-    selection.setBaseAndExtent(anchorElement, anchorOffset, headElement, headOffset);
+    this._indexSymbol = Symbol('UI.ViewportControl._indexSymbol');
   }
 
   refresh() {
-    this._observer.disconnect();
-    this._innerRefresh();
-    if (this._stickToBottom)
-      this._observer.observe(this._contentElement, this._observerConfig);
+    this._itemCount = this._provider.itemCount();
+    this._innerElement.removeChildren();
+
+    var height = 0;
+    this._cumulativeHeights = new Int32Array(this._itemCount);
+    for (var i = 0; i < this._itemCount; ++i) {
+      height += this._provider.fastItemHeight(i);
+      this._cumulativeHeights[i] = height;
+    }
+    this._innerElement.style.height = height + 'px';
+
+    this._update();
   }
 
-  _innerRefresh() {
-    if (!this._visibleHeight())
-      return;  // Do nothing for invisible controls.
-
-    if (!this._itemCount) {
-      for (var i = 0; i < this._renderedItems.length; ++i)
-        this._renderedItems[i].willHide();
-      this._renderedItems = [];
-      this._contentElement.removeChildren();
-      this._topGapElement.style.height = '0px';
-      this._bottomGapElement.style.height = '0px';
-      this._firstActiveIndex = -1;
-      this._lastActiveIndex = -1;
+  _update() {
+    if (!this._cumulativeHeights) {
+      this.refresh();
       return;
     }
 
-    var selection = this.element.getComponentSelection();
-    var shouldRestoreSelection = this._updateSelectionModel(selection);
-
-    var visibleFrom = this.element.scrollTop;
     var visibleHeight = this._visibleHeight();
-    var isInvalidating = !this._cumulativeHeights;
-
-    for (var i = 0; i < this._renderedItems.length; ++i) {
-      // Tolerate 1-pixel error due to double-to-integer rounding errors.
-      if (this._cumulativeHeights &&
-          Math.abs(this._cachedItemHeight(this._firstActiveIndex + i) - this._renderedItems[i].element().offsetHeight) >
-              1)
-        delete this._cumulativeHeights;
-    }
-    this._rebuildCumulativeHeightsIfNeeded();
-    var oldFirstActiveIndex = this._firstActiveIndex;
-    var oldLastActiveIndex = this._lastActiveIndex;
+    var visibleFrom = this.element.scrollTop;
     var activeHeight = visibleHeight * 2;
-    // When the viewport is scrolled to the bottom, using the cumulative heights estimate is not
-    // precise enough to determine next visible indices. This stickToBottom check avoids extra
-    // calls to refresh in those cases.
-    if (this._stickToBottom) {
-      this._firstActiveIndex =
-          Math.max(this._itemCount - Math.ceil(activeHeight / this._provider.minimumRowHeight()), 0);
-      this._lastActiveIndex = this._itemCount - 1;
-    } else {
-      this._firstActiveIndex = Math.max(
-          Array.prototype.lowerBound.call(
-              this._cumulativeHeights, visibleFrom + 1 - (activeHeight - visibleHeight) / 2),
-          0);
-      // Proactively render more rows in case some of them will be collapsed without triggering refresh. @see crbug.com/390169
-      this._lastActiveIndex = this._firstActiveIndex + Math.ceil(activeHeight / this._provider.minimumRowHeight()) - 1;
-      this._lastActiveIndex = Math.min(this._lastActiveIndex, this._itemCount - 1);
+    var firstActiveIndex = Math.max(
+        Array.prototype.lowerBound.call(this._cumulativeHeights, visibleFrom + 1 - (activeHeight - visibleHeight) / 2),
+        0);
+    var lastActiveIndex = Math.min(
+        Array.prototype.lowerBound.call(
+            this._cumulativeHeights, visibleFrom + visibleHeight + (activeHeight - visibleHeight) / 2),
+        this._itemCount - 1);
+
+    var children = this._innerElement.children;
+    for (var i = children.length - 1; i >= 0; --i) {
+      var element = children[i];
+      if (element[this._indexSymbol] < firstActiveIndex || element[this._indexSymbol] > lastActiveIndex)
+        element.remove();
     }
 
-    var topGapHeight = this._cumulativeHeights[this._firstActiveIndex - 1] || 0;
-    var bottomGapHeight =
-        this._cumulativeHeights[this._cumulativeHeights.length - 1] - this._cumulativeHeights[this._lastActiveIndex];
-
-    /**
-     * @this {UI.ViewportControl}
-     */
-    function prepare() {
-      this._topGapElement.style.height = topGapHeight + 'px';
-      this._bottomGapElement.style.height = bottomGapHeight + 'px';
-      this._topGapElement._active = !!topGapHeight;
-      this._bottomGapElement._active = !!bottomGapHeight;
-      this._contentElement.style.setProperty('height', '10000000px');
-    }
-
-    if (isInvalidating)
-      this._fullViewportUpdate(prepare.bind(this));
-    else
-      this._partialViewportUpdate(oldFirstActiveIndex, oldLastActiveIndex, prepare.bind(this));
-    this._contentElement.style.removeProperty('height');
-    // Should be the last call in the method as it might force layout.
-    if (shouldRestoreSelection)
-      this._restoreSelection(selection);
-    if (this._stickToBottom)
-      this.element.scrollTop = 10000000;
+    for (var i = firstActiveIndex; i <= lastActiveIndex; ++i)
+      this._insertElement(i);
   }
 
   /**
-   * @param {function()} prepare
+   * @param {number} index
    */
-  _fullViewportUpdate(prepare) {
-    for (var i = 0; i < this._renderedItems.length; ++i)
-      this._renderedItems[i].willHide();
-    prepare();
-    this._renderedItems = [];
-    this._contentElement.removeChildren();
-    for (var i = this._firstActiveIndex; i <= this._lastActiveIndex; ++i) {
-      var viewportElement = this._providerElement(i);
-      this._contentElement.appendChild(viewportElement.element());
-      this._renderedItems.push(viewportElement);
-    }
-    for (var i = 0; i < this._renderedItems.length; ++i)
-      this._renderedItems[i].wasShown();
-  }
+  _insertElement(index) {
+    var element = this._provider.itemElement(index);
+    if (!element || element.parentElement === this._innerElement)
+      return;
 
-  /**
-   * @param {number} oldFirstActiveIndex
-   * @param {number} oldLastActiveIndex
-   * @param {function()} prepare
-   */
-  _partialViewportUpdate(oldFirstActiveIndex, oldLastActiveIndex, prepare) {
-    var willBeHidden = [];
-    for (var i = 0; i < this._renderedItems.length; ++i) {
-      var index = oldFirstActiveIndex + i;
-      if (index < this._firstActiveIndex || this._lastActiveIndex < index)
-        willBeHidden.push(this._renderedItems[i]);
-    }
-    for (var i = 0; i < willBeHidden.length; ++i)
-      willBeHidden[i].willHide();
-    prepare();
-    for (var i = 0; i < willBeHidden.length; ++i)
-      willBeHidden[i].element().remove();
-
-    this._renderedItems = [];
-    var anchor = this._contentElement.firstChild;
-    var wasShown = [];
-    for (var i = this._firstActiveIndex; i <= this._lastActiveIndex; ++i) {
-      var viewportElement = this._providerElement(i);
-      var element = viewportElement.element();
-      if (element !== anchor) {
-        this._contentElement.insertBefore(element, anchor);
-        wasShown.push(viewportElement);
-      } else {
-        anchor = anchor.nextSibling;
-      }
-      this._renderedItems.push(viewportElement);
-    }
-    for (var i = 0; i < wasShown.length; ++i)
-      wasShown[i].wasShown();
-  }
-
-  /**
-   * @return {?string}
-   */
-  _selectedText() {
-    this._updateSelectionModel(this.element.getComponentSelection());
-    if (!this._headSelection || !this._anchorSelection)
-      return null;
-
-    var startSelection = null;
-    var endSelection = null;
-    if (this._selectionIsBackward) {
-      startSelection = this._headSelection;
-      endSelection = this._anchorSelection;
-    } else {
-      startSelection = this._anchorSelection;
-      endSelection = this._headSelection;
-    }
-
-    var textLines = [];
-    for (var i = startSelection.item; i <= endSelection.item; ++i)
-      textLines.push(this._providerElement(i).element().deepTextContent());
-
-    var endSelectionElement = this._providerElement(endSelection.item).element();
-    if (endSelection.node && endSelection.node.isSelfOrDescendant(endSelectionElement)) {
-      var itemTextOffset = this._textOffsetInNode(endSelectionElement, endSelection.node, endSelection.offset);
-      textLines[textLines.length - 1] = textLines.peekLast().substring(0, itemTextOffset);
-    }
-
-    var startSelectionElement = this._providerElement(startSelection.item).element();
-    if (startSelection.node && startSelection.node.isSelfOrDescendant(startSelectionElement)) {
-      var itemTextOffset = this._textOffsetInNode(startSelectionElement, startSelection.node, startSelection.offset);
-      textLines[0] = textLines[0].substring(itemTextOffset);
-    }
-
-    return textLines.join('\n');
-  }
-
-  /**
-   * @param {!Element} itemElement
-   * @param {!Node} container
-   * @param {number} offset
-   * @return {number}
-   */
-  _textOffsetInNode(itemElement, container, offset) {
-    var chars = 0;
-    var node = itemElement;
-    while ((node = node.traverseNextTextNode()) && !node.isSelfOrDescendant(container))
-      chars += node.textContent.length;
-    return chars + offset;
-  }
-
-  /**
-   * @param {!Event} event
-   */
-  _onScroll(event) {
-    this.refresh();
+    element.style.position = 'absolute';
+    element.style.top = (this._cumulativeHeights[index - 1] || 0) + 'px';
+    element.style.left = '0';
+    element.style.right = '0';
+    element[this._indexSymbol] = index;
+    this._innerElement.appendChild(element);
   }
 
   /**
    * @return {number}
    */
   firstVisibleIndex() {
-    var firstVisibleIndex =
-        Math.max(Array.prototype.lowerBound.call(this._cumulativeHeights, this.element.scrollTop + 1), 0);
-    return Math.max(firstVisibleIndex, this._firstActiveIndex);
+    return Math.max(Array.prototype.lowerBound.call(this._cumulativeHeights, this.element.scrollTop + 1), 0);
   }
 
   /**
    * @return {number}
    */
   lastVisibleIndex() {
-    var lastVisibleIndex;
-    if (this._stickToBottom) {
-      lastVisibleIndex = this._itemCount - 1;
-    } else {
-      lastVisibleIndex =
-          this.firstVisibleIndex() + Math.ceil(this._visibleHeight() / this._provider.minimumRowHeight()) - 1;
-    }
-    return Math.min(lastVisibleIndex, this._lastActiveIndex);
-  }
-
-  /**
-   * @return {?Element}
-   */
-  renderedElementAt(index) {
-    if (index < this._firstActiveIndex)
-      return null;
-    if (index > this._lastActiveIndex)
-      return null;
-    return this._renderedItems[index - this._firstActiveIndex].element();
+    return Math.min(
+        Array.prototype.lowerBound.call(this._cumulativeHeights, this.element.scrollTop + this._visibleHeight()),
+        this._itemCount);
   }
 
   /**
@@ -545,31 +118,22 @@
    * @param {number} index
    */
   forceScrollItemToBeFirst(index) {
-    this.setStickToBottom(false);
-    this._rebuildCumulativeHeightsIfNeeded();
     this.element.scrollTop = index > 0 ? this._cumulativeHeights[index - 1] : 0;
-    if (this.element.isScrolledToBottom())
-      this.setStickToBottom(true);
-    this.refresh();
+    this._update();
   }
 
   /**
    * @param {number} index
    */
   forceScrollItemToBeLast(index) {
-    this.setStickToBottom(false);
-    this._rebuildCumulativeHeightsIfNeeded();
     this.element.scrollTop = this._cumulativeHeights[index] - this._visibleHeight();
-    if (this.element.isScrolledToBottom())
-      this.setStickToBottom(true);
-    this.refresh();
+    this._update();
   }
 
   /**
    * @return {number}
    */
   _visibleHeight() {
-    // Use offsetHeight instead of clientHeight to avoid being affected by horizontal scroll.
     return this.element.offsetHeight;
   }
 };
@@ -584,7 +148,7 @@
    * @param {number} index
    * @return {number}
    */
-  fastHeight(index) {
+  fastItemHeight(index) {
     return 0;
   },
 
@@ -596,65 +160,10 @@
   },
 
   /**
-   * @return {number}
-   */
-  minimumRowHeight() {
-    return 0;
-  },
-
-  /**
    * @param {number} index
-   * @return {?UI.ViewportElement}
+   * @return {?Element}
    */
   itemElement(index) {
     return null;
   }
 };
-
-/**
- * @interface
- */
-UI.ViewportElement = function() {};
-UI.ViewportElement.prototype = {
-  willHide() {},
-
-  wasShown() {},
-
-  /**
-   * @return {!Element}
-   */
-  element() {},
-};
-
-/**
- * @implements {UI.ViewportElement}
- * @unrestricted
- */
-UI.StaticViewportElement = class {
-  /**
-   * @param {!Element} element
-   */
-  constructor(element) {
-    this._element = element;
-  }
-
-  /**
-   * @override
-   */
-  willHide() {
-  }
-
-  /**
-   * @override
-   */
-  wasShown() {
-  }
-
-  /**
-   * @override
-   * @return {!Element}
-   */
-  element() {
-    return this._element;
-  }
-};
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/inspectorCommon.css b/third_party/WebKit/Source/devtools/front_end/ui/inspectorCommon.css
index be44c32..b7b1dc6e 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/inspectorCommon.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/inspectorCommon.css
@@ -351,18 +351,20 @@
     -webkit-mask-size: 352px 168px;
 }
 
-.force-white-icons .spritesheet-smallicons, .force-white-icons.spritesheet-smallicons {
+.force-white-icons [is=ui-icon].spritesheet-smallicons, [is=ui-icon].force-white-icons.spritesheet-smallicons {
     -webkit-mask-image: -webkit-image-set(url(Images/smallIcons.png) 1x, url(Images/smallIcons_2x.png) 2x);
     -webkit-mask-size: 190px 30px;
     background-image: unset;
     background-size: unset;
+    background: unset;
     background-color: white;
 }
 
-.force-white-icons .spritesheet-largeicons, .force-white-icons.spritesheet-largeicons {
+.force-white-icons [is=ui-icon].spritesheet-largeicons, [is=ui-icon].force-white-icons.spritesheet-largeicons {
     -webkit-mask-image: -webkit-image-set(url(Images/toolbarButtonGlyphs.png) 1x, url(Images/toolbarButtonGlyphs_2x.png) 2x);
     -webkit-mask-size: 352px 168px;
     background-image: unset;
     background-size: unset;
+    background: unset;
     background-color: white;
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/module.json b/third_party/WebKit/Source/devtools/front_end/ui/module.json
index 1f2f5415..65562cc 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/ui/module.json
@@ -51,7 +51,6 @@
         "TabbedPane.js",
         "UIUtils.js",
         "ViewportControl.js",
-        "StaticViewportControl.js",
         "ZoomManager.js"
     ],
     "resources": [
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/splitWidget.css b/third_party/WebKit/Source/devtools/front_end/ui/splitWidget.css
index c1e8cc580..e95ae683 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/splitWidget.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/splitWidget.css
@@ -39,7 +39,7 @@
     display: flex;
     position: relative;
     flex-direction: column;
-    contain: strict;
+    contain: layout size style;
 }
 
 .shadow-split-widget-sidebar {
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.css b/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.css
index 4d7c9b8..5b1dab39 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.css
@@ -89,8 +89,17 @@
 }
 
 .tree-outline li .icons-container {
-    margin-left: 4px;
     align-self: center;
+    display: flex;
+    align-items: center;
+}
+
+.tree-outline li .leading-icons {
+    margin-right: 4px;
+}
+
+.tree-outline li .trailing-icons {
+    margin-left: 4px;
 }
 
 .tree-outline li::before {
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js b/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js
index 8755e425..e65892c 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js
@@ -602,7 +602,8 @@
     this._listItemNode.removeChildren();
     if (this._iconElement)
       this._listItemNode.appendChild(this._iconElement);
-
+    if (this._leadingIconsElement)
+      this._listItemNode.appendChild(this._leadingIconsElement);
     this._listItemNode.appendChild(this._titleElement);
     if (this._trailingIconsElement)
       this._listItemNode.appendChild(this._trailingIconsElement);
@@ -639,11 +640,29 @@
   /**
    * @param {!Array<!UI.Icon>} icons
    */
+  setLeadingIcons(icons) {
+    if (!this._leadingIconsElement && !icons.length)
+      return;
+    if (!this._leadingIconsElement) {
+      this._leadingIconsElement = createElementWithClass('div', 'leading-icons');
+      this._leadingIconsElement.classList.add('icons-container');
+      this._listItemNode.insertBefore(this._leadingIconsElement, this._titleElement);
+      this._ensureSelection();
+    }
+    this._leadingIconsElement.removeChildren();
+    for (var icon of icons)
+      this._leadingIconsElement.appendChild(icon);
+  }
+
+  /**
+   * @param {!Array<!UI.Icon>} icons
+   */
   setTrailingIcons(icons) {
     if (!this._trailingIconsElement && !icons.length)
       return;
     if (!this._trailingIconsElement) {
-      this._trailingIconsElement = createElementWithClass('div', 'icons-container');
+      this._trailingIconsElement = createElementWithClass('div', 'trailing-icons');
+      this._trailingIconsElement.classList.add('icons-container');
       this._listItemNode.appendChild(this._trailingIconsElement);
       this._ensureSelection();
     }
diff --git a/third_party/WebKit/Source/devtools/front_end/ui_lazy/DataGrid.js b/third_party/WebKit/Source/devtools/front_end/ui_lazy/DataGrid.js
index 49d49e9a..039b849 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui_lazy/DataGrid.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui_lazy/DataGrid.js
@@ -610,7 +610,7 @@
       for (var i = 0; i < numColumns; i++) {
         var column = this._visibleColumnsArray[i];
         if (!column.weight)
-          column.weight = 100 * cells[i].offsetWidth / tableWidth;
+          column.weight = 100 * cells[i].offsetWidth / tableWidth || 10;
       }
       this._columnWidthsInitialized = true;
     }
diff --git a/third_party/WebKit/Source/devtools/front_end/ui_lazy/FilteredListWidget.js b/third_party/WebKit/Source/devtools/front_end/ui_lazy/FilteredListWidget.js
index 8d5029c7..c74eec5 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui_lazy/FilteredListWidget.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui_lazy/FilteredListWidget.js
@@ -4,7 +4,7 @@
  * found in the LICENSE file.
  */
 /**
- * @implements {UI.StaticViewportControl.Provider}
+ * @implements {UI.ViewportControl.Provider}
  * @unrestricted
  */
 UI.FilteredListWidget = class extends UI.VBox {
@@ -33,7 +33,7 @@
     promptProxy.classList.add('filtered-list-widget-prompt-element');
 
     this._filteredItems = [];
-    this._viewportControl = new UI.StaticViewportControl(this);
+    this._viewportControl = new UI.ViewportControl(this);
     this._itemElementsContainer = this._viewportControl.element;
     this._itemElementsContainer.classList.add('container');
     this._itemElementsContainer.addEventListener('click', this._onClick.bind(this), false);
@@ -162,16 +162,19 @@
     if (this._scoringTimer) {
       clearTimeout(this._scoringTimer);
       delete this._scoringTimer;
+
+      if (this._refreshViewportWithCurrentResult)
+        this._refreshViewportWithCurrentResult();
     }
 
     var query = this._delegate.rewriteQuery(this._value());
     this._query = query;
+
     var filterRegex = query ? UI.FilteredListWidget.filterRegex(query) : null;
 
     var oldSelectedAbsoluteIndex =
-        this._selectedIndexInFiltered ? this._filteredItems[this._selectedIndexInFiltered] : null;
+        this._selectedIndexInFiltered && query ? this._filteredItems[this._selectedIndexInFiltered] : undefined;
     var filteredItems = [];
-    this._selectedIndexInFiltered = 0;
 
     var bestScores = [];
     var bestItems = [];
@@ -195,8 +198,10 @@
      * @this {UI.FilteredListWidget}
      */
     function scoreItems(fromIndex) {
+      delete this._scoringTimer;
       var maxWorkItems = 1000;
       var workDone = 0;
+
       for (var i = fromIndex; i < this._delegate.itemCount() && workDone < maxWorkItems; ++i) {
         // Filter out non-matching items quickly.
         if (filterRegex && !filterRegex.test(this._delegate.itemKeyAt(i)))
@@ -224,30 +229,43 @@
         }
       }
 
+      this._refreshViewportWithCurrentResult =
+          this._refreshViewport.bind(this, bestItems, overflowItems, filteredItems, oldSelectedAbsoluteIndex);
+
       // Process everything in chunks.
       if (i < this._delegate.itemCount()) {
         this._scoringTimer = setTimeout(scoreItems.bind(this, i), 0);
         return;
       }
-      delete this._scoringTimer;
 
-      this._filteredItems = bestItems.concat(overflowItems).concat(filteredItems);
-      for (var i = 0; i < this._filteredItems.length; ++i) {
-        if (this._filteredItems[i] === oldSelectedAbsoluteIndex) {
-          this._selectedIndexInFiltered = i;
-          break;
-        }
-      }
-      this._elements = [];
-      this._viewportControl.refresh();
-      if (!query)
-        this._selectedIndexInFiltered = 0;
-      this._updateSelection(this._selectedIndexInFiltered, false);
-      this._itemsFilteredForTest();
+      this._refreshViewportWithCurrentResult();
     }
   }
 
   /**
+   * @param {!Array<number>} bestItems
+   * @param {!Array<number>} overflowItems
+   * @param {!Array<number>} filteredItems
+   * @param {number|undefined} selectedAbsoluteIndex
+   */
+  _refreshViewport(bestItems, overflowItems, filteredItems, selectedAbsoluteIndex) {
+    delete this._refreshViewportWithCurrentResult;
+    this._filteredItems = bestItems.concat(overflowItems).concat(filteredItems);
+
+    this._selectedIndexInFiltered = 0;
+    for (var i = 0; selectedAbsoluteIndex !== undefined && i < this._filteredItems.length; ++i) {
+      if (this._filteredItems[i] === selectedAbsoluteIndex) {
+        this._selectedIndexInFiltered = i;
+        break;
+      }
+    }
+    this._elements = [];
+    this._viewportControl.refresh();
+    this._updateSelection(this._selectedIndexInFiltered, false);
+    this._itemsFilteredForTest();
+  }
+
+  /**
    * @return {boolean}
    */
   _shouldShowMatchingItems() {
diff --git a/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp b/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp
index d92af7b3..4368664 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp
+++ b/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp
@@ -482,8 +482,10 @@
   // is an iframe element with an |allowpaymentrequest| attribute specified, and
   // whose node document is allowed to use the feature indicated by
   // |allowpaymentrequest|, then return true.
-  if (frame->owner() && frame->owner()->allowPaymentRequest())
+  if (RuntimeEnabledFeatures::paymentRequestIFrameEnabled() && frame->owner() &&
+      frame->owner()->allowPaymentRequest()) {
     return allowedToUsePaymentRequest(frame->tree().parent());
+  }
 
   // 4. Return false.
   return false;
diff --git a/third_party/WebKit/Source/modules/vr/VRDisplay.cpp b/third_party/WebKit/Source/modules/vr/VRDisplay.cpp
index 44ccd0d..c35e7f13 100644
--- a/third_party/WebKit/Source/modules/vr/VRDisplay.cpp
+++ b/third_party/WebKit/Source/modules/vr/VRDisplay.cpp
@@ -702,7 +702,7 @@
   // depend on the Fullscreen API to fake VR presentation, so this will
   // become unnessecary. Until that point, though, this seems preferable to
   // adding a bunch of notification plumbing to Fullscreen.
-  if (!Fullscreen::isCurrentFullScreenElement(*m_layer.source())) {
+  if (!Fullscreen::isFullscreenElement(*m_layer.source())) {
     // TODO(mthiesse): Due to asynchronous resizing, we might get kicked out of
     // fullscreen when changing display parameters upon entering WebVR. So one
     // time only, we reenter fullscreen after having left it; otherwise we exit
diff --git a/third_party/WebKit/Source/modules/webaudio/RealtimeAnalyser.cpp b/third_party/WebKit/Source/modules/webaudio/RealtimeAnalyser.cpp
index b4cdd95..a0d1e56 100644
--- a/third_party/WebKit/Source/modules/webaudio/RealtimeAnalyser.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/RealtimeAnalyser.cpp
@@ -63,11 +63,9 @@
 bool RealtimeAnalyser::setFftSize(size_t size) {
   DCHECK(isMainThread());
 
-  // Only allow powers of two.
-  unsigned log2size = static_cast<unsigned>(log2(size));
-  bool isPOT(1UL << log2size == size);
-
-  if (!isPOT || size > MaxFFTSize || size < MinFFTSize)
+  // Only allow powers of two within the allowed range.
+  if (size > MaxFFTSize || size < MinFFTSize ||
+      !AudioUtilities::isPowerOfTwo(size))
     return false;
 
   if (m_fftSize != size) {
diff --git a/third_party/WebKit/Source/platform/audio/AudioUtilities.cpp b/third_party/WebKit/Source/platform/audio/AudioUtilities.cpp
index abb0e88..b87ba22 100644
--- a/third_party/WebKit/Source/platform/audio/AudioUtilities.cpp
+++ b/third_party/WebKit/Source/platform/audio/AudioUtilities.cpp
@@ -73,6 +73,14 @@
   // should too.
   return 384000;
 }
+
+bool isPowerOfTwo(size_t x) {
+  // From Hacker's Delight.  x & (x - 1) turns off (zeroes) the
+  // rightmost 1-bit in the word x.  If x is a power of two, then the
+  // result is, of course, 0.
+  return x > 0 && ((x & (x - 1)) == 0);
+}
+
 }  // namespace AudioUtilities
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/audio/AudioUtilities.h b/third_party/WebKit/Source/platform/audio/AudioUtilities.h
index ccb7008..8844ff84 100644
--- a/third_party/WebKit/Source/platform/audio/AudioUtilities.h
+++ b/third_party/WebKit/Source/platform/audio/AudioUtilities.h
@@ -57,6 +57,10 @@
 // Return max/min sample rate supported by AudioBuffers.
 PLATFORM_EXPORT float minAudioBufferSampleRate();
 PLATFORM_EXPORT float maxAudioBufferSampleRate();
+
+// Check to see if x is a power of two.  If x == 0, returns false.
+PLATFORM_EXPORT bool isPowerOfTwo(size_t x);
+
 }  // namespace AudioUtilities
 }  // namespace blink
 
diff --git a/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp b/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp
index 84cbb6f8..e7caecf5 100644
--- a/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp
@@ -495,6 +495,8 @@
   }
 }
 
+namespace {
+
 class UnacceleratedSurfaceFactory
     : public RecordingImageBufferFallbackSurfaceFactory {
  public:
@@ -511,6 +513,8 @@
   virtual ~UnacceleratedSurfaceFactory() {}
 };
 
+}  // namespace
+
 void ImageBuffer::disableAcceleration() {
   if (!isAccelerated())
     return;
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintControllerTest.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintControllerTest.cpp
index faafd94..5a77d02 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintControllerTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintControllerTest.cpp
@@ -15,6 +15,7 @@
 #include "platform/graphics/paint/SubsequenceRecorder.h"
 #include "platform/testing/FakeDisplayItemClient.h"
 #include "platform/testing/PaintPropertyTestHelpers.h"
+#include "platform/testing/RuntimeEnabledFeaturesTestHelpers.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include <memory>
@@ -50,11 +51,8 @@
   int numIndexedItems() const { return m_paintController->m_numIndexedItems; }
 #endif
 
-  void TearDown() override { m_featuresBackup.restore(); }
-
  private:
   std::unique_ptr<PaintController> m_paintController;
-  RuntimeEnabledFeatures::Backup m_featuresBackup;
 };
 
 const DisplayItem::Type foregroundDrawingType =
@@ -120,51 +118,33 @@
 }
 
 enum TestConfigurations {
-  SPv1,
-  SPv2,
-  UnderInvalidationCheckingSPv1,
-  UnderInvalidationCheckingSPv2,
+  SPv2 = 1 << 0,
+  UnderInvalidationChecking = 1 << 1,
 };
 
 // Tests using this class will be tested with under-invalidation-checking
 // enabled and disabled.
 class PaintControllerTest
     : public PaintControllerTestBase,
-      public ::testing::WithParamInterface<TestConfigurations> {
+      public ::testing::WithParamInterface<TestConfigurations>,
+      private ScopedSlimmingPaintV2ForTest,
+      private ScopedPaintUnderInvalidationCheckingForTest {
  public:
   PaintControllerTest()
-      : m_rootPaintPropertyClient("root"),
+      : ScopedSlimmingPaintV2ForTest(GetParam() & SPv2),
+        ScopedPaintUnderInvalidationCheckingForTest(GetParam() &
+                                                    UnderInvalidationChecking),
+        m_rootPaintPropertyClient("root"),
         m_rootPaintChunkId(m_rootPaintPropertyClient,
                            DisplayItem::kUninitializedType) {}
 
- protected:
-  void SetUp() override {
-    switch (GetParam()) {
-      case SPv1:
-        break;
-      case SPv2:
-        RuntimeEnabledFeatures::setSlimmingPaintV2Enabled(true);
-        break;
-      case UnderInvalidationCheckingSPv1:
-        RuntimeEnabledFeatures::setPaintUnderInvalidationCheckingEnabled(true);
-        break;
-      case UnderInvalidationCheckingSPv2:
-        RuntimeEnabledFeatures::setSlimmingPaintV2Enabled(true);
-        RuntimeEnabledFeatures::setPaintUnderInvalidationCheckingEnabled(true);
-        break;
-    }
-  }
-
   FakeDisplayItemClient m_rootPaintPropertyClient;
   PaintChunk::Id m_rootPaintChunkId;
 };
 
 INSTANTIATE_TEST_CASE_P(All,
                         PaintControllerTest,
-                        ::testing::Values(SPv1,
-                                          SPv2,
-                                          UnderInvalidationCheckingSPv1,
-                                          UnderInvalidationCheckingSPv2));
+                        ::testing::Values(SPv2, UnderInvalidationChecking));
 
 TEST_P(PaintControllerTest, NestedRecorders) {
   GraphicsContext context(getPaintController());
@@ -1839,7 +1819,7 @@
 }
 
 TEST_F(PaintControllerTestBase, SmallPaintControllerHasOnePaintChunk) {
-  RuntimeEnabledFeatures::setSlimmingPaintV2Enabled(true);
+  ScopedSlimmingPaintV2ForTest enableSPv2(true);
   FakeDisplayItemClient client("test client");
 
   if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) {
@@ -2025,13 +2005,15 @@
 // Death tests don't work properly on Android.
 #if defined(GTEST_HAS_DEATH_TEST) && !OS(ANDROID)
 
-class PaintControllerUnderInvalidationTest : public PaintControllerTestBase {
- protected:
-  void SetUp() override {
-    PaintControllerTestBase::SetUp();
-    RuntimeEnabledFeatures::setPaintUnderInvalidationCheckingEnabled(true);
-  }
+class PaintControllerUnderInvalidationTest
+    : public PaintControllerTestBase,
+      private ScopedPaintUnderInvalidationCheckingForTest {
+ public:
+  PaintControllerUnderInvalidationTest()
+      : PaintControllerTestBase(),
+        ScopedPaintUnderInvalidationCheckingForTest(true) {}
 
+ protected:
   void testChangeDrawing() {
     FakeDisplayItemClient first("first");
     GraphicsContext context(getPaintController());
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PropertyTreeState.h b/third_party/WebKit/Source/platform/graphics/paint/PropertyTreeState.h
index 02048442..c59fc27 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PropertyTreeState.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/PropertyTreeState.h
@@ -38,36 +38,32 @@
     DCHECK(!m_transform || !m_transform->hasOneRef());
     return m_transform.get();
   }
-  void setTransform(const TransformPaintPropertyNode* node) {
-    m_transform = node;
-    DCHECK(!node->hasOneRef());
+  void setTransform(RefPtr<const TransformPaintPropertyNode> node) {
+    m_transform = std::move(node);
   }
 
   const ClipPaintPropertyNode* clip() const {
     DCHECK(!m_clip || !m_clip->hasOneRef());
     return m_clip.get();
   }
-  void setClip(const ClipPaintPropertyNode* node) {
-    m_clip = node;
-    DCHECK(!node->hasOneRef());
+  void setClip(RefPtr<const ClipPaintPropertyNode> node) {
+    m_clip = std::move(node);
   }
 
   const EffectPaintPropertyNode* effect() const {
     DCHECK(!m_effect || !m_effect->hasOneRef());
     return m_effect.get();
   }
-  void setEffect(const EffectPaintPropertyNode* node) {
-    m_effect = node;
-    DCHECK(!node->hasOneRef());
+  void setEffect(RefPtr<const EffectPaintPropertyNode> node) {
+    m_effect = std::move(node);
   }
 
   const ScrollPaintPropertyNode* scroll() const {
     DCHECK(!m_scroll || !m_scroll->hasOneRef());
     return m_scroll.get();
   }
-  void setScroll(const ScrollPaintPropertyNode* node) {
-    m_scroll = node;
-    DCHECK(!node->hasOneRef());
+  void setScroll(RefPtr<const ScrollPaintPropertyNode> node) {
+    m_scroll = std::move(node);
   }
 
  private:
diff --git a/third_party/WebKit/Source/platform/scheduler/base/real_time_domain.cc b/third_party/WebKit/Source/platform/scheduler/base/real_time_domain.cc
index c3c8e2f..8614d7a 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/real_time_domain.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/real_time_domain.cc
@@ -39,16 +39,11 @@
   return task_queue_manager_->delegate()->NowTicks();
 }
 
-void RealTimeDomain::RequestWakeupAt(LazyNow* lazy_now,
-                                     base::TimeTicks run_time) {
+void RealTimeDomain::RequestWakeup(base::TimeTicks now, base::TimeDelta delay) {
   // NOTE this is only called if the scheduled runtime is sooner than any
   // previously scheduled runtime, or there is no (outstanding) previously
   // scheduled runtime.
-  task_queue_manager_->MaybeScheduleDelayedWork(FROM_HERE, lazy_now, run_time);
-}
-
-void RealTimeDomain::CancelWakeupAt(base::TimeTicks run_time) {
-  task_queue_manager_->CancelDelayedWork(run_time);
+  task_queue_manager_->MaybeScheduleDelayedWork(FROM_HERE, now, delay);
 }
 
 base::Optional<base::TimeDelta> RealTimeDomain::DelayTillNextTask(
diff --git a/third_party/WebKit/Source/platform/scheduler/base/real_time_domain.h b/third_party/WebKit/Source/platform/scheduler/base/real_time_domain.h
index 03e75424..6883599 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/real_time_domain.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/real_time_domain.h
@@ -29,8 +29,7 @@
  protected:
   void OnRegisterWithTaskQueueManager(
       TaskQueueManager* task_queue_manager) override;
-  void RequestWakeupAt(LazyNow* lazy_now, base::TimeTicks run_time) override;
-  void CancelWakeupAt(base::TimeTicks run_time) override;
+  void RequestWakeup(base::TimeTicks now, base::TimeDelta delay) override;
   void AsValueIntoInternal(
       base::trace_event::TracedValue* state) const override;
 
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc
index f78e39d2..2885ccd 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc
@@ -276,15 +276,11 @@
   main_thread_only().delayed_incoming_queue.push(std::move(pending_task));
 
   // If |pending_task| is at the head of the queue, then make sure a wakeup
-  // is requested if the queue is enabled.  Note we still want to schedule a
-  // wakeup even if blocked by a fence, because we'd break throttling logic
-  // otherwise.
-  base::TimeTicks next_delayed_task =
-      main_thread_only().delayed_incoming_queue.top().delayed_run_time;
-  if (next_delayed_task == delayed_run_time && IsQueueEnabled()) {
-    LazyNow lazy_now(now);
-    main_thread_only().time_domain->ScheduleDelayedWork(this, delayed_run_time,
-                                                        &lazy_now);
+  // is requested.
+  if (main_thread_only().delayed_incoming_queue.top().delayed_run_time ==
+      delayed_run_time) {
+    main_thread_only().time_domain->ScheduleDelayedWork(
+        this, pending_task.delayed_run_time, now);
   }
 
   TraceQueueSize(false);
@@ -820,19 +816,10 @@
     return;
 
   if (enable) {
-    if (!main_thread_only().delayed_incoming_queue.empty()) {
-      LazyNow lazy_now = main_thread_only().time_domain->CreateLazyNow();
-      main_thread_only().time_domain->ScheduleDelayedWork(
-          this,
-          main_thread_only().delayed_incoming_queue.top().delayed_run_time,
-          &lazy_now);
-    }
     // Note it's the job of the selector to tell the TaskQueueManager if
-    // an immediate DoWork needs posting.
+    // a DoWork needs posting.
     main_thread_only().task_queue_manager->selector_.EnableQueue(this);
   } else {
-    if (!main_thread_only().delayed_incoming_queue.empty())
-      main_thread_only().time_domain->CancelDelayedWork(this);
     main_thread_only().task_queue_manager->selector_.DisableQueue(this);
   }
 }
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc
index 756416e..30c022e 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc
@@ -218,9 +218,10 @@
 
 void TaskQueueManager::MaybeScheduleDelayedWork(
     const tracked_objects::Location& from_here,
-    LazyNow* lazy_now,
-    base::TimeTicks run_time) {
+    base::TimeTicks now,
+    base::TimeDelta delay) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
+  DCHECK_GE(delay, base::TimeDelta());
   {
     base::AutoLock lock(any_thread_lock_);
 
@@ -235,31 +236,19 @@
   }
 
   // De-duplicate DoWork posts.
+  base::TimeTicks run_time = now + delay;
   if (next_delayed_do_work_ <= run_time && !next_delayed_do_work_.is_null())
     return;
 
-  cancelable_delayed_do_work_closure_.Reset(delayed_do_work_closure_);
-
-  base::TimeDelta delay =
-      std::max(base::TimeDelta(), run_time - lazy_now->Now());
-  next_delayed_do_work_ = lazy_now->Now() + delay;
-
   TRACE_EVENT1(tracing_category_, "MaybeScheduleDelayedWorkInternal",
                "delay_ms", delay.InMillisecondsF());
 
+  cancelable_delayed_do_work_closure_.Reset(delayed_do_work_closure_);
+  next_delayed_do_work_ = run_time;
   delegate_->PostDelayedTask(
       from_here, cancelable_delayed_do_work_closure_.callback(), delay);
 }
 
-void TaskQueueManager::CancelDelayedWork(base::TimeTicks run_time) {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
-  if (next_delayed_do_work_ != run_time)
-    return;
-
-  cancelable_delayed_do_work_closure_.Cancel();
-  next_delayed_do_work_ = base::TimeTicks();
-}
-
 void TaskQueueManager::DoWork(bool delayed) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
   TRACE_EVENT1(tracing_category_, "TaskQueueManager::DoWork", "delayed",
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h
index f4f57175..a180f00 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h
@@ -74,12 +74,8 @@
   // runner. These delayed tasks are de-duplicated. Must be called on the thread
   // this class was created on.
   void MaybeScheduleDelayedWork(const tracked_objects::Location& from_here,
-                                LazyNow* lazy_now,
-                                base::TimeTicks run_time);
-
-  // Cancels a delayed task to process work at |run_time|, previously requested
-  // with MaybeScheduleDelayedWork.
-  void CancelDelayedWork(base::TimeTicks run_time);
+                                base::TimeTicks now,
+                                base::TimeDelta delay);
 
   // Set the number of tasks executed in a single invocation of the task queue
   // manager. Increasing the batch size can reduce the overhead of yielding
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_perftest.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_perftest.cc
index 44963d0..a7f7454 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_perftest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_perftest.cc
@@ -42,17 +42,12 @@
     return base::TimeDelta();  // Makes DoWork post an immediate continuation.
   }
 
-  void RequestWakeupAt(LazyNow* lazy_now, base::TimeTicks run_time) override {
+  void RequestWakeup(base::TimeTicks now, base::TimeDelta delay) override {
     // De-dupe DoWorks.
     if (NumberOfScheduledWakeups() == 1u)
       RequestDoWork();
   }
 
-  void CancelWakeupAt(base::TimeTicks run_time) override {
-    // We didn't post a delayed task in RequestWakeupAt so there's no need to do
-    // anything here.
-  }
-
   const char* GetName() const override { return "PerfTestTimeDomain"; }
 
   DISALLOW_COPY_AND_ASSIGN(PerfTestTimeDomain);
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc
index 53d97289..79e17b6 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc
@@ -2413,65 +2413,5 @@
   run_loop.Run();
 }
 
-TEST_F(TaskQueueManagerTest, DelayedDoWorkNotPostedForDisabledQueue) {
-  Initialize(1u);
-
-  runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask),
-                               base::TimeDelta::FromMilliseconds(1));
-  ASSERT_TRUE(test_task_runner_->HasPendingTasks());
-  EXPECT_EQ(base::TimeDelta::FromMilliseconds(1),
-            test_task_runner_->DelayToNextTaskTime());
-
-  std::unique_ptr<TaskQueue::QueueEnabledVoter> voter =
-      runners_[0]->CreateQueueEnabledVoter();
-  voter->SetQueueEnabled(false);
-
-  EXPECT_TRUE(test_task_runner_->HasPendingTasks());
-  test_task_runner_->RemoveCancelledTasks();
-  EXPECT_FALSE(test_task_runner_->HasPendingTasks());
-
-  voter->SetQueueEnabled(true);
-  ASSERT_TRUE(test_task_runner_->HasPendingTasks());
-  EXPECT_EQ(base::TimeDelta::FromMilliseconds(1),
-            test_task_runner_->DelayToNextTaskTime());
-}
-
-TEST_F(TaskQueueManagerTest, DisablingQueuesChangesDelayTillNextDoWork) {
-  Initialize(3u);
-  runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask),
-                               base::TimeDelta::FromMilliseconds(1));
-  runners_[1]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask),
-                               base::TimeDelta::FromMilliseconds(10));
-  runners_[2]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask),
-                               base::TimeDelta::FromMilliseconds(100));
-
-  std::unique_ptr<TaskQueue::QueueEnabledVoter> voter0 =
-      runners_[0]->CreateQueueEnabledVoter();
-  std::unique_ptr<TaskQueue::QueueEnabledVoter> voter1 =
-      runners_[1]->CreateQueueEnabledVoter();
-  std::unique_ptr<TaskQueue::QueueEnabledVoter> voter2 =
-      runners_[2]->CreateQueueEnabledVoter();
-
-  ASSERT_TRUE(test_task_runner_->HasPendingTasks());
-  EXPECT_EQ(base::TimeDelta::FromMilliseconds(1),
-            test_task_runner_->DelayToNextTaskTime());
-
-  voter0->SetQueueEnabled(false);
-  test_task_runner_->RemoveCancelledTasks();
-  ASSERT_TRUE(test_task_runner_->HasPendingTasks());
-  EXPECT_EQ(base::TimeDelta::FromMilliseconds(10),
-            test_task_runner_->DelayToNextTaskTime());
-
-  voter1->SetQueueEnabled(false);
-  test_task_runner_->RemoveCancelledTasks();
-  ASSERT_TRUE(test_task_runner_->HasPendingTasks());
-  EXPECT_EQ(base::TimeDelta::FromMilliseconds(100),
-            test_task_runner_->DelayToNextTaskTime());
-
-  voter2->SetQueueEnabled(false);
-  test_task_runner_->RemoveCancelledTasks();
-  EXPECT_FALSE(test_task_runner_->HasPendingTasks());
-}
-
 }  // namespace scheduler
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/time_domain.cc b/third_party/WebKit/Source/platform/scheduler/base/time_domain.cc
index fd91193..d326318 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/time_domain.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/time_domain.cc
@@ -54,14 +54,14 @@
   // O(log n)
   delayed_wakeup_queue_.erase(queue->heap_handle());
 
-  LazyNow destination_lazy_now = destination_time_domain->CreateLazyNow();
+  base::TimeTicks destination_now = destination_time_domain->Now();
   destination_time_domain->ScheduleDelayedWork(queue, wake_up_time,
-                                               &destination_lazy_now);
+                                               destination_now);
 }
 
 void TimeDomain::ScheduleDelayedWork(internal::TaskQueueImpl* queue,
                                      base::TimeTicks delayed_run_time,
-                                     LazyNow* lazy_now) {
+                                     base::TimeTicks now) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
   // We only want to store a single wakeup per queue, so we need to remove any
   // previously registered wake up for |queue|.
@@ -79,32 +79,15 @@
   queue->set_scheduled_time_domain_wakeup(delayed_run_time);
 
   // If |queue| is the first wakeup then request the wakeup.
-  if (delayed_wakeup_queue_.min().queue == queue)
-    RequestWakeupAt(lazy_now, delayed_run_time);
+  if (delayed_wakeup_queue_.min().queue == queue) {
+    base::TimeDelta delay = std::max(base::TimeDelta(), delayed_run_time - now);
+    RequestWakeup(now, delay);
+  }
 
   if (observer_)
     observer_->OnTimeDomainHasDelayedWork(queue);
 }
 
-void TimeDomain::CancelDelayedWork(internal::TaskQueueImpl* queue) {
-  if (!queue->heap_handle().IsValid())
-    return;
-
-  DCHECK(!delayed_wakeup_queue_.empty());
-  base::TimeTicks prev_first_wakeup = delayed_wakeup_queue_.min().time;
-
-  // O(log n)
-  delayed_wakeup_queue_.erase(queue->heap_handle());
-
-  if (delayed_wakeup_queue_.empty()) {
-    CancelWakeupAt(prev_first_wakeup);
-  } else if (prev_first_wakeup != delayed_wakeup_queue_.min().time) {
-    LazyNow lazy_now = CreateLazyNow();
-    CancelWakeupAt(prev_first_wakeup);
-    RequestWakeupAt(&lazy_now, delayed_wakeup_queue_.min().time);
-  }
-}
-
 void TimeDomain::OnQueueHasImmediateWork(internal::TaskQueueImpl* queue) {
   if (observer_)
     observer_->OnTimeDomainHasImmediateWork(queue);
diff --git a/third_party/WebKit/Source/platform/scheduler/base/time_domain.h b/third_party/WebKit/Source/platform/scheduler/base/time_domain.h
index 67b23aca..4947fd5 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/time_domain.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/time_domain.h
@@ -95,10 +95,7 @@
   // registered wakeup for |queue|.
   void ScheduleDelayedWork(internal::TaskQueueImpl* queue,
                            base::TimeTicks delayed_run_time,
-                           LazyNow* lazy_now);
-
-  // Cancels any delayed work requested for |queue|.
-  void CancelDelayedWork(internal::TaskQueueImpl* queue);
+                           base::TimeTicks now);
 
   // Registers the |queue|.
   void RegisterQueue(internal::TaskQueueImpl* queue);
@@ -114,17 +111,12 @@
   virtual void OnRegisterWithTaskQueueManager(
       TaskQueueManager* task_queue_manager) = 0;
 
-  // The implementation will schedule task processing to run at time |run_time|
-  // within the TimeDomain's time line. Only called from the main thread.
+  // The implementaion will secedule task processing to run with |delay| with
+  // respect to the TimeDomain's time source.  Always called on the main thread.
   // NOTE this is only called by ScheduleDelayedWork if the scheduled runtime
   // is sooner than any previously sheduled work or if there is no other
   // scheduled work.
-  virtual void RequestWakeupAt(LazyNow* lazy_now, base::TimeTicks run_time) = 0;
-
-  // The implementation will cancel a wake up previously requested by
-  // RequestWakeupAt.  It's expected this will be a NOP for most virtual time
-  // domains.
-  virtual void CancelWakeupAt(base::TimeTicks run_time) = 0;
+  virtual void RequestWakeup(base::TimeTicks now, base::TimeDelta delay) = 0;
 
   // For implementation specific tracing.
   virtual void AsValueIntoInternal(
diff --git a/third_party/WebKit/Source/platform/scheduler/base/time_domain_unittest.cc b/third_party/WebKit/Source/platform/scheduler/base/time_domain_unittest.cc
index 4a8f0fe8..09a253c 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/time_domain_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/time_domain_unittest.cc
@@ -52,10 +52,7 @@
   void OnRegisterWithTaskQueueManager(
       TaskQueueManager* task_queue_manager) override {}
 
-  MOCK_METHOD2(RequestWakeupAt,
-               void(LazyNow* lazy_now, base::TimeTicks run_time));
-
-  MOCK_METHOD1(CancelWakeupAt, void(base::TimeTicks run_time));
+  MOCK_METHOD2(RequestWakeup, void(base::TimeTicks now, base::TimeDelta delay));
 
   void SetNow(base::TimeTicks now) { now_ = now; }
 
@@ -91,10 +88,9 @@
 TEST_F(TimeDomainTest, ScheduleDelayedWork) {
   base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10);
   base::TimeTicks delayed_runtime = time_domain_->Now() + delay;
-  EXPECT_CALL(*time_domain_.get(), RequestWakeupAt(_, delayed_runtime));
-  LazyNow lazy_now = time_domain_->CreateLazyNow();
-  time_domain_->ScheduleDelayedWork(task_queue_.get(), lazy_now.Now() + delay,
-                                    &lazy_now);
+  EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, delay));
+  base::TimeTicks now = time_domain_->Now();
+  time_domain_->ScheduleDelayedWork(task_queue_.get(), now + delay, now);
 
   base::TimeTicks next_scheduled_runtime;
   EXPECT_TRUE(time_domain_->NextScheduledRunTime(&next_scheduled_runtime));
@@ -110,10 +106,9 @@
   base::TimeDelta delay2 = base::TimeDelta::FromMilliseconds(100);
   base::TimeTicks delayed_runtime1 = time_domain_->Now() + delay1;
   base::TimeTicks delayed_runtime2 = time_domain_->Now() + delay2;
-  EXPECT_CALL(*time_domain_.get(), RequestWakeupAt(_, delayed_runtime1));
-  LazyNow lazy_now = time_domain_->CreateLazyNow();
-  time_domain_->ScheduleDelayedWork(task_queue_.get(), delayed_runtime1,
-                                    &lazy_now);
+  EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, delay1));
+  base::TimeTicks now = time_domain_->Now();
+  time_domain_->ScheduleDelayedWork(task_queue_.get(), delayed_runtime1, now);
 
   base::TimeTicks next_scheduled_runtime;
   EXPECT_TRUE(time_domain_->NextScheduledRunTime(&next_scheduled_runtime));
@@ -123,15 +118,14 @@
 
   // Now scheduler a later wakeup, which should replace the previously requested
   // one.
-  EXPECT_CALL(*time_domain_.get(), RequestWakeupAt(_, delayed_runtime2));
-  time_domain_->ScheduleDelayedWork(task_queue_.get(), delayed_runtime2,
-                                    &lazy_now);
+  EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, delay2));
+  time_domain_->ScheduleDelayedWork(task_queue_.get(), delayed_runtime2, now);
 
   EXPECT_TRUE(time_domain_->NextScheduledRunTime(&next_scheduled_runtime));
   EXPECT_EQ(delayed_runtime2, next_scheduled_runtime);
 }
 
-TEST_F(TimeDomainTest, RequestWakeupAt_OnlyCalledForEarlierTasks) {
+TEST_F(TimeDomainTest, RequestWakeup_OnlyCalledForEarlierTasks) {
   scoped_refptr<internal::TaskQueueImpl> task_queue2 = make_scoped_refptr(
       new internal::TaskQueueImpl(nullptr, time_domain_.get(),
                                   TaskQueue::Spec(TaskQueue::QueueType::TEST),
@@ -152,26 +146,22 @@
   base::TimeDelta delay3 = base::TimeDelta::FromMilliseconds(30);
   base::TimeDelta delay4 = base::TimeDelta::FromMilliseconds(1);
 
-  // RequestWakeupAt should always be called if there are no other wakeups.
-  LazyNow lazy_now = time_domain_->CreateLazyNow();
-  EXPECT_CALL(*time_domain_.get(), RequestWakeupAt(_, lazy_now.Now() + delay1));
-  time_domain_->ScheduleDelayedWork(task_queue_.get(), lazy_now.Now() + delay1,
-                                    &lazy_now);
+  // RequestWakeup should always be called if there are no other wakeups.
+  EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, delay1));
+  base::TimeTicks now = time_domain_->Now();
+  time_domain_->ScheduleDelayedWork(task_queue_.get(), now + delay1, now);
 
   Mock::VerifyAndClearExpectations(time_domain_.get());
 
-  // RequestWakeupAt should not be called when scheduling later tasks.
-  EXPECT_CALL(*time_domain_.get(), RequestWakeupAt(_, _)).Times(0);
-  time_domain_->ScheduleDelayedWork(task_queue2.get(), lazy_now.Now() + delay2,
-                                    &lazy_now);
-  time_domain_->ScheduleDelayedWork(task_queue3.get(), lazy_now.Now() + delay3,
-                                    &lazy_now);
+  // RequestWakeup should not be called when scheduling later tasks.
+  EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, _)).Times(0);
+  time_domain_->ScheduleDelayedWork(task_queue2.get(), now + delay2, now);
+  time_domain_->ScheduleDelayedWork(task_queue3.get(), now + delay3, now);
 
-  // RequestWakeupAt should be called when scheduling earlier tasks.
+  // RequestWakeup should be called when scheduling earlier tasks.
   Mock::VerifyAndClearExpectations(time_domain_.get());
-  EXPECT_CALL(*time_domain_.get(), RequestWakeupAt(_, lazy_now.Now() + delay4));
-  time_domain_->ScheduleDelayedWork(task_queue4.get(), lazy_now.Now() + delay4,
-                                    &lazy_now);
+  EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, delay4));
+  time_domain_->ScheduleDelayedWork(task_queue4.get(), now + delay4, now);
 
   task_queue2->UnregisterTaskQueue();
   task_queue3->UnregisterTaskQueue();
@@ -184,14 +174,12 @@
                                   TaskQueue::Spec(TaskQueue::QueueType::TEST),
                                   "test.category", "test.category"));
 
-  EXPECT_CALL(*time_domain_.get(), RequestWakeupAt(_, _)).Times(1);
-  LazyNow lazy_now = time_domain_->CreateLazyNow();
+  EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, _)).Times(1);
+  base::TimeTicks now = time_domain_->Now();
   time_domain_->ScheduleDelayedWork(
-      task_queue_.get(), lazy_now.Now() + base::TimeDelta::FromMilliseconds(10),
-      &lazy_now);
+      task_queue_.get(), now + base::TimeDelta::FromMilliseconds(10), now);
   time_domain_->ScheduleDelayedWork(
-      task_queue2_.get(),
-      lazy_now.Now() + base::TimeDelta::FromMilliseconds(100), &lazy_now);
+      task_queue2_.get(), now + base::TimeDelta::FromMilliseconds(100), now);
 
   TaskQueue* next_task_queue;
   EXPECT_TRUE(time_domain_->NextScheduledTaskQueue(&next_task_queue));
@@ -208,16 +196,16 @@
 
 TEST_F(TimeDomainTest, WakeupReadyDelayedQueues) {
   base::TimeDelta delay = base::TimeDelta::FromMilliseconds(50);
-  LazyNow lazy_now = time_domain_->CreateLazyNow();
-  base::TimeTicks delayed_runtime = lazy_now.Now() + delay;
-  EXPECT_CALL(*time_domain_.get(), RequestWakeupAt(_, delayed_runtime));
-  time_domain_->ScheduleDelayedWork(task_queue_.get(), delayed_runtime,
-                                    &lazy_now);
+  EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, delay));
+  base::TimeTicks now = time_domain_->Now();
+  base::TimeTicks delayed_runtime = now + delay;
+  time_domain_->ScheduleDelayedWork(task_queue_.get(), delayed_runtime, now);
 
   base::TimeTicks next_run_time;
   ASSERT_TRUE(time_domain_->NextScheduledRunTime(&next_run_time));
   EXPECT_EQ(delayed_runtime, next_run_time);
 
+  LazyNow lazy_now = time_domain_->CreateLazyNow();
   time_domain_->WakeupReadyDelayedQueues(&lazy_now);
   ASSERT_TRUE(time_domain_->NextScheduledRunTime(&next_run_time));
   EXPECT_EQ(delayed_runtime, next_run_time);
@@ -255,11 +243,10 @@
 
 TEST_F(TimeDomainWithObserverTest, OnTimeDomainHasDelayedWork) {
   EXPECT_CALL(*observer_, OnTimeDomainHasDelayedWork(task_queue_.get()));
-  EXPECT_CALL(*time_domain_.get(), RequestWakeupAt(_, _));
-  LazyNow lazy_now = time_domain_->CreateLazyNow();
+  EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, _));
+  base::TimeTicks now = time_domain_->Now();
   time_domain_->ScheduleDelayedWork(
-      task_queue_.get(), lazy_now.Now() + base::TimeDelta::FromMilliseconds(10),
-      &lazy_now);
+      task_queue_.get(), now + base::TimeDelta::FromMilliseconds(10), now);
 }
 
 }  // namespace scheduler
diff --git a/third_party/WebKit/Source/platform/scheduler/base/virtual_time_domain.cc b/third_party/WebKit/Source/platform/scheduler/base/virtual_time_domain.cc
index 9b172b6..f40c6307 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/virtual_time_domain.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/virtual_time_domain.cc
@@ -34,17 +34,13 @@
   return now_;
 }
 
-void VirtualTimeDomain::RequestWakeupAt(LazyNow* lazy_now,
-                                        base::TimeTicks run_time) {
+void VirtualTimeDomain::RequestWakeup(base::TimeTicks now,
+                                      base::TimeDelta delay) {
   // We don't need to do anything here because the caller of AdvanceTo is
   // responsible for calling TaskQueueManager::MaybeScheduleImmediateWork if
   // needed.
 }
 
-void VirtualTimeDomain::CancelWakeupAt(base::TimeTicks run_time) {
-  // We ignore this because RequestWakeupAt is a NOP.
-}
-
 base::Optional<base::TimeDelta> VirtualTimeDomain::DelayTillNextTask(
     LazyNow* lazy_now) {
   return base::Optional<base::TimeDelta>();
diff --git a/third_party/WebKit/Source/platform/scheduler/base/virtual_time_domain.h b/third_party/WebKit/Source/platform/scheduler/base/virtual_time_domain.h
index 2cd7069..a841226 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/virtual_time_domain.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/virtual_time_domain.h
@@ -32,8 +32,7 @@
  protected:
   void OnRegisterWithTaskQueueManager(
       TaskQueueManager* task_queue_manager) override;
-  void RequestWakeupAt(LazyNow* lazy_now, base::TimeTicks run_time) override;
-  void CancelWakeupAt(base::TimeTicks run_time) override;
+  void RequestWakeup(base::TimeTicks now, base::TimeDelta delay) override;
   void AsValueIntoInternal(
       base::trace_event::TracedValue* state) const override;
 
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain.cc b/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain.cc
index 86dd975..455a0c2d 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain.cc
@@ -24,18 +24,14 @@
   return base::TimeDelta();  // Makes DoWork post an immediate continuation.
 }
 
-void AutoAdvancingVirtualTimeDomain::RequestWakeupAt(LazyNow* lazy_now,
-                                                     base::TimeTicks run_time) {
+void AutoAdvancingVirtualTimeDomain::RequestWakeup(base::TimeTicks now,
+                                                   base::TimeDelta delay) {
   // Avoid posting pointless DoWorks.  I.e. if the time domain has more then one
   // scheduled wake up then we don't need to do anything.
   if (can_advance_virtual_time_ && NumberOfScheduledWakeups() == 1u)
     RequestDoWork();
 }
 
-void AutoAdvancingVirtualTimeDomain::CancelWakeupAt(base::TimeTicks run_time) {
-  // We ignore this because RequestWakeupAt doesn't post a delayed task.
-}
-
 void AutoAdvancingVirtualTimeDomain::SetCanAdvanceVirtualTime(
     bool can_advance_virtual_time) {
   can_advance_virtual_time_ = can_advance_virtual_time;
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain.h b/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain.h
index 854cf0f..0ca186d 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain.h
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain.h
@@ -28,8 +28,7 @@
 
   // TimeDomain implementation:
   base::Optional<base::TimeDelta> DelayTillNextTask(LazyNow* lazy_now) override;
-  void RequestWakeupAt(LazyNow* lazy_now, base::TimeTicks run_time) override;
-  void CancelWakeupAt(base::TimeTicks run_time) override;
+  void RequestWakeup(base::TimeTicks now, base::TimeDelta delay) override;
   const char* GetName() const override;
 
   // Controls whether or not virtual time is allowed to advance, when the
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/throttled_time_domain.cc b/third_party/WebKit/Source/platform/scheduler/renderer/throttled_time_domain.cc
index 461d1857e..db1d088 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/throttled_time_domain.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/throttled_time_domain.cc
@@ -17,16 +17,12 @@
   return "ThrottledTimeDomain";
 }
 
-void ThrottledTimeDomain::RequestWakeupAt(LazyNow* lazy_now,
-                                          base::TimeTicks run_time) {
+void ThrottledTimeDomain::RequestWakeup(base::TimeTicks now,
+                                        base::TimeDelta delay) {
   // We assume the owner (i.e. TaskQueueThrottler) will manage wakeups on our
   // behalf.
 }
 
-void ThrottledTimeDomain::CancelWakeupAt(base::TimeTicks run_time) {
-  // We ignore this because RequestWakeupAt is a NOP.
-}
-
 base::Optional<base::TimeDelta> ThrottledTimeDomain::DelayTillNextTask(
     LazyNow* lazy_now) {
   base::TimeTicks next_run_time;
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/throttled_time_domain.h b/third_party/WebKit/Source/platform/scheduler/renderer/throttled_time_domain.h
index a3e754b..c9d73fa 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/throttled_time_domain.h
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/throttled_time_domain.h
@@ -21,8 +21,7 @@
 
   // TimeDomain implementation:
   const char* GetName() const override;
-  void RequestWakeupAt(LazyNow* lazy_now, base::TimeTicks run_time) override;
-  void CancelWakeupAt(base::TimeTicks run_time) override;
+  void RequestWakeup(base::TimeTicks now, base::TimeDelta delay) override;
   base::Optional<base::TimeDelta> DelayTillNextTask(LazyNow* lazy_now) override;
 
   using TimeDomain::WakeupReadyDelayedQueues;
diff --git a/third_party/WebKit/Source/platform/scroll/Scrollbar.cpp b/third_party/WebKit/Source/platform/scroll/Scrollbar.cpp
index 37326e0..a246461 100644
--- a/third_party/WebKit/Source/platform/scroll/Scrollbar.cpp
+++ b/third_party/WebKit/Source/platform/scroll/Scrollbar.cpp
@@ -477,12 +477,11 @@
     if (isCaptured)
       m_scrollableArea->mouseReleasedScrollbar();
 
-    // m_hoveredPart won't be updated until the next mouseMoved or mouseDown, so
-    // we have to hit test to really know if the mouse has exited the scrollbar
-    // on a mouseUp.
     ScrollbarPart part = theme().hitTest(*this, mouseEvent.position());
-    if (part == NoPart)
+    if (part == NoPart) {
+      setHoveredPart(NoPart);
       m_scrollableArea->mouseExitedScrollbar(*this);
+    }
   }
 }
 
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeOverlayMock.h b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeOverlayMock.h
index d787720..1022c2b 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeOverlayMock.h
+++ b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeOverlayMock.h
@@ -58,6 +58,11 @@
     ScrollbarThemeOverlay::paintThumb(gc, scrollbar, rect);
   }
 
+  bool shouldSnapBackToDragOrigin(const ScrollbarThemeClient& scrollbar,
+                                  const PlatformMouseEvent& evt) override {
+    return false;
+  }
+
  private:
   double m_delayInSeconds;
   bool isMockTheme() const final { return true; }
diff --git a/third_party/WebKit/Source/platform/testing/RuntimeEnabledFeaturesTestHelpers.h b/third_party/WebKit/Source/platform/testing/RuntimeEnabledFeaturesTestHelpers.h
index 151543e..38cba4d 100644
--- a/third_party/WebKit/Source/platform/testing/RuntimeEnabledFeaturesTestHelpers.h
+++ b/third_party/WebKit/Source/platform/testing/RuntimeEnabledFeaturesTestHelpers.h
@@ -52,6 +52,10 @@
     RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled,
     RuntimeEnabledFeatures::setSlimmingPaintInvalidationEnabled>
     ScopedSlimmingPaintInvalidationForTest;
+typedef ScopedRuntimeEnabledFeatureForTest<
+    RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled,
+    RuntimeEnabledFeatures::setPaintUnderInvalidationCheckingEnabled>
+    ScopedPaintUnderInvalidationCheckingForTest;
 
 }  // namespace blink
 
diff --git a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp
index fe48cb9..42251b0 100644
--- a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp
+++ b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp
@@ -217,10 +217,6 @@
               m_mockTaskRunner,
               base::WrapUnique(new scheduler::TestTimeSource(m_clock.get()))))),
       m_thread(m_scheduler->CreateMainThread()) {
-  // We need a non-zero start time because LazyNow in the blink scheduler can't
-  // be initialized with time t = 0;
-  m_clock->Advance(base::TimeDelta::FromSeconds(1));
-
   // Set the work batch size to one so RunPendingTasks behaves as expected.
   m_scheduler->GetSchedulerHelperForTesting()->SetWorkBatchSizeForTesting(1);
 
diff --git a/third_party/WebKit/Source/web/ChromeClientImpl.h b/third_party/WebKit/Source/web/ChromeClientImpl.h
index 72f565e..0bd2249 100644
--- a/third_party/WebKit/Source/web/ChromeClientImpl.h
+++ b/third_party/WebKit/Source/web/ChromeClientImpl.h
@@ -155,7 +155,8 @@
 
   void enterFullscreen(LocalFrame&) override;
   void exitFullscreen(LocalFrame&) override;
-  void fullscreenElementChanged(Element*, Element*) override;
+  void fullscreenElementChanged(Element* fromElement,
+                                Element* toElement) override;
 
   void clearCompositedSelection(LocalFrame*) override;
   void updateCompositedSelection(LocalFrame*,
diff --git a/third_party/WebKit/Source/web/FullscreenController.cpp b/third_party/WebKit/Source/web/FullscreenController.cpp
index 4099914..bc592d2 100644
--- a/third_party/WebKit/Source/web/FullscreenController.cpp
+++ b/third_party/WebKit/Source/web/FullscreenController.cpp
@@ -88,6 +88,9 @@
         fullscreen->didEnterFullscreen();
     }
   }
+
+  // TODO(foolip): If the top level browsing context (main frame) ends up with
+  // no fullscreen element, exit fullscreen again to recover.
 }
 
 void FullscreenController::didExitFullscreen() {
@@ -100,33 +103,32 @@
 
   updatePageScaleConstraints(true);
 
-  // Set |m_state| so that any |exitFullscreen()| calls from within
-  // |Fullscreen::didExitFullscreen()| do not call
-  // |WebFrameClient::exitFullscreen()| again.
-  // TODO(foolip): Remove this when state changes and events are synchronized
-  // with animation frames. https://crbug.com/402376
-  m_state = State::ExitingFullscreen;
-
-  // Notify all local frames that we have exited fullscreen.
-  // TODO(foolip): This should only need to notify the topmost local roots. That
-  // doesn't currently work because |Fullscreen::m_currentFullScreenElement|
-  // isn't set for the topmost document when an iframe goes fullscreen, but can
-  // be done once |m_currentFullScreenElement| is gone and all state is in the
-  // fullscreen element stack. https://crbug.com/402421
-  for (Frame* frame = m_webViewImpl->page()->mainFrame(); frame;
-       frame = frame->tree().traverseNext()) {
-    if (!frame->isLocalFrame())
-      continue;
-    if (Document* document = toLocalFrame(frame)->document()) {
-      if (Fullscreen* fullscreen = Fullscreen::fromIfExists(*document))
-        fullscreen->didExitFullscreen();
-    }
-  }
-
   // We need to wait until style and layout are updated in order to properly
   // restore scroll offsets since content may not be overflowing in the same way
   // until they are.
   m_state = State::NeedsScrollAndScaleRestore;
+
+  // Notify the topmost local frames that we have exited fullscreen.
+  // |Fullscreen::didExitFullscreen()| will take care of descendant frames.
+  for (Frame* frame = m_webViewImpl->page()->mainFrame(); frame;) {
+    Frame* nextFrame = frame->tree().traverseNext();
+
+    if (frame->isRemoteFrame()) {
+      frame = nextFrame;
+      continue;
+    }
+
+    DCHECK(frame->isLocalRoot());
+    if (Document* document = toLocalFrame(frame)->document()) {
+      if (Fullscreen* fullscreen = Fullscreen::fromIfExists(*document))
+        fullscreen->didExitFullscreen();
+    }
+
+    // Skip over all descendant frames.
+    while (nextFrame && nextFrame->tree().isDescendantOf(frame))
+      nextFrame = nextFrame->tree().traverseNext();
+    frame = nextFrame;
+  }
 }
 
 void FullscreenController::enterFullscreen(LocalFrame& frame) {
@@ -183,7 +185,7 @@
   DCHECK_NE(fromElement, toElement);
 
   if (toElement) {
-    DCHECK(Fullscreen::isCurrentFullScreenElement(*toElement));
+    DCHECK(Fullscreen::isFullscreenElement(*toElement));
 
     if (isHTMLVideoElement(*toElement)) {
       HTMLVideoElement& videoElement = toHTMLVideoElement(*toElement);
@@ -199,7 +201,7 @@
   }
 
   if (fromElement) {
-    DCHECK(!Fullscreen::isCurrentFullScreenElement(*fromElement));
+    DCHECK(!Fullscreen::isFullscreenElement(*fromElement));
 
     if (isHTMLVideoElement(*fromElement)) {
       // If the video used overlay fullscreen mode, restore the transparency.
diff --git a/third_party/WebKit/Source/web/FullscreenController.h b/third_party/WebKit/Source/web/FullscreenController.h
index 4ffbd6d..de3e34d 100644
--- a/third_party/WebKit/Source/web/FullscreenController.h
+++ b/third_party/WebKit/Source/web/FullscreenController.h
@@ -58,7 +58,7 @@
 
   // Called by Fullscreen (via ChromeClient) to notify that the fullscreen
   // element has changed.
-  void fullscreenElementChanged(Element*, Element*);
+  void fullscreenElementChanged(Element* fromElement, Element* toElement);
 
   bool isFullscreen() { return m_state == State::Fullscreen; }
 
diff --git a/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp b/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
index 1bbd586..5660cd4 100644
--- a/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
+++ b/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
@@ -311,7 +311,7 @@
 }
 
 bool WebPluginContainerImpl::isFullscreenElement() const {
-  return Fullscreen::isCurrentFullScreenElement(*m_element);
+  return Fullscreen::isFullscreenElement(*m_element);
 }
 
 void WebPluginContainerImpl::cancelFullscreen() {
diff --git a/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp b/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp
index 562ce9f..c252b26 100644
--- a/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp
+++ b/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp
@@ -509,24 +509,21 @@
   HTMLFrameOwnerElement* ownerElement =
       toHTMLFrameOwnerElement(frame()->owner());
 
-  // Call requestFullscreen() on |ownerElement| to make it the provisional
-  // fullscreen element in FullscreenController, and to prepare
-  // fullscreenchange events that will need to fire on it and its (local)
-  // ancestors. The events will be triggered if/when fullscreen is entered.
+  // Call |requestFullscreen()| on |ownerElement| to make it the pending
+  // fullscreen element in anticipation of the coming |didEnterFullscreen()|
+  // call.
   //
-  // Passing |forCrossProcessAncestor| to requestFullscreen is necessary
-  // because:
-  // - |ownerElement| will need :-webkit-full-screen-ancestor style in
-  //   addition to :-webkit-full-screen.
-  // - there's no need to resend the ToggleFullscreen IPC to the browser
-  //   process.
+  // PrefixedForCrossProcessDescendant is necessary because:
+  //  - The fullscreen element ready check and other checks should be bypassed.
+  //  - |ownerElement| will need :-webkit-full-screen-ancestor style in addition
+  //    to :-webkit-full-screen.
   //
   // TODO(alexmos): currently, this assumes prefixed requests, but in the
   // future, this should plumb in information about which request type
   // (prefixed or unprefixed) to use for firing fullscreen events.
-  Fullscreen::requestFullscreen(*ownerElement,
-                                Fullscreen::RequestType::Prefixed,
-                                true /* forCrossProcessAncestor */);
+  Fullscreen::requestFullscreen(
+      *ownerElement,
+      Fullscreen::RequestType::PrefixedForCrossProcessDescendant);
 }
 
 WebRemoteFrameImpl::WebRemoteFrameImpl(WebTreeScopeType scope,
diff --git a/third_party/WebKit/Source/web/WebViewImpl.h b/third_party/WebKit/Source/web/WebViewImpl.h
index 657760e..2ae2324 100644
--- a/third_party/WebKit/Source/web/WebViewImpl.h
+++ b/third_party/WebKit/Source/web/WebViewImpl.h
@@ -448,7 +448,7 @@
 
   void enterFullscreen(LocalFrame&);
   void exitFullscreen(LocalFrame&);
-  void fullscreenElementChanged(Element*, Element*);
+  void fullscreenElementChanged(Element* fromElement, Element* toElement);
 
   // Exposed for the purpose of overriding device metrics.
   void sendResizeEventAndRepaint();
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
index a20e959..f3236b1 100644
--- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -7698,14 +7698,11 @@
   UserGestureIndicator gesture(DocumentUserGestureToken::create(document));
   Element* divFullscreen = document->getElementById("div1");
   Fullscreen::requestFullscreen(*divFullscreen);
-  EXPECT_EQ(nullptr, Fullscreen::currentFullScreenElementFrom(*document));
-  EXPECT_EQ(divFullscreen, Fullscreen::fullscreenElementFrom(*document));
   webViewImpl->didEnterFullscreen();
-  EXPECT_EQ(divFullscreen, Fullscreen::currentFullScreenElementFrom(*document));
+  EXPECT_EQ(nullptr, Fullscreen::fullscreenElementFrom(*document));
+  webViewImpl->beginFrame(WTF::monotonicallyIncreasingTime());
   EXPECT_EQ(divFullscreen, Fullscreen::fullscreenElementFrom(*document));
   webViewImpl->updateAllLifecyclePhases();
-  EXPECT_EQ(divFullscreen, Fullscreen::currentFullScreenElementFrom(*document));
-  EXPECT_EQ(divFullscreen, Fullscreen::fullscreenElementFrom(*document));
 
   // Verify that the element is sized to the viewport.
   LayoutFullScreen* fullscreenLayoutObject =
@@ -7738,14 +7735,11 @@
   UserGestureIndicator gesture(DocumentUserGestureToken::create(document));
   Element* divFullscreen = document->getElementById("div1");
   Fullscreen::requestFullscreen(*divFullscreen);
-  EXPECT_EQ(nullptr, Fullscreen::currentFullScreenElementFrom(*document));
-  EXPECT_EQ(divFullscreen, Fullscreen::fullscreenElementFrom(*document));
   webViewImpl->didEnterFullscreen();
-  EXPECT_EQ(divFullscreen, Fullscreen::currentFullScreenElementFrom(*document));
+  EXPECT_EQ(nullptr, Fullscreen::fullscreenElementFrom(*document));
+  webViewImpl->beginFrame(WTF::monotonicallyIncreasingTime());
   EXPECT_EQ(divFullscreen, Fullscreen::fullscreenElementFrom(*document));
   webViewImpl->updateAllLifecyclePhases();
-  EXPECT_EQ(divFullscreen, Fullscreen::currentFullScreenElementFrom(*document));
-  EXPECT_EQ(divFullscreen, Fullscreen::fullscreenElementFrom(*document));
 
   // Verify that the viewports are nonscrollable.
   FrameView* frameView = webViewHelper.webView()->mainFrameImpl()->frameView();
@@ -7762,14 +7756,11 @@
   ASSERT_FALSE(visualViewportScrollLayer->userScrollableVertical());
 
   // Verify that the viewports are scrollable upon exiting fullscreen.
-  EXPECT_EQ(divFullscreen, Fullscreen::currentFullScreenElementFrom(*document));
-  EXPECT_EQ(divFullscreen, Fullscreen::fullscreenElementFrom(*document));
   webViewImpl->didExitFullscreen();
-  EXPECT_EQ(nullptr, Fullscreen::currentFullScreenElementFrom(*document));
+  EXPECT_EQ(divFullscreen, Fullscreen::fullscreenElementFrom(*document));
+  webViewImpl->beginFrame(WTF::monotonicallyIncreasingTime());
   EXPECT_EQ(nullptr, Fullscreen::fullscreenElementFrom(*document));
   webViewImpl->updateAllLifecyclePhases();
-  EXPECT_EQ(nullptr, Fullscreen::currentFullScreenElementFrom(*document));
-  EXPECT_EQ(nullptr, Fullscreen::fullscreenElementFrom(*document));
   ASSERT_TRUE(layoutViewportScrollLayer->userScrollableHorizontal());
   ASSERT_TRUE(layoutViewportScrollLayer->userScrollableVertical());
   ASSERT_TRUE(visualViewportScrollLayer->userScrollableHorizontal());
@@ -7791,20 +7782,12 @@
   Document* document = webViewImpl->mainFrameImpl()->frame()->document();
   UserGestureIndicator gesture(DocumentUserGestureToken::create(document));
   Fullscreen::requestFullscreen(*document->documentElement());
-  EXPECT_EQ(nullptr, Fullscreen::currentFullScreenElementFrom(*document));
-  EXPECT_EQ(document->documentElement(),
-            Fullscreen::fullscreenElementFrom(*document));
   webViewImpl->didEnterFullscreen();
-  EXPECT_EQ(document->documentElement(),
-            Fullscreen::currentFullScreenElementFrom(*document));
+  EXPECT_EQ(nullptr, Fullscreen::fullscreenElementFrom(*document));
+  webViewImpl->beginFrame(WTF::monotonicallyIncreasingTime());
   EXPECT_EQ(document->documentElement(),
             Fullscreen::fullscreenElementFrom(*document));
-
   webViewImpl->updateAllLifecyclePhases();
-  EXPECT_EQ(document->documentElement(),
-            Fullscreen::currentFullScreenElementFrom(*document));
-  EXPECT_EQ(document->documentElement(),
-            Fullscreen::fullscreenElementFrom(*document));
 
   // Verify that the main frame is still scrollable.
   WebLayer* webScrollLayer =
@@ -7843,6 +7826,7 @@
   Element* divFullscreen = document->getElementById("div1");
   Fullscreen::requestFullscreen(*divFullscreen);
   webViewImpl->didEnterFullscreen();
+  webViewImpl->beginFrame(WTF::monotonicallyIncreasingTime());
   webViewImpl->updateAllLifecyclePhases();
 
   // Verify that the element is sized to the viewport.
@@ -7884,6 +7868,11 @@
     Fullscreen::requestFullscreen(*topBody);
   }
   webViewImpl->didEnterFullscreen();
+  EXPECT_EQ(nullptr, Fullscreen::fullscreenElementFrom(*topDoc));
+  EXPECT_EQ(nullptr, Fullscreen::fullscreenElementFrom(*iframeDoc));
+  webViewImpl->beginFrame(WTF::monotonicallyIncreasingTime());
+  EXPECT_EQ(topBody, Fullscreen::fullscreenElementFrom(*topDoc));
+  EXPECT_EQ(nullptr, Fullscreen::fullscreenElementFrom(*iframeDoc));
   webViewImpl->updateAllLifecyclePhases();
 
   {
@@ -7891,23 +7880,25 @@
     Fullscreen::requestFullscreen(*iframeBody);
   }
   webViewImpl->didEnterFullscreen();
+  EXPECT_EQ(topBody, Fullscreen::fullscreenElementFrom(*topDoc));
+  EXPECT_EQ(nullptr, Fullscreen::fullscreenElementFrom(*iframeDoc));
+  webViewImpl->beginFrame(WTF::monotonicallyIncreasingTime());
+  EXPECT_EQ(iframe, Fullscreen::fullscreenElementFrom(*topDoc));
+  EXPECT_EQ(iframeBody, Fullscreen::fullscreenElementFrom(*iframeDoc));
   webViewImpl->updateAllLifecyclePhases();
 
   // We are now in nested fullscreen, with both documents having a non-empty
   // fullscreen element stack.
-  EXPECT_EQ(topBody, Fullscreen::currentFullScreenElementFrom(*topDoc));
-  EXPECT_EQ(iframe, Fullscreen::fullscreenElementFrom(*topDoc));
-  EXPECT_EQ(iframeBody, Fullscreen::currentFullScreenElementFrom(*iframeDoc));
-  EXPECT_EQ(iframeBody, Fullscreen::fullscreenElementFrom(*iframeDoc));
 
   webViewImpl->didExitFullscreen();
+  EXPECT_EQ(iframe, Fullscreen::fullscreenElementFrom(*topDoc));
+  EXPECT_EQ(iframeBody, Fullscreen::fullscreenElementFrom(*iframeDoc));
+  webViewImpl->beginFrame(WTF::monotonicallyIncreasingTime());
+  EXPECT_EQ(nullptr, Fullscreen::fullscreenElementFrom(*topDoc));
+  EXPECT_EQ(nullptr, Fullscreen::fullscreenElementFrom(*iframeDoc));
   webViewImpl->updateAllLifecyclePhases();
 
-  // We should now have fully exited fullscreen.
-  EXPECT_EQ(nullptr, Fullscreen::currentFullScreenElementFrom(*topDoc));
-  EXPECT_EQ(nullptr, Fullscreen::fullscreenElementFrom(*topDoc));
-  EXPECT_EQ(nullptr, Fullscreen::currentFullScreenElementFrom(*iframeDoc));
-  EXPECT_EQ(nullptr, Fullscreen::fullscreenElementFrom(*iframeDoc));
+  // We have now fully exited fullscreen.
 }
 
 TEST_P(ParameterizedWebFrameTest, FullscreenWithTinyViewport) {
@@ -7936,6 +7927,7 @@
   UserGestureIndicator gesture(DocumentUserGestureToken::create(document));
   Fullscreen::requestFullscreen(*document->documentElement());
   webViewImpl->didEnterFullscreen();
+  webViewImpl->beginFrame(WTF::monotonicallyIncreasingTime());
   webViewImpl->updateAllLifecyclePhases();
   EXPECT_EQ(384, layoutViewItem.logicalWidth().floor());
   EXPECT_EQ(640, layoutViewItem.logicalHeight().floor());
@@ -7944,6 +7936,7 @@
   EXPECT_FLOAT_EQ(1.0, webViewImpl->maximumPageScaleFactor());
 
   webViewImpl->didExitFullscreen();
+  webViewImpl->beginFrame(WTF::monotonicallyIncreasingTime());
   webViewImpl->updateAllLifecyclePhases();
   EXPECT_EQ(320, layoutViewItem.logicalWidth().floor());
   EXPECT_EQ(533, layoutViewItem.logicalHeight().floor());
@@ -7972,6 +7965,7 @@
   UserGestureIndicator gesture(DocumentUserGestureToken::create(document));
   Fullscreen::requestFullscreen(*document->documentElement());
   webViewImpl->didEnterFullscreen();
+  webViewImpl->beginFrame(WTF::monotonicallyIncreasingTime());
   webViewImpl->updateAllLifecyclePhases();
   EXPECT_EQ(384, layoutViewItem.logicalWidth().floor());
   EXPECT_EQ(640, layoutViewItem.logicalHeight().floor());
@@ -7992,6 +7986,7 @@
   EXPECT_FLOAT_EQ(1.0, webViewImpl->maximumPageScaleFactor());
 
   webViewImpl->didExitFullscreen();
+  webViewImpl->beginFrame(WTF::monotonicallyIncreasingTime());
   webViewImpl->updateAllLifecyclePhases();
   EXPECT_EQ(320, layoutViewItem.logicalWidth().floor());
   EXPECT_EQ(192, layoutViewItem.logicalHeight().floor());
@@ -8035,6 +8030,7 @@
   }
 
   webViewImpl->didEnterFullscreen();
+  webViewImpl->beginFrame(WTF::monotonicallyIncreasingTime());
   webViewImpl->updateAllLifecyclePhases();
   client.m_screenInfo.rect.width = screenSizeMinusStatusBars.width;
   client.m_screenInfo.rect.height = screenSizeMinusStatusBars.height;
@@ -8049,6 +8045,7 @@
   EXPECT_FLOAT_EQ(1.0, webViewImpl->maximumPageScaleFactor());
 
   webViewImpl->didExitFullscreen();
+  webViewImpl->beginFrame(WTF::monotonicallyIncreasingTime());
   webViewImpl->updateAllLifecyclePhases();
   client.m_screenInfo.rect.width = screenSizeMinusStatusBars.width;
   client.m_screenInfo.rect.height = screenSizeMinusStatusBars.height;
@@ -8094,6 +8091,7 @@
       DocumentUserGestureToken::create(document, UserGestureToken::NewGesture));
   Fullscreen::requestFullscreen(*document->documentElement());
   webViewImpl->didEnterFullscreen();
+  webViewImpl->beginFrame(WTF::monotonicallyIncreasingTime());
   webViewImpl->updateAllLifecyclePhases();
 
   // Entering fullscreen causes layout size and page scale limits to be
@@ -8111,6 +8109,7 @@
   WebFrame* frame = webViewHelper.webView()->mainFrame();
   FrameTestHelpers::loadHTMLString(frame, source, testURL);
   webViewImpl->didExitFullscreen();
+  webViewImpl->beginFrame(WTF::monotonicallyIncreasingTime());
   webViewImpl->updateAllLifecyclePhases();
 
   // Make sure the new page's layout size and scale factor limits aren't
@@ -8158,19 +8157,23 @@
   HTMLVideoElement* video =
       toHTMLVideoElement(document->getElementById("video"));
   EXPECT_TRUE(video->usesOverlayFullscreenVideo());
-  EXPECT_FALSE(video->isFullscreen());
-  EXPECT_FALSE(layerTreeView.hasTransparentBackground);
 
   video->webkitEnterFullscreen();
   webViewImpl->didEnterFullscreen();
-  webViewImpl->updateAllLifecyclePhases();
-  EXPECT_TRUE(video->isFullscreen());
-  EXPECT_TRUE(layerTreeView.hasTransparentBackground);
-
-  webViewImpl->didExitFullscreen();
-  webViewImpl->updateAllLifecyclePhases();
   EXPECT_FALSE(video->isFullscreen());
   EXPECT_FALSE(layerTreeView.hasTransparentBackground);
+  webViewImpl->beginFrame(WTF::monotonicallyIncreasingTime());
+  EXPECT_TRUE(video->isFullscreen());
+  EXPECT_TRUE(layerTreeView.hasTransparentBackground);
+  webViewImpl->updateAllLifecyclePhases();
+
+  webViewImpl->didExitFullscreen();
+  EXPECT_TRUE(video->isFullscreen());
+  EXPECT_TRUE(layerTreeView.hasTransparentBackground);
+  webViewImpl->beginFrame(WTF::monotonicallyIncreasingTime());
+  EXPECT_FALSE(video->isFullscreen());
+  EXPECT_FALSE(layerTreeView.hasTransparentBackground);
+  webViewImpl->updateAllLifecyclePhases();
 }
 
 TEST_P(ParameterizedWebFrameTest, LayoutBlockPercentHeightDescendants) {
@@ -10901,6 +10904,69 @@
   EXPECT_EQ(hitTestResult.scrollbar()->hoveredPart(), ScrollbarPart::ThumbPart);
 }
 
+TEST_F(WebFrameTest, MouseReleaseUpdatesScrollbarHoveredPart) {
+  registerMockedHttpURLLoad("custom-scrollbar-hover.html");
+  FrameTestHelpers::WebViewHelper webViewHelper;
+  WebViewImpl* webView = webViewHelper.initializeAndLoad(
+      m_baseURL + "custom-scrollbar-hover.html");
+
+  webViewHelper.resize(WebSize(200, 200));
+
+  webView->updateAllLifecyclePhases();
+
+  Document* document = toLocalFrame(webView->page()->mainFrame())->document();
+
+  Element* scrollbarDiv = document->getElementById("scrollbar");
+  EXPECT_TRUE(scrollbarDiv);
+
+  ScrollableArea* scrollableArea =
+      toLayoutBox(scrollbarDiv->layoutObject())->getScrollableArea();
+
+  EXPECT_TRUE(scrollableArea->verticalScrollbar());
+  Scrollbar* scrollbar = scrollableArea->verticalScrollbar();
+  EXPECT_EQ(scrollbar->pressedPart(), ScrollbarPart::NoPart);
+  EXPECT_EQ(scrollbar->hoveredPart(), ScrollbarPart::NoPart);
+
+  // Mouse moved over the scrollbar.
+  PlatformMouseEvent mouseMoveOverScrollbar(
+      IntPoint(175, 1), IntPoint(175, 1),
+      WebPointerProperties::Button::NoButton, PlatformEvent::MouseMoved, 0,
+      PlatformEvent::NoModifiers, TimeTicks::Now());
+  document->frame()->eventHandler().handleMouseMoveEvent(
+      mouseMoveOverScrollbar, Vector<PlatformMouseEvent>());
+  HitTestResult hitTestResult = webView->coreHitTestResultAt(WebPoint(175, 1));
+  EXPECT_EQ(scrollbar->pressedPart(), ScrollbarPart::NoPart);
+  EXPECT_EQ(scrollbar->hoveredPart(), ScrollbarPart::ThumbPart);
+
+  // Mouse pressed.
+  PlatformMouseEvent mousePressEvent(
+      IntPoint(175, 1), IntPoint(175, 1), WebPointerProperties::Button::Left,
+      PlatformEvent::MousePressed, 0, PlatformEvent::Modifiers::LeftButtonDown,
+      TimeTicks::Now());
+  document->frame()->eventHandler().handleMousePressEvent(mousePressEvent);
+  EXPECT_EQ(scrollbar->pressedPart(), ScrollbarPart::ThumbPart);
+  EXPECT_EQ(scrollbar->hoveredPart(), ScrollbarPart::ThumbPart);
+
+  // Mouse moved off the scrollbar while still pressed.
+  PlatformMouseEvent mouseMoveOffScrollbar(
+      IntPoint(1, 1), IntPoint(1, 1), WebPointerProperties::Button::Left,
+      PlatformEvent::MouseMoved, 0, PlatformEvent::Modifiers::LeftButtonDown,
+      TimeTicks::Now());
+  document->frame()->eventHandler().handleMouseLeaveEvent(
+      mouseMoveOffScrollbar);
+  EXPECT_EQ(scrollbar->pressedPart(), ScrollbarPart::ThumbPart);
+  EXPECT_EQ(scrollbar->hoveredPart(), ScrollbarPart::ThumbPart);
+
+  // Mouse released.
+  PlatformMouseEvent MouseReleaseEvent(
+      IntPoint(1, 1), IntPoint(1, 1), WebPointerProperties::Button::Left,
+      PlatformEvent::MouseReleased, 0, PlatformEvent::Modifiers::LeftButtonDown,
+      TimeTicks::Now());
+  document->frame()->eventHandler().handleMouseReleaseEvent(MouseReleaseEvent);
+  EXPECT_EQ(scrollbar->pressedPart(), ScrollbarPart::NoPart);
+  EXPECT_EQ(scrollbar->hoveredPart(), ScrollbarPart::NoPart);
+}
+
 static void disableCompositing(WebSettings* settings) {
   settings->setAcceleratedCompositingEnabled(false);
   settings->setPreferCompositingToLCDTextEnabled(false);
diff --git a/third_party/WebKit/Source/web/tests/WebViewTest.cpp b/third_party/WebKit/Source/web/tests/WebViewTest.cpp
index ed93164..257c108f 100644
--- a/third_party/WebKit/Source/web/tests/WebViewTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebViewTest.cpp
@@ -1725,6 +1725,7 @@
   UserGestureIndicator gesture(DocumentUserGestureToken::create(document));
   Fullscreen::requestFullscreen(*element);
   webViewImpl->didEnterFullscreen();
+  webViewImpl->beginFrame(WTF::monotonicallyIncreasingTime());
   webViewImpl->updateAllLifecyclePhases();
 
   // Sanity-check. There should be no scrolling possible.
@@ -1738,10 +1739,12 @@
   // parameters are reset. The page sets display: none on overflowing elements
   // while in fullscreen so if we try to restore before the style and layout
   // is applied the offsets will be clamped.
+  EXPECT_FALSE(webViewImpl->mainFrameImpl()->frameView()->needsLayout());
   webViewImpl->didExitFullscreen();
   EXPECT_TRUE(webViewImpl->mainFrameImpl()->frameView()->needsLayout());
+  webViewImpl->beginFrame(WTF::monotonicallyIncreasingTime());
+  EXPECT_EQ(0, webViewImpl->mainFrame()->getScrollOffset().height);
   webViewImpl->updateAllLifecyclePhases();
-
   EXPECT_EQ(2000, webViewImpl->mainFrame()->getScrollOffset().height);
 }
 
@@ -1766,6 +1769,7 @@
   UserGestureIndicator gesture(DocumentUserGestureToken::create(document));
   Fullscreen::requestFullscreen(*element);
   webViewImpl->didEnterFullscreen();
+  webViewImpl->beginFrame(WTF::monotonicallyIncreasingTime());
   webViewImpl->updateAllLifecyclePhases();
 
   // Sanity-check. There should be no scrolling possible.
@@ -1781,6 +1785,7 @@
   webViewImpl->didExitFullscreen();
   Fullscreen::requestFullscreen(*element);
   webViewImpl->didEnterFullscreen();
+  webViewImpl->beginFrame(WTF::monotonicallyIncreasingTime());
   webViewImpl->updateAllLifecyclePhases();
 
   // Sanity-check. There should be no scrolling possible.
@@ -1792,6 +1797,7 @@
 
   // When we exit now, we should restore the original scroll value.
   webViewImpl->didExitFullscreen();
+  webViewImpl->beginFrame(WTF::monotonicallyIncreasingTime());
   webViewImpl->updateAllLifecyclePhases();
 
   EXPECT_EQ(2000, webViewImpl->mainFrame()->getScrollOffset().height);
@@ -1823,6 +1829,8 @@
   UserGestureIndicator gesture(DocumentUserGestureToken::create(document));
   Fullscreen::requestFullscreen(*element);
   webViewImpl->didEnterFullscreen();
+  webViewImpl->beginFrame(WTF::monotonicallyIncreasingTime());
+  webViewImpl->updateAllLifecyclePhases();
 
   // Page scale factor must be 1.0 during fullscreen for elements to be sized
   // properly.
@@ -1834,6 +1842,7 @@
 
   // Confirm that exiting fullscreen restores the parameters.
   webViewImpl->didExitFullscreen();
+  webViewImpl->beginFrame(WTF::monotonicallyIncreasingTime());
   webViewImpl->updateAllLifecyclePhases();
 
   EXPECT_EQ(2.0f, webViewImpl->pageScaleFactor());
diff --git a/tools/chrome_proxy/webdriver/common.py b/tools/chrome_proxy/webdriver/common.py
index 05b2c89..53e0b09 100644
--- a/tools/chrome_proxy/webdriver/common.py
+++ b/tools/chrome_proxy/webdriver/common.py
@@ -13,6 +13,7 @@
 import time
 import traceback
 import unittest
+import urlparse
 
 sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir,
   os.pardir, 'third_party', 'webdriver', 'pylib'))
@@ -53,7 +54,7 @@
   parser.add_argument('-f', '--failfast', help='Stop the test run on the first '
     'error or failure.', action='store_true')
   parser.add_argument('--logging_level', choices=['DEBUG', 'INFO', 'WARN',
-    'ERROR', 'CRIT'], default='ERROR', help='The logging verbosity for log '
+    'ERROR', 'CRIT'], default='WARN', help='The logging verbosity for log '
     'messages, printed to stderr. To see stderr logging output during a '
     'successful test run, also pass --disable_buffer. Default=ERROR')
   parser.add_argument('--log_file', help='If given, write logging statements '
@@ -260,6 +261,10 @@
       timeout: The time in seconds to load the page before timing out.
     """
     self._url = url
+    if (len(urlparse.urlparse(url).netloc) == 0 and
+        len(urlparse.urlparse(url).scheme) == 0):
+      self._logger.warn('Invalid URL: "%s". Did you forget to prepend '
+        '"http://"? See RFC 1808 for more information', url)
     if not self._driver:
       self._StartDriver()
     self._driver.set_page_load_timeout(timeout)
@@ -357,7 +362,7 @@
       len(all_messages), method_filter)
     return all_messages
 
-  def GetHTTPResponses(self, include_favicon=False):
+  def GetHTTPResponses(self, include_favicon=False, skip_domainless_pages=True):
     """Parses the Performance Logs and returns a list of HTTPResponse objects.
 
     Use caution when calling this function  multiple times. Only responses
@@ -366,6 +371,8 @@
 
     Args:
       include_favicon: A bool that if True will include responses for favicons.
+      skip_domainless_pages: If True, only responses with a net_loc as in RFC
+        1808 will be included. Pages such as about:blank will be skipped.
     Returns:
       A list of HTTPResponse objects, each representing a single completed HTTP
       transaction by Chrome.
@@ -392,8 +399,13 @@
       response = MakeHTTPResponse(message)
       self._logger.debug('New HTTPResponse: %s', str(response))
       is_favicon = response.url.endswith('favicon.ico')
-      if not is_favicon or include_favicon:
+      has_domain = len(urlparse.urlparse(response.url).netloc) > 0
+      if (not is_favicon or include_favicon) and (not skip_domainless_pages or
+          has_domain):
         all_responses.append(response)
+      else:
+        self._logger.info("Skipping HTTPResponse with url=%s in returned logs.",
+          response.url)
     self._logger.info('%d new HTTPResponse objects found in the logs %s '
       'favicons', len(all_responses), ('including' if include_favicon else
       'not including'))
diff --git a/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp b/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp
index 97d9ebd..d308f5e 100644
--- a/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp
+++ b/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp
@@ -218,20 +218,25 @@
   return decl.getName() == "swap";
 }
 
+bool IsBlacklistedMethodName(llvm::StringRef name) {
+  static const char* kBlacklistedNames[] = {
+      "lock", "unlock", "try_lock",
+      "begin", "end", "rbegin", "rend",
+  };
+  for (const auto& b : kBlacklistedNames) {
+    if (name == b)
+      return true;
+  }
+  return false;
+}
+
 bool IsBlacklistedMethod(const clang::CXXMethodDecl& decl) {
   if (decl.isStatic())
     return false;
 
   clang::StringRef name = decl.getName();
-
-  // These methods should never be renamed.
-  static const char* kBlacklistMethods[] = {"trace",  "traceImpl", "lock",
-                                            "unlock", "try_lock",  "begin",
-                                            "end",    "rbegin",    "rend"};
-  for (const auto& b : kBlacklistMethods) {
-    if (name == b)
+  if (IsBlacklistedMethodName(name))
       return true;
-  }
 
   // Subclasses of InspectorAgent will subclass "disable()" from both blink and
   // from gen/, which is problematic, but DevTools folks don't want to rename
@@ -243,21 +248,6 @@
   return false;
 }
 
-bool IsBlacklistedFunctionOrMethodName(llvm::StringRef name) {
-  static const char* kBlacklistedNames[] = {
-      // From IsBlacklistedFunction:
-      "swap",
-      // From IsBlacklistedMethod:
-      "trace", "traceImpl", "lock", "unlock", "try_lock", "begin", "end",
-      "rbegin", "rend", "disable",
-  };
-  for (const auto& b : kBlacklistedNames) {
-    if (name == b)
-      return true;
-  }
-  return false;
-}
-
 AST_MATCHER(clang::FunctionDecl, isBlacklistedFunction) {
   return IsBlacklistedFunction(Node);
 }
@@ -826,7 +816,7 @@
 
     // |T::myMethod(...)| -> |T::MyMethod(...)|.
     if ((old_name.find('_') == std::string::npos) && IsCallee(node, context) &&
-        !IsBlacklistedFunctionOrMethodName(old_name)) {
+        !IsBlacklistedMethodName(old_name)) {
       new_name = old_name;
       new_name[0] = clang::toUppercase(old_name[0]);
       return true;
diff --git a/tools/clang/rewrite_to_chrome_style/tests/methods-expected.cc b/tools/clang/rewrite_to_chrome_style/tests/methods-expected.cc
index f770362..4cbdc0e 100644
--- a/tools/clang/rewrite_to_chrome_style/tests/methods-expected.cc
+++ b/tools/clang/rewrite_to_chrome_style/tests/methods-expected.cc
@@ -54,8 +54,9 @@
   my_iterator end() {}
   my_iterator rbegin() {}
   MyIterator rend() {}
-  // The trace() method is used by Oilpan, we shouldn't rename it.
-  void trace() {}
+  // The trace() method is used by Oilpan, but we plan to tweak the Oilpan's
+  // clang plugin, so that it recognizes the new method name.
+  void Trace() {}
   // These are used by std::unique_lock and std::lock_guard.
   void lock() {}
   void unlock() {}
diff --git a/tools/clang/rewrite_to_chrome_style/tests/methods-original.cc b/tools/clang/rewrite_to_chrome_style/tests/methods-original.cc
index 2802033..3e85018 100644
--- a/tools/clang/rewrite_to_chrome_style/tests/methods-original.cc
+++ b/tools/clang/rewrite_to_chrome_style/tests/methods-original.cc
@@ -58,7 +58,8 @@
   my_iterator end() {}
   my_iterator rbegin() {}
   MyIterator rend() {}
-  // The trace() method is used by Oilpan, we shouldn't rename it.
+  // The trace() method is used by Oilpan, but we plan to tweak the Oilpan's
+  // clang plugin, so that it recognizes the new method name.
   void trace() {}
   // These are used by std::unique_lock and std::lock_guard.
   void lock() {}
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index ce86f478..8e1f5f7 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -4936,6 +4936,19 @@
   </summary>
 </histogram>
 
+<histogram
+    name="Bluetooth.Web.RequestDevice.NumOfDevicesInChooserWhenNotAcceptingAllDevices"
+    units="devices">
+  <owner>jyasskin@chromium.org</owner>
+  <owner>ortuno@chromium.org</owner>
+  <owner>scheib@chromium.org</owner>
+  <owner>juncai@chromium.org</owner>
+  <summary>
+    In the case of not accepting all devices, records the number of devices that
+    are in the chooser when a device is paired.
+  </summary>
+</histogram>
+
 <histogram name="Bluetooth.Web.RequestDevice.OptionalServices.Count"
     units="filters">
   <owner>jyasskin@chromium.org</owner>
@@ -18750,6 +18763,13 @@
   </summary>
 </histogram>
 
+<histogram name="FileBrowser.QuickView.DialogType" enum="FileDialogType">
+  <owner>oka@google.com</owner>
+  <summary>
+    File dialog type (e.g. Full page, Save as file) when quick view is launched.
+  </summary>
+</histogram>
+
 <histogram name="FileBrowser.QuickView.FileType" enum="ViewFileType">
   <owner>oka@google.com</owner>
   <summary>File types that were tried to be opened with quick view.</summary>
@@ -48408,6 +48428,36 @@
   </summary>
 </histogram>
 
+<histogram name="Power.PowerSupplyMaxPower" units="W">
+  <owner>bleung@chromium.org</owner>
+  <owner>derat@chromium.org</owner>
+  <summary>
+    The maximum power supported by the connected power supply on Chrome OS. A
+    sample is reported every time that the power manager polls sysfs (typically
+    every 30 seconds) and sees a connected supply.
+  </summary>
+</histogram>
+
+<histogram name="Power.PowerSupplyMaxVoltage" units="V">
+  <owner>bleung@chromium.org</owner>
+  <owner>derat@chromium.org</owner>
+  <summary>
+    The maximum voltage supported by the connected power supply on Chrome OS. A
+    sample is reported every time that the power manager polls sysfs (typically
+    every 30 seconds) and sees a connected supply.
+  </summary>
+</histogram>
+
+<histogram name="Power.PowerSupplyType" enum="PowerSupplyType">
+  <owner>bleung@chromium.org</owner>
+  <owner>derat@chromium.org</owner>
+  <summary>
+    The type of the connected power supply on Chrome OS. A sample is reported
+    every time that the power manager polls sysfs (typically every 30 seconds)
+    and sees a connected supply.
+  </summary>
+</histogram>
+
 <histogram name="Power.RetrySuspendCount">
   <obsolete>
     Deprecated Feb 2014 by Power.SuspendAttemptsBeforeCancel and
@@ -93547,6 +93597,7 @@
   <int value="-699767107" label="enable-sync-app-list"/>
   <int value="-697751423" label="disable-quickoffice-component-app"/>
   <int value="-684900739" label="disable-merge-key-char-events"/>
+  <int value="-684223908" label="enable-android-wallpapers-app"/>
   <int value="-667517406" label="overscroll-history-navigation"/>
   <int value="-661978438" label="enable-data-reduction-proxy-lo-fi"/>
   <int value="-660160292" label="enable-apps-show-on-first-paint"/>
@@ -99156,6 +99207,9 @@
 </enum>
 
 <enum name="PowerChargerType" type="int">
+  <obsolete>
+    Deprecated 11/2014 in issue 427057.
+  </obsolete>
   <int value="0" label="Unknown charger"/>
   <int value="1" label="MAINS charger"/>
   <int value="2" label="USB Charger"/>
@@ -99163,6 +99217,22 @@
   <int value="4" label="Safe Spring Charger"/>
 </enum>
 
+<enum name="PowerSupplyType" type="int">
+  <summary>
+    The type of power supply connected to a Chrome OS system, as reported by the
+    kernel.
+  </summary>
+  <int value="0" label="Other"/>
+  <int value="1" label="Mains"/>
+  <int value="2" label="USB"/>
+  <int value="3" label="USB_ACA"/>
+  <int value="4" label="USB_CDP"/>
+  <int value="5" label="USB_DCP"/>
+  <int value="6" label="USB_C"/>
+  <int value="7" label="USB_PD"/>
+  <int value="8" label="USB_PD_DRP"/>
+</enum>
+
 <enum name="PowerwashDialogViewType" type="int">
   <int value="0" label="Invoked on settings page"/>
   <int value="1" label="Shortcut. Confirmation for powerwash only."/>
diff --git a/ui/android/BUILD.gn b/ui/android/BUILD.gn
index 4ee7b10..5e44d1f 100644
--- a/ui/android/BUILD.gn
+++ b/ui/android/BUILD.gn
@@ -42,6 +42,8 @@
     "ui_android_jni_registrar.h",
     "view_android.cc",
     "view_android.h",
+    "view_client.cc",
+    "view_client.h",
     "window_android.cc",
     "window_android.h",
     "window_android_compositor.h",
@@ -81,6 +83,7 @@
   sources = [
     "java/src/org/chromium/ui/OverscrollRefreshHandler.java",
     "java/src/org/chromium/ui/base/ViewAndroidDelegate.java",
+    "java/src/org/chromium/ui/base/ViewRoot.java",
     "java/src/org/chromium/ui/base/WindowAndroid.java",
     "java/src/org/chromium/ui/display/DisplayAndroidManager.java",
     "java/src/org/chromium/ui/resources/ResourceManager.java",
@@ -176,6 +179,7 @@
     "java/src/org/chromium/ui/base/SelectFileDialog.java",
     "java/src/org/chromium/ui/base/TouchDevice.java",
     "java/src/org/chromium/ui/base/ViewAndroidDelegate.java",
+    "java/src/org/chromium/ui/base/ViewRoot.java",
     "java/src/org/chromium/ui/base/WindowAndroid.java",
     "java/src/org/chromium/ui/display/DisplayAndroid.java",
     "java/src/org/chromium/ui/display/DisplayAndroidManager.java",
diff --git a/ui/android/java/src/org/chromium/ui/base/ViewRoot.java b/ui/android/java/src/org/chromium/ui/base/ViewRoot.java
new file mode 100644
index 0000000..c224e8e3
--- /dev/null
+++ b/ui/android/java/src/org/chromium/ui/base/ViewRoot.java
@@ -0,0 +1,50 @@
+// 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.
+
+package org.chromium.ui.base;
+
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+
+/**
+ * Class used to forward view, input events down to native.
+ *
+ * TODO(jinsukkim): Add its native counterpart inheriting from ViewAndroid
+ *     so that it will act as a root of ViewAndroid tree. It effectively
+ *     replaces WindowAndroid in terms of the role.
+ */
+@JNINamespace("ui")
+public class ViewRoot {
+    // The corresponding native ViewAndroid. This object can only be used while
+    // the native instance is alive.
+    private long mNativeView;
+
+    @CalledByNative
+    private static ViewRoot create(long nativeView) {
+        return new ViewRoot(nativeView);
+    }
+
+    private ViewRoot(long nativeView) {
+        mNativeView = nativeView;
+    }
+
+    /**
+     * Called when the underlying surface the compositor draws to changes size.
+     * This may be larger than the viewport size.
+     * @param width Width of the physical backing surface.
+     * @param height Height of the physical backing surface.
+     */
+    public void onPhysicalBackingSizeChanged(int width, int height) {
+        assert mNativeView != 0;
+        nativeOnPhysicalBackingSizeChanged(mNativeView, width, height);
+    }
+
+    @CalledByNative
+    private void onDestroyNativeView() {
+        mNativeView = 0;
+    }
+
+    private static native void nativeOnPhysicalBackingSizeChanged(long viewAndroid,
+            int width, int height);
+}
diff --git a/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java b/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
index 88f64bda..9fece45 100644
--- a/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
+++ b/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
@@ -110,6 +110,8 @@
 
     private AndroidPermissionDelegate mPermissionDelegate;
 
+    private ViewRoot mViewRoot;
+
     /**
      * An interface to notify listeners of changes in the soft keyboard's visibility.
      */
@@ -727,6 +729,16 @@
         }
     }
 
+    /**
+     * @return {@link ViewRoot} instance used to forward input/view events down to native.
+     */
+    public ViewRoot getViewRoot() {
+        if (mViewRoot == null) {
+            mViewRoot = nativeGetViewRootForJava(mNativeWindowAndroid);
+        }
+        return mViewRoot;
+    }
+
     private native long nativeInit(int displayId);
     private native void nativeOnVSync(long nativeWindowAndroid,
                                       long vsyncTimeMicros,
@@ -735,5 +747,5 @@
     private native void nativeOnActivityStopped(long nativeWindowAndroid);
     private native void nativeOnActivityStarted(long nativeWindowAndroid);
     private native void nativeDestroy(long nativeWindowAndroid);
-
+    private native ViewRoot nativeGetViewRootForJava(long nativeWindowAndroid);
 }
diff --git a/ui/android/ui_android_jni_registrar.cc b/ui/android/ui_android_jni_registrar.cc
index 3c02c50..470ac88 100644
--- a/ui/android/ui_android_jni_registrar.cc
+++ b/ui/android/ui_android_jni_registrar.cc
@@ -17,6 +17,7 @@
 static base::android::RegistrationMethod kAndroidRegisteredMethods[] = {
     {"DisplayAndroidManager", ui::RegisterScreenAndroid},
     {"ResourceManager", ui::ResourceManagerImpl::RegisterResourceManager},
+    {"ViewRoot", ui::RegisterViewRoot},
     {"WindowAndroid", WindowAndroid::RegisterWindowAndroid},
 };
 
diff --git a/ui/android/view_android.cc b/ui/android/view_android.cc
index 664758c..96e5649 100644
--- a/ui/android/view_android.cc
+++ b/ui/android/view_android.cc
@@ -9,12 +9,15 @@
 #include "base/android/jni_android.h"
 #include "cc/layers/layer.h"
 #include "jni/ViewAndroidDelegate_jni.h"
+#include "jni/ViewRoot_jni.h"
+#include "ui/android/view_client.h"
 #include "ui/android/window_android.h"
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
 
 namespace ui {
 
+using base::android::JavaParamRef;
 using base::android::JavaRef;
 using base::android::ScopedJavaLocalRef;
 
@@ -68,24 +71,29 @@
   return view_.get(env);
 }
 
-ViewAndroid::ViewAndroid(const JavaRef<jobject>& delegate)
-    : parent_(nullptr)
-    , delegate_(base::android::AttachCurrentThread(),
-                delegate.obj()) {}
-
-ViewAndroid::ViewAndroid() : parent_(nullptr) {}
+ViewAndroid::ViewAndroid(ViewClient* client) : parent_(nullptr),
+                                               client_(client),
+                                               physical_width_pix_(0),
+                                               physical_height_pix_(0) {}
+ViewAndroid::ViewAndroid() : ViewAndroid(nullptr) {}
 
 ViewAndroid::~ViewAndroid() {
   RemoveFromParent();
 
-  for (std::list<ViewAndroid*>::iterator it = children_.begin();
-       it != children_.end(); it++) {
-    DCHECK_EQ((*it)->parent_, this);
-    (*it)->parent_ = nullptr;
+  for (auto& child : children_) {
+    DCHECK_EQ(child->parent_, this);
+    child->parent_ = nullptr;
   }
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  const ScopedJavaLocalRef<jobject> view_root = view_root_.get(env);
+  if (!view_root.is_null())
+    Java_ViewRoot_onDestroyNativeView(env, view_root);
 }
 
 void ViewAndroid::SetDelegate(const JavaRef<jobject>& delegate) {
+  // A ViewAndroid may have its own delegate or otherwise will
+  // use the next available parent's delegate.
   JNIEnv* env = base::android::AttachCurrentThread();
   delegate_ = JavaObjectWeakGlobalRef(env, delegate);
 }
@@ -94,11 +102,17 @@
   DCHECK(child);
   DCHECK(std::find(children_.begin(), children_.end(), child) ==
          children_.end());
+  DCHECK(!HasViewRootInTreeHierarchy() ||
+         !child->HasViewRootInSubtree());
 
   children_.push_back(child);
   if (child->parent_)
     child->RemoveFromParent();
   child->parent_ = this;
+  if (physical_width_pix_ || physical_height_pix_) {
+    child->OnPhysicalBackingSizeChanged(physical_width_pix_,
+                                        physical_height_pix_);
+  }
 }
 
 void ViewAndroid::RemoveFromParent() {
@@ -151,6 +165,15 @@
   return parent_ ? parent_->GetWindowAndroid() : nullptr;
 }
 
+ScopedJavaLocalRef<jobject> ViewAndroid::CreateViewRoot() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  return Java_ViewRoot_create(env, reinterpret_cast<intptr_t>(this));
+}
+
+bool ViewAndroid::HasViewRoot() {
+  return !view_root_.is_uninitialized();
+}
+
 const ScopedJavaLocalRef<jobject> ViewAndroid::GetViewAndroidDelegate()
     const {
   JNIEnv* env = base::android::AttachCurrentThread();
@@ -167,6 +190,38 @@
 
 void ViewAndroid::SetLayer(scoped_refptr<cc::Layer> layer) {
   layer_ = layer;
+  UpdateLayerBounds();
+}
+
+ScopedJavaLocalRef<jobject> ViewAndroid::GetViewRoot() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  const ScopedJavaLocalRef<jobject> view_root = view_root_.get(env);
+  if (!view_root.is_null())
+     return view_root;
+
+  DCHECK(!HasViewRootInTreeHierarchy());
+  view_root_ = JavaObjectWeakGlobalRef(env, CreateViewRoot());
+  return view_root_.get(env);
+}
+
+bool ViewAndroid::HasViewRootInTreeHierarchy() {
+  ViewAndroid* view = parent_;
+  while (view) {
+    if (view->HasViewRoot())
+      return true;
+    view = view->parent_;
+  }
+  return HasViewRootInSubtree();
+}
+
+bool ViewAndroid::HasViewRootInSubtree() {
+  if (HasViewRoot())
+    return true;
+  for (auto& child : children_) {
+    if (child->HasViewRootInSubtree())
+      return true;
+  }
+  return false;
 }
 
 bool ViewAndroid::StartDragAndDrop(const JavaRef<jstring>& jtext,
@@ -179,4 +234,42 @@
                                                    jimage);
 }
 
+gfx::Size ViewAndroid::GetPhysicalBackingSize() {
+  return gfx::Size(physical_width_pix_, physical_height_pix_);
+}
+
+void ViewAndroid::UpdateLayerBounds() {
+  if (layer_)
+    layer_->SetBounds(GetPhysicalBackingSize());
+}
+
+void ViewAndroid::OnPhysicalBackingSizeChanged(int width, int height) {
+  if (width == physical_width_pix_ && height == physical_height_pix_)
+    return;
+
+  physical_width_pix_ = width;
+  physical_height_pix_ = height;
+  UpdateLayerBounds();
+
+  if (client_)
+    client_->OnPhysicalBackingSizeChanged(width, height);
+
+  for (auto& child : children_)
+    child->OnPhysicalBackingSizeChanged(width, height);
+}
+
+// static
+void OnPhysicalBackingSizeChanged(JNIEnv* env,
+                                  const JavaParamRef<jclass>& jcaller,
+                                  jlong native_view,
+                                  int width,
+                                  int height) {
+  ViewAndroid* view_android = reinterpret_cast<ViewAndroid*>(native_view);
+  view_android->OnPhysicalBackingSizeChanged(width, height);
+}
+
+bool RegisterViewRoot(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
 }  // namespace ui
diff --git a/ui/android/view_android.h b/ui/android/view_android.h
index 607a1ac..d05520d 100644
--- a/ui/android/view_android.h
+++ b/ui/android/view_android.h
@@ -18,6 +18,7 @@
 
 namespace ui {
 
+class ViewClient;
 class WindowAndroid;
 
 // A simple container for a UI layer.
@@ -54,9 +55,7 @@
     // Default copy/assign disabled by move constructor.
   };
 
-  // A ViewAndroid may have its own delegate or otherwise will
-  // use the next available parent's delegate.
-  ViewAndroid(const base::android::JavaRef<jobject>& delegate);
+  explicit ViewAndroid(ViewClient* client);
 
   ViewAndroid();
   virtual ~ViewAndroid();
@@ -65,6 +64,10 @@
   // if disconnected.
   virtual WindowAndroid* GetWindowAndroid() const;
 
+  // Returns |ViewRoot| associated with the current ViewAndroid.
+  // Create one if not present.
+  base::android::ScopedJavaLocalRef<jobject> GetViewRoot();
+
   // Used to return and set the layer for this view. May be |null|.
   cc::Layer* GetLayer() const;
   void SetLayer(scoped_refptr<cc::Layer> layer);
@@ -84,25 +87,51 @@
   void SetAnchorRect(const base::android::JavaRef<jobject>& anchor,
                      const gfx::RectF& bounds);
 
+  gfx::Size GetPhysicalBackingSize();
+  void UpdateLayerBounds();
+
+  // Internal implementation of ViewClient forwarding calls to the interface.
+  void OnPhysicalBackingSizeChanged(int width, int height);
+
  protected:
   ViewAndroid* parent_;
 
  private:
   void RemoveChild(ViewAndroid* child);
 
+  // Checks if any ViewAndroid instance in the tree hierarchy (including
+  // all the parents and the children) has |ViewRoot| already.
+  bool HasViewRootInTreeHierarchy();
+
+  // Checks if any children (plus this ViewAndroid itself) has |ViewRoot|.
+  bool HasViewRootInSubtree();
+
   // Returns the Java delegate for this view. This is used to delegate work
   // up to the embedding view (or the embedder that can deal with the
   // implementation details).
   const base::android::ScopedJavaLocalRef<jobject>
       GetViewAndroidDelegate() const;
 
+  // Creates a new |ViewRoot| for this ViewAndroid. No parent or child
+  // should have |ViewRoot| for this ViewAndroid to have one.
+  base::android::ScopedJavaLocalRef<jobject> CreateViewRoot();
+
+  bool HasViewRoot();
+
   std::list<ViewAndroid*> children_;
   scoped_refptr<cc::Layer> layer_;
   JavaObjectWeakGlobalRef delegate_;
+  JavaObjectWeakGlobalRef view_root_;
+  ViewClient* const client_;
+
+  int physical_width_pix_;
+  int physical_height_pix_;
 
   DISALLOW_COPY_AND_ASSIGN(ViewAndroid);
 };
 
+bool RegisterViewRoot(JNIEnv* env);
+
 }  // namespace ui
 
 #endif  // UI_ANDROID_VIEW_ANDROID_H_
diff --git a/ui/android/view_client.cc b/ui/android/view_client.cc
new file mode 100644
index 0000000..0408cb1
--- /dev/null
+++ b/ui/android/view_client.cc
@@ -0,0 +1,11 @@
+// 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 "ui/android/view_client.h"
+
+namespace ui {
+
+void ViewClient::OnPhysicalBackingSizeChanged(int width, int height) { }
+
+}  // namespace ui
diff --git a/ui/android/view_client.h b/ui/android/view_client.h
new file mode 100644
index 0000000..d734c2f
--- /dev/null
+++ b/ui/android/view_client.h
@@ -0,0 +1,24 @@
+// 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 UI_ANDROID_VIEW_CLIENT_H_
+#define UI_ANDROID_VIEW_CLIENT_H_
+
+#include "ui/android/ui_android_export.h"
+
+namespace ui {
+
+// Client interface used to forward events from Java to native views.
+// Calls are dispatched to its children along the hierarchy of ViewAndroid.
+// Use bool return type to stop propagating the call i.e. overriden method
+// should return true to indicate that the event was handled and stop
+// the processing.
+class UI_ANDROID_EXPORT ViewClient {
+ public:
+  virtual void OnPhysicalBackingSizeChanged(int width, int height);
+};
+
+}  // namespace ui
+
+#endif  // UI_ANDROID_VIEW_CLIENT_H_
diff --git a/ui/android/window_android.cc b/ui/android/window_android.cc
index cff32ba6..16f2633 100644
--- a/ui/android/window_android.cc
+++ b/ui/android/window_android.cc
@@ -132,6 +132,12 @@
     observer.OnActivityStarted();
 }
 
+ScopedJavaLocalRef<jobject> WindowAndroid::GetViewRootForJava(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& obj) {
+  return GetViewRoot();
+}
+
 bool WindowAndroid::HasPermission(const std::string& permission) {
   JNIEnv* env = AttachCurrentThread();
   return Java_WindowAndroid_hasPermission(
diff --git a/ui/android/window_android.h b/ui/android/window_android.h
index 05279ce..b7763ac 100644
--- a/ui/android/window_android.h
+++ b/ui/android/window_android.h
@@ -74,6 +74,8 @@
                          const base::android::JavaParamRef<jobject>& obj);
   void OnActivityStarted(JNIEnv* env,
                          const base::android::JavaParamRef<jobject>& obj);
+  base::android::ScopedJavaLocalRef<jobject> GetViewRootForJava(JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj);
 
   // Return whether the specified Android permission is granted.
   bool HasPermission(const std::string& permission);
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
index 4faf5cd..15f78e5 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -369,8 +369,6 @@
     ":ui_features",
     "//base",
     "//skia",
-    "//ui/events:events_base",
-    "//ui/events/platform",
     "//ui/gfx",
     "//ui/gfx/geometry",
   ]
@@ -389,12 +387,22 @@
     "//url",
   ]
 
+  if (!is_ios) {
+    # iOS does not use Chromium-specific code for event handling.
+    public_deps += [
+      "//ui/events:events_base",
+      "//ui/events/platform",
+    ]
+  }
+
   if (is_ios) {
     set_sources_assignment_filter([])
     sources += [
       "l10n/l10n_util_mac.h",
       "l10n/l10n_util_mac.mm",
     ]
+    public_deps += [ "//ui/events:event_constants" ]
+
     set_sources_assignment_filter(sources_assignment_filter)
   }
 
diff --git a/ui/chromeos/BUILD.gn b/ui/chromeos/BUILD.gn
index f20011e..e5844a5 100644
--- a/ui/chromeos/BUILD.gn
+++ b/ui/chromeos/BUILD.gn
@@ -23,6 +23,8 @@
     "ime/input_method_menu_manager.h",
     "ime/mode_indicator_view.cc",
     "ime/mode_indicator_view.h",
+    "touch_accessibility_enabler.cc",
+    "touch_accessibility_enabler.h",
     "touch_exploration_controller.cc",
     "touch_exploration_controller.h",
     "user_activity_power_manager_notifier.cc",
@@ -61,6 +63,7 @@
     "ime/input_method_menu_item_unittest.cc",
     "ime/input_method_menu_manager_unittest.cc",
     "run_all_unittests.cc",
+    "touch_accessibility_enabler_unittest.cc",
     "touch_exploration_controller_unittest.cc",
   ]
   deps = [
diff --git a/ui/chromeos/touch_accessibility_enabler.cc b/ui/chromeos/touch_accessibility_enabler.cc
new file mode 100644
index 0000000..07d5c80
--- /dev/null
+++ b/ui/chromeos/touch_accessibility_enabler.cc
@@ -0,0 +1,158 @@
+// 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 "ui/chromeos/touch_accessibility_enabler.h"
+
+#include <math.h>
+
+#include <utility>
+
+#include "base/logging.h"
+#include "base/metrics/user_metrics.h"
+#include "base/time/default_tick_clock.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/events/event.h"
+#include "ui/events/event_processor.h"
+#include "ui/events/event_utils.h"
+
+namespace ui {
+
+namespace {
+
+// Delay between timer callbacks. Each one plays a tick sound.
+constexpr int kTimerDelayInMS = 500;
+
+// The number of ticks of the timer before the first sound is generated.
+constexpr int kTimerTicksOfFirstSoundFeedback = 6;
+
+// The number of ticks of the timer before toggling spoken feedback.
+constexpr int kTimerTicksToToggleSpokenFeedback = 10;
+
+}  // namespace
+
+TouchAccessibilityEnabler::TouchAccessibilityEnabler(
+    aura::Window* root_window,
+    TouchAccessibilityEnablerDelegate* delegate)
+    : root_window_(root_window),
+      delegate_(delegate),
+      state_(NO_FINGERS_DOWN),
+      tick_clock_(NULL) {
+  DCHECK(root_window);
+  DCHECK(delegate);
+  root_window_->AddPreTargetHandler(this);
+}
+
+TouchAccessibilityEnabler::~TouchAccessibilityEnabler() {
+  root_window_->RemovePreTargetHandler(this);
+}
+
+void TouchAccessibilityEnabler::OnTouchEvent(ui::TouchEvent* event) {
+  // Skip events rewritten by TouchExplorationController, it will hand
+  // us the unrewritten events directly.
+  if (!(event->flags() & ui::EF_TOUCH_ACCESSIBILITY))
+    HandleTouchEvent(*event);
+}
+
+void TouchAccessibilityEnabler::HandleTouchEvent(const ui::TouchEvent& event) {
+  DCHECK(!(event.flags() & ui::EF_TOUCH_ACCESSIBILITY));
+  const ui::EventType type = event.type();
+  const gfx::PointF& location = event.location_f();
+  const int touch_id = event.touch_id();
+
+  if (type == ui::ET_TOUCH_PRESSED) {
+    touch_locations_.insert(std::pair<int, gfx::PointF>(touch_id, location));
+  } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) {
+    auto iter = touch_locations_.find(touch_id);
+
+    // Can happen if this object is constructed while fingers were down.
+    if (iter == touch_locations_.end())
+      return;
+
+    touch_locations_.erase(touch_id);
+  } else if (type == ui::ET_TOUCH_MOVED) {
+    auto iter = touch_locations_.find(touch_id);
+
+    // Can happen if this object is constructed while fingers were down.
+    if (iter == touch_locations_.end())
+      return;
+
+    float delta = (location - iter->second).Length();
+    if (delta > gesture_detector_config_.double_tap_slop) {
+      state_ = WAIT_FOR_NO_FINGERS;
+      CancelTimer();
+      return;
+    }
+  } else {
+    NOTREACHED() << "Unexpected event type received: " << event.name();
+    return;
+  }
+
+  if (touch_locations_.size() == 0) {
+    state_ = NO_FINGERS_DOWN;
+    CancelTimer();
+    return;
+  }
+
+  if (touch_locations_.size() > 2) {
+    state_ = WAIT_FOR_NO_FINGERS;
+    CancelTimer();
+    return;
+  }
+
+  if (state_ == NO_FINGERS_DOWN && event.type() == ui::ET_TOUCH_PRESSED) {
+    state_ = ONE_FINGER_DOWN;
+  } else if (state_ == ONE_FINGER_DOWN &&
+             event.type() == ui::ET_TOUCH_PRESSED) {
+    state_ = TWO_FINGERS_DOWN;
+    two_finger_start_time_ = Now();
+    StartTimer();
+  }
+}
+
+base::TimeTicks TouchAccessibilityEnabler::Now() {
+  if (tick_clock_) {
+    // This is the same as what EventTimeForNow() does, but here we do it
+    // with a clock that can be replaced with a simulated clock for tests.
+    return tick_clock_->NowTicks();
+  }
+  return ui::EventTimeForNow();
+}
+
+void TouchAccessibilityEnabler::StartTimer() {
+  if (timer_.IsRunning())
+    return;
+
+  timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kTimerDelayInMS),
+               this, &ui::TouchAccessibilityEnabler::OnTimer);
+}
+
+void TouchAccessibilityEnabler::CancelTimer() {
+  if (timer_.IsRunning())
+    timer_.Stop();
+}
+
+void TouchAccessibilityEnabler::OnTimer() {
+  base::TimeTicks now = Now();
+  double tick_count_f =
+      (now - two_finger_start_time_).InMillisecondsF() / kTimerDelayInMS;
+  int tick_count = roundf(tick_count_f);
+
+  if (tick_count == kTimerTicksOfFirstSoundFeedback) {
+    base::RecordAction(
+        base::UserMetricsAction("Accessibility.TwoFingersHeldDown"));
+  }
+
+  if (tick_count >= kTimerTicksOfFirstSoundFeedback &&
+      tick_count < kTimerTicksToToggleSpokenFeedback) {
+    delegate_->PlaySpokenFeedbackToggleCountdown(tick_count);
+  }
+  if (tick_count == kTimerTicksToToggleSpokenFeedback) {
+    delegate_->ToggleSpokenFeedback();
+    state_ = WAIT_FOR_NO_FINGERS;
+  }
+}
+
+}  // namespace ui
diff --git a/ui/chromeos/touch_accessibility_enabler.h b/ui/chromeos/touch_accessibility_enabler.h
new file mode 100644
index 0000000..1b25990a
--- /dev/null
+++ b/ui/chromeos/touch_accessibility_enabler.h
@@ -0,0 +1,119 @@
+// 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 UI_CHROMEOS_TOUCH_ACCESSIBILITY_ENABLER_H_
+#define UI_CHROMEOS_TOUCH_ACCESSIBILITY_ENABLER_H_
+
+#include "base/macros.h"
+#include "base/time/tick_clock.h"
+#include "base/timer/timer.h"
+#include "base/values.h"
+#include "ui/chromeos/ui_chromeos_export.h"
+#include "ui/events/event.h"
+#include "ui/events/event_handler.h"
+#include "ui/events/gesture_detection/gesture_detector.h"
+
+namespace aura {
+class Window;
+}
+
+namespace ui {
+
+class Event;
+class EventHandler;
+class TouchEvent;
+
+// A delegate to handle commands in response to detected accessibility gesture
+// events.
+class TouchAccessibilityEnablerDelegate {
+ public:
+  virtual ~TouchAccessibilityEnablerDelegate() {}
+
+  // While the user holds down two fingers on a touch screen, which is the
+  // gesture to enable spoken feedback (if held down long enough), play a sound
+  // every "tick" (approximately every half-second) to warn the user something
+  // is about to happen.
+  virtual void PlaySpokenFeedbackToggleCountdown(int tick_count) {}
+
+  // Toggles spoken feedback.
+  virtual void ToggleSpokenFeedback() {}
+};
+
+// TouchAccessibilityEnabler triggers turning spoken feedback on or off
+// by holding down two fingers on the touch screen for several seconds.
+class UI_CHROMEOS_EXPORT TouchAccessibilityEnabler : public ui::EventHandler {
+ public:
+  TouchAccessibilityEnabler(aura::Window* root_window,
+                            ui::TouchAccessibilityEnablerDelegate* delegate);
+  ~TouchAccessibilityEnabler() override;
+
+  bool IsInNoFingersDownForTesting() { return state_ == NO_FINGERS_DOWN; }
+  bool IsInOneFingerDownForTesting() { return state_ == ONE_FINGER_DOWN; }
+  bool IsInTwoFingersDownForTesting() { return state_ == TWO_FINGERS_DOWN; }
+  bool IsInWaitForNoFingersForTesting() {
+    return state_ == WAIT_FOR_NO_FINGERS;
+  }
+  void TriggerOnTimerForTesting() { OnTimer(); }
+
+  void HandleTouchEvent(const ui::TouchEvent& event);
+
+ private:
+  // Overridden from ui::EventHandler
+  void OnTouchEvent(ui::TouchEvent* event) override;
+
+  void StartTimer();
+  void CancelTimer();
+  void OnTimer();
+
+  // Returns the current time of the tick clock.
+  base::TimeTicks Now();
+
+  enum State {
+    // No fingers are down.
+    NO_FINGERS_DOWN,
+
+    // One finger is down and it's possible this could be a two-finger-hold.
+    ONE_FINGER_DOWN,
+
+    // Two fingers are down and stationary and we will trigger enabling
+    // spoken feedback after a delay.
+    TWO_FINGERS_DOWN,
+
+    // This is the "reject" state when we get anything other than two fingers
+    // held down and stationary. Stay in this state until all fingers are
+    // removed.
+    WAIT_FOR_NO_FINGERS
+  };
+
+  aura::Window* root_window_;
+
+  // Called when we detect a long-press of two fingers. Not owned.
+  ui::TouchAccessibilityEnablerDelegate* delegate_;
+
+  // The current state.
+  State state_;
+
+  // The time when we entered the two finger state.
+  base::TimeTicks two_finger_start_time_;
+
+  // Map of touch ids to their initial locations.
+  std::map<int, gfx::PointF> touch_locations_;
+
+  // A timer that triggers repeatedly while two fingers are held down.
+  base::RepeatingTimer timer_;
+
+  // A default gesture detector config, so we can share the same
+  // timeout and pixel slop constants.
+  ui::GestureDetector::Config gesture_detector_config_;
+
+  // When touch_accessibility_enabler gets time relative to real time during
+  // testing, this clock is set to the simulated clock and used.
+  base::TickClock* tick_clock_;
+
+  DISALLOW_COPY_AND_ASSIGN(TouchAccessibilityEnabler);
+};
+
+}  // namespace ui
+
+#endif  // UI_CHROMEOS_TOUCH_ACCESSIBILITY_ENABLER_H_
diff --git a/ui/chromeos/touch_accessibility_enabler_unittest.cc b/ui/chromeos/touch_accessibility_enabler_unittest.cc
new file mode 100644
index 0000000..95c385d
--- /dev/null
+++ b/ui/chromeos/touch_accessibility_enabler_unittest.cc
@@ -0,0 +1,181 @@
+// 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 "ui/chromeos/touch_accessibility_enabler.h"
+
+#include "base/macros.h"
+#include "base/test/simple_test_tick_clock.h"
+#include "base/time/time.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/window.h"
+#include "ui/events/event.h"
+#include "ui/events/event_utils.h"
+#include "ui/events/gestures/gesture_provider_aura.h"
+#include "ui/events/test/event_generator.h"
+#include "ui/events/test/events_test_utils.h"
+#include "ui/gfx/geometry/point.h"
+
+namespace ui {
+
+namespace {
+
+class MockTouchAccessibilityEnablerDelegate
+    : public ui::TouchAccessibilityEnablerDelegate {
+ public:
+  MockTouchAccessibilityEnablerDelegate() {}
+  ~MockTouchAccessibilityEnablerDelegate() override {}
+
+  void PlaySpokenFeedbackToggleCountdown(int tick_count) override {
+    ++feedback_progress_sound_count_;
+  }
+  void ToggleSpokenFeedback() override { toggle_spoken_feedback_ = true; }
+
+  size_t feedback_progress_sound_count() const {
+    return feedback_progress_sound_count_;
+  }
+  bool toggle_spoken_feedback() const { return toggle_spoken_feedback_; }
+
+ private:
+  size_t feedback_progress_sound_count_ = 0;
+  bool toggle_spoken_feedback_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(MockTouchAccessibilityEnablerDelegate);
+};
+
+class TouchAccessibilityEnablerTest : public aura::test::AuraTestBase {
+ public:
+  TouchAccessibilityEnablerTest() {}
+  ~TouchAccessibilityEnablerTest() override {}
+
+  void SetUp() override {
+    aura::test::AuraTestBase::SetUp();
+
+    generator_.reset(new test::EventGenerator(root_window()));
+
+    simulated_clock_ = new base::SimpleTestTickClock();
+    // Tests fail if time is ever 0.
+    simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(10));
+    // ui takes ownership of the tick clock.
+    ui::SetEventTickClockForTesting(
+        std::unique_ptr<base::TickClock>(simulated_clock_));
+
+    enabler_.reset(new TouchAccessibilityEnabler(root_window(), &delegate_));
+  }
+
+  void TearDown() override {
+    enabler_.reset(nullptr);
+    ui::SetEventTickClockForTesting(nullptr);
+    aura::test::AuraTestBase::TearDown();
+  }
+
+ protected:
+  base::TimeTicks Now() {
+    // This is the same as what EventTimeForNow() does, but here we do it
+    // with our simulated clock.
+    return simulated_clock_->NowTicks();
+  }
+
+  std::unique_ptr<test::EventGenerator> generator_;
+  // Owned by |ui|.
+  base::SimpleTestTickClock* simulated_clock_ = nullptr;
+  MockTouchAccessibilityEnablerDelegate delegate_;
+  std::unique_ptr<TouchAccessibilityEnabler> enabler_;
+  ui::GestureDetector::Config gesture_detector_config_;
+
+  DISALLOW_COPY_AND_ASSIGN(TouchAccessibilityEnablerTest);
+};
+
+}  // namespace
+
+TEST_F(TouchAccessibilityEnablerTest, EntersOneFingerDownMode) {
+  EXPECT_TRUE(enabler_->IsInNoFingersDownForTesting());
+  EXPECT_FALSE(enabler_->IsInOneFingerDownForTesting());
+  generator_->set_current_location(gfx::Point(11, 12));
+  generator_->PressTouch();
+
+  EXPECT_FALSE(enabler_->IsInNoFingersDownForTesting());
+  EXPECT_TRUE(enabler_->IsInOneFingerDownForTesting());
+}
+
+TEST_F(TouchAccessibilityEnablerTest, EntersTwoFingersDownMode) {
+  EXPECT_TRUE(enabler_->IsInNoFingersDownForTesting());
+  generator_->set_current_location(gfx::Point(11, 12));
+  generator_->PressTouchId(1);
+
+  generator_->set_current_location(gfx::Point(22, 34));
+  generator_->PressTouchId(2);
+
+  EXPECT_TRUE(enabler_->IsInTwoFingersDownForTesting());
+}
+
+TEST_F(TouchAccessibilityEnablerTest, PlaysProgressSound) {
+  EXPECT_TRUE(enabler_->IsInNoFingersDownForTesting());
+  generator_->set_current_location(gfx::Point(11, 12));
+  generator_->PressTouchId(1);
+
+  generator_->set_current_location(gfx::Point(22, 34));
+  generator_->PressTouchId(2);
+
+  EXPECT_TRUE(enabler_->IsInTwoFingersDownForTesting());
+  EXPECT_EQ(0U, delegate_.feedback_progress_sound_count());
+
+  enabler_->TriggerOnTimerForTesting();
+  EXPECT_EQ(0U, delegate_.feedback_progress_sound_count());
+
+  simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(3000));
+  enabler_->TriggerOnTimerForTesting();
+  EXPECT_EQ(1U, delegate_.feedback_progress_sound_count());
+}
+
+TEST_F(TouchAccessibilityEnablerTest, TogglesSpokenFeedback) {
+  EXPECT_TRUE(enabler_->IsInNoFingersDownForTesting());
+  generator_->set_current_location(gfx::Point(11, 12));
+  generator_->PressTouchId(1);
+
+  generator_->set_current_location(gfx::Point(22, 34));
+  generator_->PressTouchId(2);
+
+  EXPECT_TRUE(enabler_->IsInTwoFingersDownForTesting());
+  EXPECT_FALSE(delegate_.toggle_spoken_feedback());
+
+  enabler_->TriggerOnTimerForTesting();
+  EXPECT_FALSE(delegate_.toggle_spoken_feedback());
+
+  simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(5000));
+  enabler_->TriggerOnTimerForTesting();
+  EXPECT_TRUE(delegate_.toggle_spoken_feedback());
+}
+
+TEST_F(TouchAccessibilityEnablerTest, ThreeFingersCancelsDetection) {
+  EXPECT_TRUE(enabler_->IsInNoFingersDownForTesting());
+  generator_->set_current_location(gfx::Point(11, 12));
+  generator_->PressTouchId(1);
+
+  generator_->set_current_location(gfx::Point(22, 34));
+  generator_->PressTouchId(2);
+
+  EXPECT_TRUE(enabler_->IsInTwoFingersDownForTesting());
+
+  generator_->set_current_location(gfx::Point(33, 56));
+  generator_->PressTouchId(3);
+
+  EXPECT_TRUE(enabler_->IsInWaitForNoFingersForTesting());
+}
+
+TEST_F(TouchAccessibilityEnablerTest, MovingFingerPastSlopCancelsDetection) {
+  EXPECT_TRUE(enabler_->IsInNoFingersDownForTesting());
+  generator_->set_current_location(gfx::Point(11, 12));
+  generator_->PressTouch();
+
+  int slop = gesture_detector_config_.double_tap_slop;
+  int half_slop = slop / 2;
+
+  generator_->MoveTouch(gfx::Point(11 + half_slop, 12));
+  EXPECT_TRUE(enabler_->IsInOneFingerDownForTesting());
+
+  generator_->MoveTouch(gfx::Point(11 + slop + 1, 12));
+  EXPECT_TRUE(enabler_->IsInWaitForNoFingersForTesting());
+}
+
+}  // namespace ui
diff --git a/ui/chromeos/touch_exploration_controller.cc b/ui/chromeos/touch_exploration_controller.cc
index 6288ed1..584c1a10 100644
--- a/ui/chromeos/touch_exploration_controller.cc
+++ b/ui/chromeos/touch_exploration_controller.cc
@@ -13,6 +13,7 @@
 #include "ui/aura/window.h"
 #include "ui/aura/window_event_dispatcher.h"
 #include "ui/aura/window_tree_host.h"
+#include "ui/chromeos/touch_accessibility_enabler.h"
 #include "ui/events/event.h"
 #include "ui/events/event_processor.h"
 #include "ui/events/event_utils.h"
@@ -40,14 +41,16 @@
 
 TouchExplorationController::TouchExplorationController(
     aura::Window* root_window,
-    TouchExplorationControllerDelegate* delegate)
+    TouchExplorationControllerDelegate* delegate,
+    TouchAccessibilityEnabler* touch_accessibility_enabler)
     : root_window_(root_window),
       delegate_(delegate),
       state_(NO_FINGERS_DOWN),
       anchor_point_state_(ANCHOR_POINT_NONE),
       gesture_provider_(new GestureProviderAura(this, this)),
       prev_state_(NO_FINGERS_DOWN),
-      VLOG_on_(true) {
+      VLOG_on_(true),
+      touch_accessibility_enabler_(touch_accessibility_enabler) {
   DCHECK(root_window);
   root_window->GetHost()->GetEventSource()->AddEventRewriter(this);
 }
@@ -84,6 +87,10 @@
   }
   const ui::TouchEvent& touch_event = static_cast<const ui::TouchEvent&>(event);
 
+  // Let TouchAccessibilityEnabler process the unrewritten event.
+  if (touch_accessibility_enabler_)
+    touch_accessibility_enabler_->HandleTouchEvent(touch_event);
+
   if (!exclude_bounds_.IsEmpty()) {
     gfx::Point location = touch_event.location();
     root_window_->GetHost()->ConvertScreenInPixelsToDIP(&location);
diff --git a/ui/chromeos/touch_exploration_controller.h b/ui/chromeos/touch_exploration_controller.h
index 0af2d079..6727c2a 100644
--- a/ui/chromeos/touch_exploration_controller.h
+++ b/ui/chromeos/touch_exploration_controller.h
@@ -25,6 +25,7 @@
 class Event;
 class GestureEvent;
 class GestureProviderAura;
+class TouchAccessibilityEnabler;
 class TouchEvent;
 
 // A delegate to handle commands in response to detected accessibility gesture
@@ -180,7 +181,8 @@
  public:
   explicit TouchExplorationController(
       aura::Window* root_window,
-      ui::TouchExplorationControllerDelegate* delegate);
+      ui::TouchExplorationControllerDelegate* delegate,
+      TouchAccessibilityEnabler* touch_accessibility_enabler);
   ~TouchExplorationController() override;
 
   // Make synthesized touch events are anchored at this point. This is
@@ -506,6 +508,12 @@
   // LocatedEvents within this area should be left alone.
   gfx::Rect exclude_bounds_;
 
+  // Code that detects a touch-screen gesture to enable or disable
+  // accessibility. That handler is always running, whereas this is not,
+  // but events need to be sent to TouchAccessibilityEnabler before being
+  // rewritten when TouchExplorationController is running.
+  TouchAccessibilityEnabler* touch_accessibility_enabler_;
+
   DISALLOW_COPY_AND_ASSIGN(TouchExplorationController);
 };
 
diff --git a/ui/chromeos/touch_exploration_controller_unittest.cc b/ui/chromeos/touch_exploration_controller_unittest.cc
index 02acee7..14b7a247 100644
--- a/ui/chromeos/touch_exploration_controller_unittest.cc
+++ b/ui/chromeos/touch_exploration_controller_unittest.cc
@@ -298,7 +298,8 @@
     } else if (on && !touch_exploration_controller_.get()) {
       touch_exploration_controller_.reset(
           new ui::TouchExplorationControllerTestApi(
-              new TouchExplorationController(root_window(), &delegate_)));
+              new TouchExplorationController(root_window(), &delegate_,
+                                             nullptr)));
       cursor_client()->ShowCursor();
       cursor_client()->DisableMouseEvents();
     }
diff --git a/ui/events/BUILD.gn b/ui/events/BUILD.gn
index cb4738c2..0ad083d 100644
--- a/ui/events/BUILD.gn
+++ b/ui/events/BUILD.gn
@@ -35,13 +35,18 @@
   }
 }
 
+source_set("event_constants") {
+  sources = [
+    "event_constants.h",
+  ]
+}
+
 component("events_base") {
   sources = [
     "android/scroller.cc",
     "android/scroller.h",
     "base_event_utils.cc",
     "base_event_utils.h",
-    "event_constants.h",
     "event_switches.cc",
     "event_switches.h",
     "events_base_export.h",
@@ -72,6 +77,7 @@
 
   public_deps = [
     ":dom_keycode_converter",
+    ":event_constants",
     "//base",
     "//ui/events/platform",
     "//ui/gfx/geometry",
@@ -345,140 +351,142 @@
   }
 }
 
-test("events_unittests") {
-  sources = [
-    "android/scroller_unittest.cc",
-    "cocoa/events_mac_unittest.mm",
-    "event_dispatcher_unittest.cc",
-    "event_processor_unittest.cc",
-    "event_rewriter_unittest.cc",
-    "event_unittest.cc",
-    "gesture_detection/bitset_32_unittest.cc",
-    "gesture_detection/filtered_gesture_provider_unittest.cc",
-    "gesture_detection/gesture_event_data_packet_unittest.cc",
-    "gesture_detection/gesture_provider_unittest.cc",
-    "gesture_detection/motion_event_buffer_unittest.cc",
-    "gesture_detection/motion_event_generic_unittest.cc",
-    "gesture_detection/snap_scroll_controller_unittest.cc",
-    "gesture_detection/touch_disposition_gesture_filter_unittest.cc",
-    "gesture_detection/velocity_tracker_unittest.cc",
-    "gestures/fling_curve_unittest.cc",
-    "keycodes/dom/keycode_converter_unittest.cc",
-    "keycodes/keyboard_code_conversion_unittest.cc",
-    "keycodes/platform_key_map_win_unittest.cc",
-    "latency_info_unittest.cc",
-    "platform/platform_event_source_unittest.cc",
-    "scoped_target_handler_unittest.cc",
-    "win/event_utils_win_unittest.cc",
-  ]
-
-  deps = [
-    ":dom_keycode_converter",
-    ":events",
-    ":events_base",
-    ":gesture_detection",
-    ":test_support",
-    "//base",
-    "//base/test:test_support",
-    "//mojo/edk/test:run_all_unittests",
-    "//skia",
-    "//testing/gmock",
-    "//testing/gtest",
-    "//ui/events/devices",
-    "//ui/events/platform",
-    "//ui/gfx:test_support",
-  ]
-
-  if (!is_ios) {
-    sources += [
-      "blink/blink_event_util_unittest.cc",
-      "blink/input_handler_proxy_unittest.cc",
-      "blink/input_scroll_elasticity_controller_unittest.cc",
-      "blink/web_input_event_traits_unittest.cc",
-      "blink/web_input_event_unittest.cc",
-      "devices/mojo/device_struct_traits_unittest.cc",
-      "gestures/blink/web_gesture_curve_impl_unittest.cc",
-      "ipc/latency_info_param_traits_unittest.cc",
-      "mojo/struct_traits_unittest.cc",
-    ]
-    deps += [
-      "//cc",
-      "//ipc:test_support",
-      "//mojo/public/cpp/bindings",
-      "//third_party/WebKit/public:blink_headers",
-      "//ui/display",
-      "//ui/events/blink",
-      "//ui/events/devices/mojo:test_interfaces",
-      "//ui/events/gestures/blink",
-      "//ui/events/ipc",
-      "//ui/events/mojo:test_interfaces",
-      "//ui/gfx/ipc/geometry",
-    ]
-  }
-
-  if (!is_android && !is_ios) {
-    data_deps = [
-      "//third_party/mesa:osmesa",
-    ]
-  }
-
-  if (use_x11) {
-    sources += [
-      "devices/x11/device_data_manager_x11_unittest.cc",
-      "x/events_x_unittest.cc",
-    ]
-    configs += [ "//build/config/linux:x11" ]
-    deps += [
-      "//ui/events/devices/x11",
-      "//ui/events/x",
-      "//ui/gfx/x",
-    ]
-  }
-
-  if (use_ozone) {
-    sources += [
-      "ozone/chromeos/cursor_controller_unittest.cc",
-      "ozone/evdev/event_converter_evdev_impl_unittest.cc",
-      "ozone/evdev/event_converter_test_util.cc",
-      "ozone/evdev/event_device_info_unittest.cc",
-      "ozone/evdev/event_device_test_util.cc",
-      "ozone/evdev/input_injector_evdev_unittest.cc",
-      "ozone/evdev/tablet_event_converter_evdev_unittest.cc",
-      "ozone/evdev/touch_event_converter_evdev_unittest.cc",
-      "ozone/evdev/touch_noise/touch_noise_finder_unittest.cc",
+if (!is_ios) {
+  test("events_unittests") {
+    sources = [
+      "android/scroller_unittest.cc",
+      "cocoa/events_mac_unittest.mm",
+      "event_dispatcher_unittest.cc",
+      "event_processor_unittest.cc",
+      "event_rewriter_unittest.cc",
+      "event_unittest.cc",
+      "gesture_detection/bitset_32_unittest.cc",
+      "gesture_detection/filtered_gesture_provider_unittest.cc",
+      "gesture_detection/gesture_event_data_packet_unittest.cc",
+      "gesture_detection/gesture_provider_unittest.cc",
+      "gesture_detection/motion_event_buffer_unittest.cc",
+      "gesture_detection/motion_event_generic_unittest.cc",
+      "gesture_detection/snap_scroll_controller_unittest.cc",
+      "gesture_detection/touch_disposition_gesture_filter_unittest.cc",
+      "gesture_detection/velocity_tracker_unittest.cc",
+      "gestures/fling_curve_unittest.cc",
+      "keycodes/dom/keycode_converter_unittest.cc",
+      "keycodes/keyboard_code_conversion_unittest.cc",
+      "keycodes/platform_key_map_win_unittest.cc",
+      "latency_info_unittest.cc",
+      "platform/platform_event_source_unittest.cc",
+      "scoped_target_handler_unittest.cc",
+      "win/event_utils_win_unittest.cc",
     ]
 
-    if (use_xkbcommon) {
+    deps = [
+      ":dom_keycode_converter",
+      ":events",
+      ":events_base",
+      ":gesture_detection",
+      ":test_support",
+      "//base",
+      "//base/test:test_support",
+      "//mojo/edk/test:run_all_unittests",
+      "//skia",
+      "//testing/gmock",
+      "//testing/gtest",
+      "//ui/events/devices",
+      "//ui/events/platform",
+      "//ui/gfx:test_support",
+    ]
+
+    if (!is_ios) {
       sources += [
-        "ozone/layout/keyboard_layout_engine_unittest.cc",
-        "ozone/layout/xkb/xkb_keyboard_layout_engine_unittest.cc",
+        "blink/blink_event_util_unittest.cc",
+        "blink/input_handler_proxy_unittest.cc",
+        "blink/input_scroll_elasticity_controller_unittest.cc",
+        "blink/web_input_event_traits_unittest.cc",
+        "blink/web_input_event_unittest.cc",
+        "devices/mojo/device_struct_traits_unittest.cc",
+        "gestures/blink/web_gesture_curve_impl_unittest.cc",
+        "ipc/latency_info_param_traits_unittest.cc",
+        "mojo/struct_traits_unittest.cc",
+      ]
+      deps += [
+        "//cc",
+        "//ipc:test_support",
+        "//mojo/public/cpp/bindings",
+        "//third_party/WebKit/public:blink_headers",
+        "//ui/display",
+        "//ui/events/blink",
+        "//ui/events/devices/mojo:test_interfaces",
+        "//ui/events/gestures/blink",
+        "//ui/events/ipc",
+        "//ui/events/mojo:test_interfaces",
+        "//ui/gfx/ipc/geometry",
       ]
     }
 
-    deps += [
-      "//ui/events/ozone:events_ozone",
-      "//ui/events/ozone:events_ozone_evdev",
-      "//ui/events/ozone:events_ozone_layout",
-    ]
-  }
+    if (!is_android && !is_ios) {
+      data_deps = [
+        "//third_party/mesa:osmesa",
+      ]
+    }
 
-  if (use_aura) {
-    sources += [
-      "gestures/gesture_provider_aura_unittest.cc",
-      "gestures/motion_event_aura_unittest.cc",
-    ]
-  }
+    if (use_x11) {
+      sources += [
+        "devices/x11/device_data_manager_x11_unittest.cc",
+        "x/events_x_unittest.cc",
+      ]
+      configs += [ "//build/config/linux:x11" ]
+      deps += [
+        "//ui/events/devices/x11",
+        "//ui/events/x",
+        "//ui/gfx/x",
+      ]
+    }
 
-  if (is_android) {
-    sources += [ "android/motion_event_android_unittest.cc" ]
-  }
+    if (use_ozone) {
+      sources += [
+        "ozone/chromeos/cursor_controller_unittest.cc",
+        "ozone/evdev/event_converter_evdev_impl_unittest.cc",
+        "ozone/evdev/event_converter_test_util.cc",
+        "ozone/evdev/event_device_info_unittest.cc",
+        "ozone/evdev/event_device_test_util.cc",
+        "ozone/evdev/input_injector_evdev_unittest.cc",
+        "ozone/evdev/tablet_event_converter_evdev_unittest.cc",
+        "ozone/evdev/touch_event_converter_evdev_unittest.cc",
+        "ozone/evdev/touch_noise/touch_noise_finder_unittest.cc",
+      ]
 
-  if (is_ios) {
-    assert_no_deps = ios_assert_no_deps
-  }
+      if (use_xkbcommon) {
+        sources += [
+          "ozone/layout/keyboard_layout_engine_unittest.cc",
+          "ozone/layout/xkb/xkb_keyboard_layout_engine_unittest.cc",
+        ]
+      }
 
-  if (is_win) {
-    sources += [ "blink/web_input_event_builders_win_unittest.cc" ]
+      deps += [
+        "//ui/events/ozone:events_ozone",
+        "//ui/events/ozone:events_ozone_evdev",
+        "//ui/events/ozone:events_ozone_layout",
+      ]
+    }
+
+    if (use_aura) {
+      sources += [
+        "gestures/gesture_provider_aura_unittest.cc",
+        "gestures/motion_event_aura_unittest.cc",
+      ]
+    }
+
+    if (is_android) {
+      sources += [ "android/motion_event_android_unittest.cc" ]
+    }
+
+    if (is_ios) {
+      assert_no_deps = ios_assert_no_deps
+    }
+
+    if (is_win) {
+      sources += [ "blink/web_input_event_builders_win_unittest.cc" ]
+    }
   }
 }
 
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js
index bc23f24..c2ead981 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -548,8 +548,8 @@
     chrome.commandLinePrivate.hasSwitch(
         'disable-files-quick-view', function(disabled) {
           if (!disabled) {
-            this.quickViewUma_ =
-                new QuickViewUma(assert(this.volumeManager_));
+            this.quickViewUma_ = new QuickViewUma(
+                assert(this.volumeManager_), assert(this.dialogType));
             this.quickViewController_ = new QuickViewController(
                 quickView, assert(this.metadataModel_),
                 assert(this.selectionHandler_),
diff --git a/ui/file_manager/file_manager/foreground/js/quick_view_uma.js b/ui/file_manager/file_manager/foreground/js/quick_view_uma.js
index c7b73fa..66d7df66 100644
--- a/ui/file_manager/file_manager/foreground/js/quick_view_uma.js
+++ b/ui/file_manager/file_manager/foreground/js/quick_view_uma.js
@@ -6,16 +6,22 @@
  * UMA exporter for Quick View.
  *
  * @param {!VolumeManagerWrapper} volumeManager
+ * @param {!DialogType} dialogType
  *
  * @constructor
  */
-function QuickViewUma(volumeManager) {
+function QuickViewUma(volumeManager, dialogType) {
 
   /**
    * @type {!VolumeManagerWrapper}
    * @private
    */
   this.volumeManager_ = volumeManager;
+  /**
+   * @type {DialogType}
+   * @private
+   */
+  this.dialogType_ = dialogType;
 }
 
 /**
@@ -73,4 +79,13 @@
   } else {
     console.error('Unknown volume type: ' + volumeType);
   }
+  // Record stats of dialog types. It must be in sync with
+  // FileDialogType enum in tools/metrics/histograms/histogram.xml.
+  metrics.recordEnum('QuickView.DialogType', this.dialogType_,
+      [DialogType.SELECT_FOLDER,
+       DialogType.SELECT_UPLOAD_FOLDER,
+       DialogType.SELECT_SAVEAS_FILE,
+       DialogType.SELECT_OPEN_FILE,
+       DialogType.SELECT_OPEN_MULTI_FILE,
+       DialogType.FULL_PAGE]);
 };
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn
index c50ffa0..110c3f2 100644
--- a/ui/gfx/BUILD.gn
+++ b/ui/gfx/BUILD.gn
@@ -261,7 +261,6 @@
     "//base:i18n",
     "//base/third_party/dynamic_annotations",
     "//skia",
-    "//third_party/harfbuzz-ng",
     "//third_party/libpng",
     "//third_party/qcms",
     "//third_party/zlib",
@@ -310,7 +309,10 @@
     sources += [ "scoped_cg_context_save_gstate_mac.h" ]
     set_sources_assignment_filter(sources_assignment_filter)
   } else {
-    deps += [ "//third_party:jpeg" ]
+    deps += [
+      "//third_party:jpeg",
+      "//third_party/harfbuzz-ng",
+    ]
   }
 
   # Android.
diff --git a/ui/gfx/transform.cc b/ui/gfx/transform.cc
index 6a44391..9c8a0053 100644
--- a/ui/gfx/transform.cc
+++ b/ui/gfx/transform.cc
@@ -246,10 +246,13 @@
   if (!IsIdentityOrTranslation())
     return false;
 
+  float t[] = {matrix_.get(0, 3), matrix_.get(1, 3), matrix_.get(2, 3)};
   bool no_fractional_translation =
-      static_cast<int>(matrix_.get(0, 3)) == matrix_.get(0, 3) &&
-      static_cast<int>(matrix_.get(1, 3)) == matrix_.get(1, 3) &&
-      static_cast<int>(matrix_.get(2, 3)) == matrix_.get(2, 3);
+      base::IsValueInRangeForNumericType<int>(t[0]) &&
+      base::IsValueInRangeForNumericType<int>(t[1]) &&
+      base::IsValueInRangeForNumericType<int>(t[2]) &&
+      static_cast<int>(t[0]) == t[0] && static_cast<int>(t[1]) == t[1] &&
+      static_cast<int>(t[2]) == t[2];
 
   return no_fractional_translation;
 }
diff --git a/ui/gfx/transform.h b/ui/gfx/transform.h
index 469f6e03..a942bd6c 100644
--- a/ui/gfx/transform.h
+++ b/ui/gfx/transform.h
@@ -140,8 +140,10 @@
            matrix_.get(2, 2) > 0.0;
   }
 
-  // Returns true if the matrix is either identity or pure, non-fractional
-  // translation.
+  // Returns true if the matrix is identity or, if the matrix consists only
+  // of a translation whose components can be represented as integers. Returns
+  // false if the translation contains a fractional component or is too large to
+  // fit in an integer.
   bool IsIdentityOrIntegerTranslation() const;
 
   // Returns true if the matrix had only scaling components.
diff --git a/ui/gfx/transform_unittest.cc b/ui/gfx/transform_unittest.cc
index 8d99b6e..136f4198 100644
--- a/ui/gfx/transform_unittest.cc
+++ b/ui/gfx/transform_unittest.cc
@@ -1345,6 +1345,16 @@
   transform.MakeIdentity();
   transform.Translate3d(0, 0, 8.9f);
   EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation());
+
+  float max_int = std::numeric_limits<int>::max();
+  transform.MakeIdentity();
+  transform.Translate3d(0, 0, max_int + 1000.5f);
+  EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation());
+
+  float max_float = std::numeric_limits<float>::max();
+  transform.MakeIdentity();
+  transform.Translate3d(0, 0, max_float - 0.5f);
+  EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation());
 }
 
 TEST(XFormTest, verifyMatrixInversion) {
diff --git a/ui/native_theme/native_theme_aura.cc b/ui/native_theme/native_theme_aura.cc
index 4b6742f..a58674c1 100644
--- a/ui/native_theme/native_theme_aura.cc
+++ b/ui/native_theme/native_theme_aura.cc
@@ -32,15 +32,6 @@
 // this painting code are defined in overlay_scrollbar_constants_aura.h.
 constexpr int kOverlayScrollbarStrokeWidth = 1;
 constexpr int kOverlayScrollbarMinimumLength = 12;
-constexpr SkAlpha kOverlayScrollbarAlphaNormal = 0x4D;
-constexpr SkAlpha kOverlayScrollbarAlphaHovered = 0x80;
-constexpr SkAlpha kOverlayScrollbarAlphaPressed = 0x80;
-
-// Indexed by ScrollbarOverlayColorTheme.
-constexpr SkColor kOverlayScrollbarThumbColor[] = {SK_ColorBLACK,
-                                                   SK_ColorWHITE};
-constexpr SkColor kOverlayScrollbarStrokeColor[] = {SK_ColorWHITE,
-                                                    SK_ColorBLACK};
 
 const SkColor kTrackColor = SkColorSetRGB(0xF1, 0xF1, 0xF1);
 
@@ -195,35 +186,54 @@
   TRACE_EVENT0("blink", "NativeThemeAura::PaintScrollbarThumb");
 
   SkAlpha thumb_alpha = SK_AlphaTRANSPARENT;
-  const bool overlay = use_overlay_scrollbars_;
-  switch (state) {
-    case NativeTheme::kDisabled:
-      thumb_alpha = SK_AlphaTRANSPARENT;
-      break;
-    case NativeTheme::kHovered:
-      thumb_alpha = overlay ? kOverlayScrollbarAlphaHovered : 0x4D;
-      break;
-    case NativeTheme::kNormal:
-      thumb_alpha = overlay ? kOverlayScrollbarAlphaNormal : 0x33;
-      break;
-    case NativeTheme::kPressed:
-      thumb_alpha = overlay ? kOverlayScrollbarAlphaPressed : 0x80;
-      break;
-    case NativeTheme::kNumStates:
-      NOTREACHED();
-      break;
-  }
-
   gfx::Rect thumb_rect(rect);
   SkColor thumb_color;
-  if (overlay) {
+
+  if (use_overlay_scrollbars_) {
+    // Constants used for painting overlay scrollbar thumb.
+    constexpr SkAlpha kOverlayScrollbarFillAlphaNormal = 0x4D;
+    constexpr SkAlpha kOverlayScrollbarFillAlphaHovered = 0x80;
+    constexpr SkAlpha kOverlayScrollbarFillAlphaPressed = 0x80;
+    constexpr SkAlpha kOverlayScrollbarStrokeAlphaNormal = 0x4D;
+    constexpr SkAlpha kOverlayScrollbarStrokeAlphaHovered = 0x58;
+    constexpr SkAlpha kOverlayScrollbarStrokeAlphaPressed = 0x80;
+
+    // Indexed by ScrollbarOverlayColorTheme.
+    constexpr SkColor kOverlayScrollbarThumbColor[] = {SK_ColorBLACK,
+                                                       SK_ColorWHITE};
+    constexpr SkColor kOverlayScrollbarStrokeColor[] = {SK_ColorWHITE,
+                                                        SK_ColorBLACK};
+
     thumb_color = kOverlayScrollbarThumbColor[theme];
 
+    SkAlpha stroke_alpha = SK_AlphaTRANSPARENT;
+    switch (state) {
+      case NativeTheme::kDisabled:
+        thumb_alpha = SK_AlphaTRANSPARENT;
+        stroke_alpha = SK_AlphaTRANSPARENT;
+        break;
+      case NativeTheme::kHovered:
+        thumb_alpha = kOverlayScrollbarFillAlphaHovered;
+        stroke_alpha = kOverlayScrollbarStrokeAlphaHovered;
+        break;
+      case NativeTheme::kNormal:
+        thumb_alpha = kOverlayScrollbarFillAlphaNormal;
+        stroke_alpha = kOverlayScrollbarStrokeAlphaNormal;
+        break;
+      case NativeTheme::kPressed:
+        thumb_alpha = kOverlayScrollbarFillAlphaPressed;
+        stroke_alpha = kOverlayScrollbarStrokeAlphaPressed;
+        break;
+      case NativeTheme::kNumStates:
+        NOTREACHED();
+        break;
+    }
+
     // In overlay mode, draw a stroke (border).
     constexpr int kStrokeWidth = kOverlayScrollbarStrokeWidth;
     SkPaint paint;
     paint.setColor(
-        SkColorSetA(kOverlayScrollbarStrokeColor[theme], thumb_alpha));
+        SkColorSetA(kOverlayScrollbarStrokeColor[theme], stroke_alpha));
     paint.setStyle(SkPaint::kStroke_Style);
     paint.setStrokeWidth(kStrokeWidth);
 
@@ -235,6 +245,23 @@
     // Inset the all the edges edges so we fill-in the stroke below.
     thumb_rect.Inset(kStrokeWidth, kStrokeWidth);
   } else {
+    switch (state) {
+      case NativeTheme::kDisabled:
+        thumb_alpha = SK_AlphaTRANSPARENT;
+        break;
+      case NativeTheme::kHovered:
+        thumb_alpha = 0x4D;
+        break;
+      case NativeTheme::kNormal:
+        thumb_alpha = 0x33;
+        break;
+      case NativeTheme::kPressed:
+        thumb_alpha = 0x80;
+        break;
+      case NativeTheme::kNumStates:
+        NOTREACHED();
+        break;
+    }
     // If there are no scrollbuttons then provide some padding so that the thumb
     // doesn't touch the top of the track.
     const int kThumbPadding = 2;
diff --git a/ui/resources/default_100_percent/panel_bottom_left_corner.png b/ui/resources/default_100_percent/panel_bottom_left_corner.png
deleted file mode 100644
index 2a3d843..0000000
--- a/ui/resources/default_100_percent/panel_bottom_left_corner.png
+++ /dev/null
Binary files differ
diff --git a/ui/resources/default_100_percent/panel_bottom_right_corner.png b/ui/resources/default_100_percent/panel_bottom_right_corner.png
deleted file mode 100644
index 32aaee7..0000000
--- a/ui/resources/default_100_percent/panel_bottom_right_corner.png
+++ /dev/null
Binary files differ
diff --git a/ui/resources/default_100_percent/panel_top_left_corner.png b/ui/resources/default_100_percent/panel_top_left_corner.png
deleted file mode 100644
index ed52ffd..0000000
--- a/ui/resources/default_100_percent/panel_top_left_corner.png
+++ /dev/null
Binary files differ
diff --git a/ui/resources/default_100_percent/panel_top_right_corner.png b/ui/resources/default_100_percent/panel_top_right_corner.png
deleted file mode 100644
index 3f56e1fb..0000000
--- a/ui/resources/default_100_percent/panel_top_right_corner.png
+++ /dev/null
Binary files differ
diff --git a/ui/resources/ui_resources.grd b/ui/resources/ui_resources.grd
index 7dd3885..ea73b366 100644
--- a/ui/resources/ui_resources.grd
+++ b/ui/resources/ui_resources.grd
@@ -174,12 +174,6 @@
         <structure type="chrome_scaled_image" name="IDR_OOBE_ACTION_BOX_BUTTON_NORMAL" file="cros/action_box_button_normal.png" />
         <structure type="chrome_scaled_image" name="IDR_OOBE_ACTION_BOX_BUTTON_PRESSED" file="cros/action_box_button_pressed.png" />
       </if>
-      <if expr="toolkit_views">
-        <structure type="chrome_scaled_image" name="IDR_PANEL_TOP_LEFT_CORNER" file="panel_top_left_corner.png" />
-        <structure type="chrome_scaled_image" name="IDR_PANEL_TOP_RIGHT_CORNER" file="panel_top_right_corner.png" />
-        <structure type="chrome_scaled_image" name="IDR_PANEL_BOTTOM_LEFT_CORNER" file="panel_bottom_left_corner.png" />
-        <structure type="chrome_scaled_image" name="IDR_PANEL_BOTTOM_RIGHT_CORNER" file="panel_bottom_right_corner.png" />
-      </if>
       <if expr="not is_android and not is_ios">
         <structure type="chrome_scaled_image" name="IDR_SIGNAL_0_BAR" file="common/signal_0_bar.png" />
         <structure type="chrome_scaled_image" name="IDR_SIGNAL_1_BAR" file="common/signal_1_bar.png" />
diff --git a/ui/wm/core/shadow.cc b/ui/wm/core/shadow.cc
index 05174d2..22e12576 100644
--- a/ui/wm/core/shadow.cc
+++ b/ui/wm/core/shadow.cc
@@ -130,13 +130,37 @@
   shadow_layer_->SetFillsBoundsOpaquely(false);
   layer()->Add(shadow_layer_.get());
 
-  const ShadowDetails& details = GetDetailsForElevation(ElevationForStyle());
-  shadow_layer_->UpdateNinePatchLayerImage(details.ninebox_image);
   UpdateLayerBounds();
 }
 
 void Shadow::UpdateLayerBounds() {
-  const ShadowDetails& details = GetDetailsForElevation(ElevationForStyle());
+  if (content_bounds_.IsEmpty())
+    return;
+
+  // The elevation depends on the style, but the ninebox assumption breaks down
+  // when the window is too small. The height/width of |blur_region| will be
+  // 4 * elevation (see GetDetailsForElevation), so cap elevation at the most we
+  // can handle.
+  const int smaller_dimension =
+      std::min(content_bounds_.width(), content_bounds_.height());
+  const int size_adjusted_elevation = std::min(
+      (smaller_dimension - 2 * kRoundedCornerRadius) / 4, ElevationForStyle());
+  const ShadowDetails& details =
+      GetDetailsForElevation(size_adjusted_elevation);
+  gfx::Insets blur_region = gfx::ShadowValue::GetBlurRegion(details.values) +
+                            gfx::Insets(kRoundedCornerRadius);
+  if (size_adjusted_elevation != effective_elevation_) {
+    shadow_layer_->UpdateNinePatchLayerImage(details.ninebox_image);
+    // The ninebox grid is defined in terms of the image size. The shadow blurs
+    // in both inward and outward directions from the edge of the contents, so
+    // the aperture goes further inside the image than the shadow margins (which
+    // represent exterior blur).
+    gfx::Rect aperture(details.ninebox_image.size());
+    aperture.Inset(blur_region);
+    shadow_layer_->UpdateNinePatchLayerAperture(aperture);
+  }
+  effective_elevation_ = size_adjusted_elevation;
+
   // Shadow margins are negative, so this expands outwards from
   // |content_bounds_|.
   const gfx::Insets margins = gfx::ShadowValue::GetMargin(details.values);
@@ -174,32 +198,10 @@
   occlusion_bounds.Inset(-margins + gfx::Insets(kRoundedCornerRadius));
   shadow_layer_->UpdateNinePatchOcclusion(occlusion_bounds);
 
-  // The border is more or less the same inset as the aperture, but can be no
-  // larger than the shadow layer. When the shadow layer is too small, shrink
-  // the dimensions proportionally.
-  gfx::Insets blur_region = gfx::ShadowValue::GetBlurRegion(details.values) +
-                            gfx::Insets(kRoundedCornerRadius);
-  int border_w = std::min(blur_region.width(), shadow_layer_bounds.width());
-  int border_x = border_w * blur_region.left() / blur_region.width();
-  int border_h = std::min(blur_region.height(), shadow_layer_bounds.height());
-  int border_y = border_h * blur_region.top() / blur_region.height();
+  // The border is the same inset as the aperture.
   shadow_layer_->UpdateNinePatchLayerBorder(
-      gfx::Rect(border_x, border_y, border_w, border_h));
-
-  // The ninebox grid is defined in terms of the image size. The shadow blurs in
-  // both inward and outward directions from the edge of the contents, so the
-  // aperture goes further inside the image than the shadow margins (which
-  // represent exterior blur).
-  gfx::Rect aperture(details.ninebox_image.size());
-  // The insets for the aperture are nominally |blur_region| but we need to
-  // resize them if the contents are too small.
-  // TODO(estade): by cutting out parts of ninebox, we lose the smooth
-  // horizontal or vertical transition. This isn't very noticeable, but we may
-  // need to address it by using a separate shadow layer for each ShadowValue,
-  // by adjusting the shadow for very small windows, or other means.
-  aperture.Inset(gfx::Insets(border_y, border_x, border_h - border_y,
-                             border_w - border_x));
-  shadow_layer_->UpdateNinePatchLayerAperture(aperture);
+      gfx::Rect(blur_region.left(), blur_region.top(), blur_region.width(),
+                blur_region.height()));
 }
 
 int Shadow::ElevationForStyle() {
diff --git a/ui/wm/core/shadow.h b/ui/wm/core/shadow.h
index bc7053f..8117c46 100644
--- a/ui/wm/core/shadow.h
+++ b/ui/wm/core/shadow.h
@@ -92,6 +92,9 @@
   // Bounds of the content that the shadow encloses.
   gfx::Rect content_bounds_;
 
+  // The elevation of the shadow image that's currently set on |shadow_layer_|.
+  int effective_elevation_ = 0;
+
   DISALLOW_COPY_AND_ASSIGN(Shadow);
 };
 
diff --git a/ui/wm/core/shadow_unittest.cc b/ui/wm/core/shadow_unittest.cc
index 7416c39..b4b1f73 100644
--- a/ui/wm/core/shadow_unittest.cc
+++ b/ui/wm/core/shadow_unittest.cc
@@ -10,6 +10,10 @@
 namespace wm {
 namespace {
 
+gfx::Insets InsetsForElevation(int elevation) {
+  return -gfx::Insets(2 * elevation) + gfx::Insets(elevation, 0, -elevation, 0);
+}
+
 using ShadowTest = aura::test::AuraTestBase;
 
 // Test if the proper content bounds is calculated based on the current style.
@@ -22,9 +26,7 @@
     shadow.SetContentBounds(content_bounds);
     EXPECT_EQ(content_bounds, shadow.content_bounds());
     gfx::Rect shadow_bounds(content_bounds);
-    int elevation = 24;
-    shadow_bounds.Inset(-gfx::Insets(2 * elevation) +
-                        gfx::Insets(elevation, 0, -elevation, 0));
+    shadow_bounds.Inset(InsetsForElevation(24));
     EXPECT_EQ(shadow_bounds, shadow.layer()->bounds());
   }
 
@@ -34,9 +36,39 @@
     shadow.SetContentBounds(content_bounds);
     EXPECT_EQ(content_bounds, shadow.content_bounds());
     gfx::Rect shadow_bounds(content_bounds);
-    int elevation = 6;
-    shadow_bounds.Inset(-gfx::Insets(2 * elevation) +
-                        gfx::Insets(elevation, 0, -elevation, 0));
+    shadow_bounds.Inset(InsetsForElevation(6));
+    EXPECT_EQ(shadow_bounds, shadow.layer()->bounds());
+  }
+}
+
+// Test that the elevation is reduced when the contents are too small to handle
+// the full elevation.
+TEST_F(ShadowTest, AdjustElevationForSmallContents) {
+  Shadow shadow;
+  shadow.Init(Shadow::STYLE_ACTIVE);
+  {
+    gfx::Rect content_bounds(100, 100, 300, 300);
+    shadow.SetContentBounds(content_bounds);
+    gfx::Rect shadow_bounds(content_bounds);
+    shadow_bounds.Inset(InsetsForElevation(24));
+    EXPECT_EQ(shadow_bounds, shadow.layer()->bounds());
+  }
+
+  {
+    constexpr int kWidth = 80;
+    gfx::Rect content_bounds(100, 100, kWidth, 300);
+    shadow.SetContentBounds(content_bounds);
+    gfx::Rect shadow_bounds(content_bounds);
+    shadow_bounds.Inset(InsetsForElevation((kWidth - 4) / 4));
+    EXPECT_EQ(shadow_bounds, shadow.layer()->bounds());
+  }
+
+  {
+    constexpr int kHeight = 80;
+    gfx::Rect content_bounds(100, 100, 300, kHeight);
+    shadow.SetContentBounds(content_bounds);
+    gfx::Rect shadow_bounds(content_bounds);
+    shadow_bounds.Inset(InsetsForElevation((kHeight - 4) / 4));
     EXPECT_EQ(shadow_bounds, shadow.layer()->bounds());
   }
 }