diff --git a/DEPS b/DEPS
index 2e5aaa8..cdd076e 100644
--- a/DEPS
+++ b/DEPS
@@ -39,11 +39,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '3ca73360493ba71831c86c8c5f9c36187c0355ca',
+  'skia_revision': '973d92cf91b21013361209e8a5c0c4685728847f',
   # 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': 'c0eabe60e9260ccca9fc2d119e723fdd91814846',
+  'v8_revision': 'd6a1568f656bfeacd8e85bdd6cddf04fea906336',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
diff --git a/base/android/linker/modern_linker_jni.cc b/base/android/linker/modern_linker_jni.cc
index 1cd18db..53ae405c 100644
--- a/base/android/linker/modern_linker_jni.cc
+++ b/base/android/linker/modern_linker_jni.cc
@@ -290,8 +290,10 @@
 
 // Helper for LoadLibrary(). We reserve an address space larger than
 // needed. After library loading we want to trim that reservation to only
-// what is needed.
-bool ResizeReservedAddressSpace(void* addr,
+// what is needed. Failure to trim should not occur, but if it does then
+// everything will still run, so we treat it as a warning rather than
+// an error.
+void ResizeReservedAddressSpace(void* addr,
                                 size_t reserved_size,
                                 size_t load_size,
                                 size_t min_vaddr) {
@@ -301,38 +303,35 @@
 
   const uintptr_t uintptr_addr = reinterpret_cast<uintptr_t>(addr);
 
-  if (reserved_size < load_size) {
+  if (reserved_size > load_size) {
+    // Unmap the part of the reserved address space that is beyond the end of
+    // the loaded library data.
+    void* unmap = reinterpret_cast<void*>(uintptr_addr + load_size);
+    const size_t length = reserved_size - load_size;
+    if (munmap(unmap, length) == -1) {
+      LOG_ERROR("WARNING: unmap of %d bytes at %p failed: %s",
+                static_cast<int>(length), unmap, strerror(errno));
+    }
+  } else {
     LOG_ERROR("WARNING: library reservation was too small");
-    return true;
-  }
-
-  // Unmap the part of the reserved address space that is beyond the end of
-  // the loaded library data.
-  void* unmap = reinterpret_cast<void*>(uintptr_addr + load_size);
-  size_t length = reserved_size - load_size;
-  if (munmap(unmap, length) == -1) {
-    LOG_ERROR("Failed to unmap %d at %p", static_cast<int>(length), unmap);
-    return false;
   }
 
 #if RESERVE_BREAKPAD_GUARD_REGION
-  if (min_vaddr > kBreakpadGuardRegionBytes) {
+  if (kBreakpadGuardRegionBytes > min_vaddr) {
+    // Unmap the part of the reserved address space that is ahead of where we
+    // actually need the guard region to start. Resizes the guard region to
+    // min_vaddr bytes.
+    void* unmap =
+        reinterpret_cast<void*>(uintptr_addr - kBreakpadGuardRegionBytes);
+    const size_t length = kBreakpadGuardRegionBytes - min_vaddr;
+    if (munmap(unmap, length) == -1) {
+      LOG_ERROR("WARNING: unmap of %d bytes at %p failed: %s",
+                static_cast<int>(length), unmap, strerror(errno));
+    }
+  } else {
     LOG_ERROR("WARNING: breakpad guard region reservation was too small");
-    return true;
-  }
-
-  // Unmap the part of the reserved address space that is ahead of where we
-  // actually need the guard region to start. Resizes the guard region to
-  // min_vaddr bytes.
-  unmap = reinterpret_cast<void*>(uintptr_addr - kBreakpadGuardRegionBytes);
-  length = kBreakpadGuardRegionBytes - min_vaddr;
-  if (munmap(unmap, length) == -1) {
-    LOG_ERROR("Failed to unmap %d at %p", static_cast<int>(length), unmap);
-    return false;
   }
 #endif
-
-  return true;
 }
 
 // Load a library with the chromium linker, using android_dlopen_ext().
@@ -420,17 +419,29 @@
     return false;
   }
 
-  // After loading, trim the mapping to match the library's actual size.
+  // For https://crbug.com/568880.
+  //
+  // Release the scoped mapping. Now that the library has loaded we can no
+  // longer assume we have control of all of this area. libdl knows addr and
+  // has loaded the library into some portion of the reservation. It will
+  // not expect that portion of memory to be arbitrarily unmapped.
+  mapping.Release();
+
+  // After loading we can find the actual size of the library. It should
+  // be less than the space we reserved for it.
   size_t load_size = 0;
   size_t min_vaddr = 0;
   if (!GetLibraryLoadSize(addr, &load_size, &min_vaddr)) {
     LOG_ERROR("Unable to find size for load at %p", addr);
     return false;
   }
-  if (!ResizeReservedAddressSpace(addr, size, load_size, min_vaddr)) {
-    LOG_ERROR("Unable to resize reserved address mapping");
-    return false;
-  }
+
+  // Trim the reservation mapping to match the library's actual size. Failure
+  // to resize is not a fatal error. At worst we lose a portion of virtual
+  // address space that we might otherwise have recovered. Note that trimming
+  // the mapping here requires that we have already released the scoped
+  // mapping.
+  ResizeReservedAddressSpace(addr, size, load_size, min_vaddr);
 
   // Locate and if found then call the loaded library's JNI_OnLoad() function.
   using JNI_OnLoadFunctionPtr = int (*)(void* vm, void* reserved);
@@ -445,9 +456,6 @@
     }
   }
 
-  // Release mapping before returning so that we do not unmap reserved space.
-  mapping.Release();
-
   // Note the load address and load size in the supplied libinfo object.
   const size_t cast_addr = reinterpret_cast<size_t>(addr);
   s_lib_info_fields.SetLoadInfo(env, lib_info_obj, cast_addr, load_size);
@@ -532,11 +540,31 @@
     return false;
   }
 
-  // Unload the library from this address. The reserved space is
-  // automatically unmapped on exit from this function.
+  // For https://crbug.com/568880.
+  //
+  // Release the scoped mapping. See comment in LoadLibrary() above for more.
+  mapping.Release();
+
+  // For https://crbug.com/568880.
+  //
+  // Unload the library from this address. Calling dlclose() will unmap the
+  // part of the reservation occupied by the libary, but will leave the
+  // remainder of the reservation mapped, and we have no effective way of
+  // unmapping the leftover portions because we don't know where dlclose's
+  // unmap ended.
+  //
+  // For now we live with this. It is a loss of some virtual address space
+  // (but not actual memory), and because it occurs only once and only in
+  // the browser process, and never in renderer processes, it is not a
+  // significant issue.
+  //
+  // TODO(simonb): Between mapping.Release() and here, consider calling the
+  // functions that trim the reservation down to the size of the loaded
+  // library. This may help recover some or all of the virtual address space
+  // that is otherwise lost.
   dlclose(handle);
 
-  // Reopen the shared RELFO fd in read-only mode. This ensures that nothing
+  // Reopen the shared RELRO fd in read-only mode. This ensures that nothing
   // can write to it through the RELRO fd that we return in libinfo.
   close(relro_fd);
   relro_fd = open(filepath, O_RDONLY);
diff --git a/base/mac/sdk_forward_declarations.h b/base/mac/sdk_forward_declarations.h
index 363ada1e..99abc909 100644
--- a/base/mac/sdk_forward_declarations.h
+++ b/base/mac/sdk_forward_declarations.h
@@ -330,7 +330,7 @@
 - (void)toggleFullScreen:(id)sender;
 - (void)setRestorable:(BOOL)flag;
 - (NSRect)convertRectFromScreen:(NSRect)aRect;
-- (NSSize)convertRectToScreen:(NSRect)aRect;
+- (NSRect)convertRectToScreen:(NSRect)aRect;
 @end
 
 @interface NSCursor (LionSDKDeclarations)
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 352225f..0ccee99 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -3902,6 +3902,12 @@
         <message name="IDS_EXTENSION_PROMPT_WARNING_HOSTS_LIST_READ_ONLY" desc="Permission string for read-only access to data for an arbitrary list of websites.">
           Read your data on a number of websites
         </message>
+        <message name="IDS_EXTENSION_PROMPT_WARNING_HOST_AND_SUBDOMAIN" desc="Permission string requesting access to data on a website and its sub-domains.">
+          all <ph name="WEBSITE_1">$1<ex>google.com</ex></ph> sites
+        </message>
+        <message name="IDS_EXTENSION_PROMPT_WARNING_HOST_AND_SUBDOMAIN_LIST" desc="Single entry permission string requesting access to data on a website and its sub-domains.">
+          All <ph name="WEBSITE_1">$1<ex>google.com</ex></ph> sites
+        </message>
         <message name="IDS_EXTENSION_PROMPT_WARNING_INPUT" desc="Permission string for access to input.">
           Read and change anything you type
         </message>
diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h
index 008fae1..49c9726f9 100644
--- a/chrome/browser/profiles/profile_impl.h
+++ b/chrome/browser/profiles/profile_impl.h
@@ -64,7 +64,7 @@
 }
 
 namespace user_prefs {
-class refRegistrySyncable;
+class PrefRegistrySyncable;
 }
 
 // The default profile implementation.
diff --git a/chrome/browser/ui/passwords/account_chooser_prompt.h b/chrome/browser/ui/passwords/account_chooser_prompt.h
index 9848073d2..d8d6d4c 100644
--- a/chrome/browser/ui/passwords/account_chooser_prompt.h
+++ b/chrome/browser/ui/passwords/account_chooser_prompt.h
@@ -5,6 +5,12 @@
 #ifndef CHROME_BROWSER_UI_PASSWORDS_ACCOUNT_CHOOSER_PROMPT_H_
 #define CHROME_BROWSER_UI_PASSWORDS_ACCOUNT_CHOOSER_PROMPT_H_
 
+namespace content {
+class WebContents;
+}
+
+class PasswordDialogController;
+
 // A platform-independent interface for the account chooser dialog.
 class AccountChooserPrompt {
  public:
@@ -18,6 +24,8 @@
   virtual ~AccountChooserPrompt() = default;
 };
 
-
+// Factory function for AccountChooserPrompt on desktop platforms.
+AccountChooserPrompt* CreateAccountChooserPromptView(
+    PasswordDialogController* controller, content::WebContents* web_contents);
 
 #endif  // CHROME_BROWSER_UI_PASSWORDS_ACCOUNT_CHOOSER_PROMPT_H_
diff --git a/chrome/browser/ui/passwords/manage_passwords_test.cc b/chrome/browser/ui/passwords/manage_passwords_test.cc
index b3dfb7b..973c8c6 100644
--- a/chrome/browser/ui/passwords/manage_passwords_test.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_test.cc
@@ -78,20 +78,6 @@
   GetController()->OnAutomaticPasswordSave(std::move(test_form_manager));
 }
 
-void ManagePasswordsTest::SetupChooseCredentials(
-    ScopedVector<autofill::PasswordForm> local_credentials,
-    ScopedVector<autofill::PasswordForm> federated_credentials,
-    const GURL& origin) {
-  base::string16 kTestUsername = base::ASCIIToUTF16("test_username");
-  autofill::PasswordFormMap map;
-  map.insert(std::make_pair(
-      kTestUsername,
-      make_scoped_ptr(new autofill::PasswordForm(*test_form()))));
-  GetController()->OnChooseCredentials(
-      std::move(local_credentials), std::move(federated_credentials), origin,
-      base::Bind(&ManagePasswordsTest::OnChooseCredential, this));
-}
-
 void ManagePasswordsTest::SetupAutoSignin(
     ScopedVector<autofill::PasswordForm> local_credentials) {
   GetController()->OnAutoSignin(std::move(local_credentials));
diff --git a/chrome/browser/ui/passwords/manage_passwords_test.h b/chrome/browser/ui/passwords/manage_passwords_test.h
index 60c3cd9..3eda4b1 100644
--- a/chrome/browser/ui/passwords/manage_passwords_test.h
+++ b/chrome/browser/ui/passwords/manage_passwords_test.h
@@ -44,12 +44,6 @@
   // Put the controller, icon, and bubble into a pending-password state.
   void SetupPendingPassword();
 
-  // Put the controller, icon, and bubble into a choosing credential state.
-  void SetupChooseCredentials(
-      ScopedVector<autofill::PasswordForm> local_credentials,
-      ScopedVector<autofill::PasswordForm> federated_credentials,
-      const GURL& origin);
-
   // Put the controller, icon, and bubble into an auto sign-in state.
   void SetupAutoSignin(
       ScopedVector<autofill::PasswordForm> local_credentials);
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
index ad06a11..a1394be 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
@@ -17,7 +17,9 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/location_bar/location_bar.h"
+#include "chrome/browser/ui/passwords/account_chooser_prompt.h"
 #include "chrome/browser/ui/passwords/manage_passwords_icon_view.h"
+#include "chrome/browser/ui/passwords/password_dialog_controller_impl.h"
 #include "chrome/browser/ui/tab_dialogs.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
@@ -42,6 +44,14 @@
              ServiceAccessType::EXPLICIT_ACCESS).get();
 }
 
+std::vector<scoped_ptr<autofill::PasswordForm>> CopyFormVector(
+    const ScopedVector<autofill::PasswordForm>& forms) {
+  std::vector<scoped_ptr<autofill::PasswordForm>> result(forms.size());
+  for (size_t i = 0; i < forms.size(); ++i)
+    result[i].reset(new autofill::PasswordForm(*forms[i]));
+  return result;
+}
+
 }  // namespace
 
 DEFINE_WEB_CONTENTS_USER_DATA_KEY(ManagePasswordsUIController);
@@ -88,9 +98,24 @@
     const GURL& origin,
     base::Callback<void(const password_manager::CredentialInfo&)> callback) {
   DCHECK(!local_credentials.empty() || !federated_credentials.empty());
+  PasswordDialogController::FormsVector locals =
+      CopyFormVector(local_credentials);
+  PasswordDialogController::FormsVector federations =
+      CopyFormVector(federated_credentials);
   passwords_data_.OnRequestCredentials(
       std::move(local_credentials), std::move(federated_credentials), origin);
+#if defined(OS_MACOSX)
+  // TODO(vasilii): remove once Mac supports the dialog.
+  // http://crbug.com/550922
   base::AutoReset<bool> resetter(&should_pop_up_bubble_, true);
+#else
+  dialog_controller_.reset(new PasswordDialogControllerImpl(
+      Profile::FromBrowserContext(web_contents()->GetBrowserContext()),
+      this));
+  dialog_controller_->ShowAccountChooser(
+      CreateAccountChooser(dialog_controller_.get()),
+      std::move(locals), std::move(federations));
+#endif
   UpdateBubbleAndIconVisibility();
   if (!should_pop_up_bubble_) {
     passwords_data_.set_credentials_callback(callback);
@@ -142,12 +167,18 @@
 void ManagePasswordsUIController::UpdateIconAndBubbleState(
     ManagePasswordsIconView* icon) {
   if (should_pop_up_bubble_) {
+    DCHECK(!dialog_controller_);
     // We must display the icon before showing the bubble, as the bubble would
     // be otherwise unanchored.
     icon->SetState(GetState());
     ShowBubbleWithoutUserInteraction();
   } else {
-    icon->SetState(GetState());
+    password_manager::ui::State state = GetState();
+    // The dialog should hide the icon.
+    if (dialog_controller_ &&
+        state == password_manager::ui::CREDENTIAL_REQUEST_STATE)
+      state = password_manager::ui::INACTIVE_STATE;
+    icon->SetState(state);
   }
 }
 
@@ -204,6 +235,7 @@
 }
 
 void ManagePasswordsUIController::OnBubbleHidden() {
+  dialog_controller_.reset();
   if (GetState() == password_manager::ui::CREDENTIAL_REQUEST_STATE ||
       GetState() == password_manager::ui::CONFIRMATION_STATE ||
       GetState() == password_manager::ui::AUTO_SIGNIN_STATE) {
@@ -256,6 +288,11 @@
     const autofill::PasswordForm& form,
     password_manager::CredentialType credential_type) {
   passwords_data_.ChooseCredential(form, credential_type);
+  if (dialog_controller_) {
+    dialog_controller_.reset();
+    passwords_data_.TransitionToState(password_manager::ui::MANAGE_STATE);
+    UpdateBubbleAndIconVisibility();
+  }
 }
 
 void ManagePasswordsUIController::NavigateToExternalPasswordManager() {
@@ -324,6 +361,19 @@
   location_bar->UpdateManagePasswordsIconAndBubble();
 }
 
+#if defined(OS_MACOSX)
+// TODO(vasilii): remove once Mac supports the dialog.
+AccountChooserPrompt* ManagePasswordsUIController::CreateAccountChooser(
+    PasswordDialogController* controller) {
+  return nullptr;
+}
+#else
+AccountChooserPrompt* ManagePasswordsUIController::CreateAccountChooser(
+    PasswordDialogController* controller) {
+  return CreateAccountChooserPromptView(controller, web_contents());
+}
+#endif
+
 void ManagePasswordsUIController::DidNavigateMainFrame(
     const content::LoadCommittedDetails& details,
     const content::FrameNavigateParams& params) {
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller.h b/chrome/browser/ui/passwords/manage_passwords_ui_controller.h
index 6f31d1b..ecbf087 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller.h
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller.h
@@ -25,7 +25,10 @@
 class PasswordFormManager;
 }
 
+class AccountChooserPrompt;
 class ManagePasswordsIconView;
+class PasswordDialogController;
+class PasswordDialogControllerImpl;
 
 // Per-tab class to control the Omnibox password icon and bubble.
 class ManagePasswordsUIController
@@ -105,6 +108,10 @@
   // manage passwords icon and bubble.
   virtual void UpdateBubbleAndIconVisibility();
 
+  // Called to create the account chooser dialog. Mocked in tests.
+  virtual AccountChooserPrompt* CreateAccountChooser(
+      PasswordDialogController* controller);
+
   // Overwrites the client for |passwords_data_|.
   void set_client(password_manager::PasswordManagerClient* client) {
     passwords_data_.set_client(client);
@@ -128,6 +135,9 @@
   // The wrapper around current state and data.
   ManagePasswordsState passwords_data_;
 
+  // The controller for the blocking dialogs.
+  scoped_ptr<PasswordDialogControllerImpl> dialog_controller_;
+
   // Contains true if the bubble is to be popped up in the next call to
   // UpdateBubbleAndIconVisibility().
   bool should_pop_up_bubble_;
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller_unittest.cc b/chrome/browser/ui/passwords/manage_passwords_ui_controller_unittest.cc
index 2c451dd..1204dba 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller_unittest.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller_unittest.cc
@@ -12,9 +12,11 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "chrome/browser/ui/passwords/account_chooser_prompt.h"
 #include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h"
 #include "chrome/browser/ui/passwords/manage_passwords_icon_view.h"
 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller_mock.h"
+#include "chrome/browser/ui/passwords/password_dialog_controller.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/autofill/core/common/password_form.h"
@@ -33,14 +35,24 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using ::testing::DoAll;
 using ::testing::ElementsAre;
 using ::testing::Pointee;
+using ::testing::Return;
+using ::testing::SaveArg;
+using ::testing::_;
 
 namespace {
 
 // Number of dismissals that for sure supresses the bubble.
 const int kGreatDissmisalCount = 10;
 
+class AccountChooserPromptMock : public AccountChooserPrompt {
+ public:
+  MOCK_METHOD0(Show, void());
+  MOCK_METHOD0(ControllerGone, void());
+};
+
 class TestManagePasswordsIconView : public ManagePasswordsIconView {
  public:
   TestManagePasswordsIconView() {}
@@ -67,6 +79,8 @@
 
   bool opened_bubble() const { return opened_bubble_; }
 
+  MOCK_METHOD1(CreateAccountChooser,
+               AccountChooserPrompt*(PasswordDialogController*));
   using ManagePasswordsUIController::DidNavigateMainFrame;
 
  private:
@@ -129,46 +143,14 @@
   ManagePasswordsUIControllerTest()
       : password_manager_(&client_), field_trial_list_(nullptr) {}
 
-  void SetUp() override {
-    ChromeRenderViewHostTestHarness::SetUp();
-
-    // Create the test UIController here so that it's bound to
-    // |test_web_contents_|, and will be retrieved correctly via
-    // ManagePasswordsUIController::FromWebContents in |controller()|.
-    new TestManagePasswordsUIController(web_contents(), &client_);
-
-    test_local_form_.origin = GURL("http://example.com/login");
-    test_local_form_.username_value = base::ASCIIToUTF16("username");
-    test_local_form_.password_value = base::ASCIIToUTF16("12345");
-
-    test_federated_form_.origin = GURL("http://example.com/login");
-    test_federated_form_.username_value = base::ASCIIToUTF16("username");
-    test_federated_form_.federation_url = GURL("https://federation.test/");
-
-    // We need to be on a "webby" URL for most tests.
-    content::WebContentsTester::For(web_contents())
-        ->NavigateAndCommit(GURL("http://example.com"));
-  }
-
-  void ExpectIconStateIs(password_manager::ui::State state) {
-// No op on Android, where there is no icon.
-#if !defined(OS_ANDROID)
-    TestManagePasswordsIconView view;
-    controller()->UpdateIconAndBubbleState(&view);
-    EXPECT_EQ(state, view.state());
-#endif
-  }
-
-  void ExpectIconAndControllerStateIs(password_manager::ui::State state) {
-    ExpectIconStateIs(state);
-    EXPECT_EQ(state, controller()->GetState());
-  }
+  void SetUp() override;
 
   autofill::PasswordForm& test_local_form() { return test_local_form_; }
   autofill::PasswordForm& test_federated_form() { return test_federated_form_; }
   password_manager::CredentialInfo* credential_info() const {
     return credential_info_.get();
   }
+  AccountChooserPromptMock& account_chooser() { return account_chooser_; }
 
   TestManagePasswordsUIController* controller() {
     return static_cast<TestManagePasswordsUIController*>(
@@ -179,6 +161,9 @@
     credential_info_.reset(new password_manager::CredentialInfo(info));
   }
 
+  void ExpectIconStateIs(password_manager::ui::State state);
+  void ExpectIconAndControllerStateIs(password_manager::ui::State state);
+
   scoped_ptr<password_manager::PasswordFormManager>
   CreateFormManagerWithBestMatches(
       const autofill::PasswordForm& observed_form,
@@ -195,8 +180,43 @@
   autofill::PasswordForm test_federated_form_;
   scoped_ptr<password_manager::CredentialInfo> credential_info_;
   base::FieldTrialList field_trial_list_;
+  AccountChooserPromptMock account_chooser_;
 };
 
+void ManagePasswordsUIControllerTest::SetUp() {
+  ChromeRenderViewHostTestHarness::SetUp();
+
+  // Create the test UIController here so that it's bound to
+  // |test_web_contents_|, and will be retrieved correctly via
+  // ManagePasswordsUIController::FromWebContents in |controller()|.
+  new TestManagePasswordsUIController(web_contents(), &client_);
+
+  test_local_form_.origin = GURL("http://example.com/login");
+  test_local_form_.username_value = base::ASCIIToUTF16("username");
+  test_local_form_.password_value = base::ASCIIToUTF16("12345");
+
+  test_federated_form_.origin = GURL("http://example.com/login");
+  test_federated_form_.username_value = base::ASCIIToUTF16("username");
+  test_federated_form_.federation_url = GURL("https://federation.test/");
+
+  // We need to be on a "webby" URL for most tests.
+  content::WebContentsTester::For(web_contents())
+  ->NavigateAndCommit(GURL("http://example.com"));
+}
+
+void ManagePasswordsUIControllerTest::ExpectIconStateIs(
+    password_manager::ui::State state) {
+  TestManagePasswordsIconView view;
+  controller()->UpdateIconAndBubbleState(&view);
+  EXPECT_EQ(state, view.state());
+}
+
+void ManagePasswordsUIControllerTest::ExpectIconAndControllerStateIs(
+    password_manager::ui::State state) {
+  ExpectIconStateIs(state);
+  EXPECT_EQ(state, controller()->GetState());
+}
+
 scoped_ptr<password_manager::PasswordFormManager>
 ManagePasswordsUIControllerTest::CreateFormManagerWithBestMatches(
     const autofill::PasswordForm& observed_form,
@@ -433,6 +453,8 @@
   ExpectIconStateIs(password_manager::ui::MANAGE_STATE);
 }
 
+#if defined(OS_MACOSX)
+// TODO(vasilii): remove once Mac supports the account chooser dialog.
 TEST_F(ManagePasswordsUIControllerTest, ChooseCredentialLocal) {
   ScopedVector<autofill::PasswordForm> local_credentials;
   local_credentials.push_back(new autofill::PasswordForm(test_local_form()));
@@ -547,6 +569,138 @@
   EXPECT_EQ(password_manager::CredentialType::CREDENTIAL_TYPE_EMPTY,
             credential_info()->type);
 }
+#else // defined(OS_MACOSX)
+TEST_F(ManagePasswordsUIControllerTest, ChooseCredentialLocal) {
+  ScopedVector<autofill::PasswordForm> local_credentials;
+  local_credentials.push_back(new autofill::PasswordForm(test_local_form()));
+  ScopedVector<autofill::PasswordForm> federated_credentials;
+  GURL origin("http://example.com");
+  PasswordDialogController* dialog_controller = nullptr;
+  EXPECT_CALL(*controller(), CreateAccountChooser(_)).WillOnce(
+      DoAll(SaveArg<0>(&dialog_controller), Return(&account_chooser())));
+  EXPECT_CALL(account_chooser(), Show());
+  EXPECT_TRUE(controller()->OnChooseCredentials(
+      std::move(local_credentials), std::move(federated_credentials), origin,
+      base::Bind(&ManagePasswordsUIControllerTest::CredentialCallback,
+                 base::Unretained(this))));
+  EXPECT_EQ(password_manager::ui::CREDENTIAL_REQUEST_STATE,
+            controller()->GetState());
+  EXPECT_EQ(origin, controller()->GetOrigin());
+  EXPECT_THAT(controller()->GetCurrentForms(),
+              ElementsAre(Pointee(test_local_form())));
+
+  ExpectIconStateIs(password_manager::ui::INACTIVE_STATE);
+
+  EXPECT_CALL(account_chooser(), ControllerGone());
+  dialog_controller->OnChooseCredentials(
+      test_local_form(),
+      password_manager::CredentialType::CREDENTIAL_TYPE_PASSWORD);
+  EXPECT_EQ(password_manager::ui::MANAGE_STATE, controller()->GetState());
+  ASSERT_TRUE(credential_info());
+  EXPECT_EQ(test_local_form().username_value, credential_info()->id);
+  EXPECT_EQ(test_local_form().password_value, credential_info()->password);
+  EXPECT_TRUE(credential_info()->federation.is_empty());
+  EXPECT_EQ(password_manager::CredentialType::CREDENTIAL_TYPE_PASSWORD,
+            credential_info()->type);
+}
+
+TEST_F(ManagePasswordsUIControllerTest, ChooseCredentialLocalButFederated) {
+  ScopedVector<autofill::PasswordForm> local_credentials;
+  local_credentials.push_back(
+      new autofill::PasswordForm(test_federated_form()));
+  ScopedVector<autofill::PasswordForm> federated_credentials;
+  GURL origin("http://example.com");
+  PasswordDialogController* dialog_controller = nullptr;
+  EXPECT_CALL(*controller(), CreateAccountChooser(_)).WillOnce(
+      DoAll(SaveArg<0>(&dialog_controller), Return(&account_chooser())));
+  EXPECT_CALL(account_chooser(), Show());
+  EXPECT_TRUE(controller()->OnChooseCredentials(
+      std::move(local_credentials), std::move(federated_credentials), origin,
+      base::Bind(&ManagePasswordsUIControllerTest::CredentialCallback,
+                 base::Unretained(this))));
+  EXPECT_EQ(password_manager::ui::CREDENTIAL_REQUEST_STATE,
+            controller()->GetState());
+  EXPECT_EQ(origin, controller()->GetOrigin());
+  EXPECT_THAT(controller()->GetCurrentForms(),
+              ElementsAre(Pointee(test_federated_form())));
+
+  ExpectIconStateIs(password_manager::ui::INACTIVE_STATE);
+
+  EXPECT_CALL(account_chooser(), ControllerGone());
+  dialog_controller->OnChooseCredentials(
+      test_federated_form(),
+      password_manager::CredentialType::CREDENTIAL_TYPE_PASSWORD);
+  EXPECT_EQ(password_manager::ui::MANAGE_STATE, controller()->GetState());
+  ASSERT_TRUE(credential_info());
+  EXPECT_EQ(test_federated_form().username_value, credential_info()->id);
+  EXPECT_EQ(test_federated_form().federation_url,
+            credential_info()->federation);
+  EXPECT_TRUE(credential_info()->password.empty());
+  EXPECT_EQ(password_manager::CredentialType::CREDENTIAL_TYPE_FEDERATED,
+            credential_info()->type);
+}
+
+TEST_F(ManagePasswordsUIControllerTest, ChooseCredentialFederated) {
+  ScopedVector<autofill::PasswordForm> local_credentials;
+  ScopedVector<autofill::PasswordForm> federated_credentials;
+  federated_credentials.push_back(
+      new autofill::PasswordForm(test_local_form()));
+  GURL origin("http://example.com");
+  PasswordDialogController* dialog_controller = nullptr;
+  EXPECT_CALL(*controller(), CreateAccountChooser(_)).WillOnce(
+      DoAll(SaveArg<0>(&dialog_controller), Return(&account_chooser())));
+  EXPECT_CALL(account_chooser(), Show());
+  EXPECT_TRUE(controller()->OnChooseCredentials(
+      std::move(local_credentials), std::move(federated_credentials), origin,
+      base::Bind(&ManagePasswordsUIControllerTest::CredentialCallback,
+                 base::Unretained(this))));
+  EXPECT_EQ(password_manager::ui::CREDENTIAL_REQUEST_STATE,
+            controller()->GetState());
+  EXPECT_EQ(0u, controller()->GetCurrentForms().size());
+  EXPECT_EQ(origin, controller()->GetOrigin());
+
+  ExpectIconStateIs(password_manager::ui::INACTIVE_STATE);
+
+  EXPECT_CALL(account_chooser(), ControllerGone());
+  dialog_controller->OnChooseCredentials(
+     test_local_form(),
+      password_manager::CredentialType::CREDENTIAL_TYPE_FEDERATED);
+  controller()->OnBubbleHidden();
+  EXPECT_EQ(password_manager::ui::MANAGE_STATE, controller()->GetState());
+  ASSERT_TRUE(credential_info());
+  EXPECT_EQ(test_local_form().username_value, credential_info()->id);
+  EXPECT_TRUE(credential_info()->password.empty());
+  EXPECT_EQ(password_manager::CredentialType::CREDENTIAL_TYPE_FEDERATED,
+            credential_info()->type);
+}
+
+TEST_F(ManagePasswordsUIControllerTest, ChooseCredentialCancel) {
+  ScopedVector<autofill::PasswordForm> local_credentials;
+  local_credentials.push_back(new autofill::PasswordForm(test_local_form()));
+  ScopedVector<autofill::PasswordForm> federated_credentials;
+  GURL origin("http://example.com");
+  PasswordDialogController* dialog_controller = nullptr;
+  EXPECT_CALL(*controller(), CreateAccountChooser(_)).WillOnce(
+      DoAll(SaveArg<0>(&dialog_controller), Return(&account_chooser())));
+  EXPECT_CALL(account_chooser(), Show());
+  EXPECT_TRUE(controller()->OnChooseCredentials(
+      std::move(local_credentials), std::move(federated_credentials), origin,
+      base::Bind(&ManagePasswordsUIControllerTest::CredentialCallback,
+                 base::Unretained(this))));
+  EXPECT_EQ(password_manager::ui::CREDENTIAL_REQUEST_STATE,
+            controller()->GetState());
+  EXPECT_EQ(origin, controller()->GetOrigin());
+
+  EXPECT_CALL(account_chooser(), ControllerGone()).Times(0);
+  dialog_controller->OnCloseAccountChooser();
+  EXPECT_EQ(password_manager::ui::MANAGE_STATE, controller()->GetState());
+  ASSERT_TRUE(credential_info());
+  EXPECT_TRUE(credential_info()->federation.is_empty());
+  EXPECT_TRUE(credential_info()->password.empty());
+  EXPECT_EQ(password_manager::CredentialType::CREDENTIAL_TYPE_EMPTY,
+            credential_info()->type);
+}
+#endif // defined(OS_MACOSX)
 
 TEST_F(ManagePasswordsUIControllerTest, AutoSignin) {
   ScopedVector<autofill::PasswordForm> local_credentials;
diff --git a/chrome/browser/ui/passwords/password_dialog_controller.h b/chrome/browser/ui/passwords/password_dialog_controller.h
index e6019b3..92dc15e 100644
--- a/chrome/browser/ui/passwords/password_dialog_controller.h
+++ b/chrome/browser/ui/passwords/password_dialog_controller.h
@@ -41,6 +41,9 @@
   virtual void OnChooseCredentials(
       const autofill::PasswordForm& password_form,
       password_manager::CredentialType credential_type) = 0;
+
+  // Called when the account chooser dialog was closed.
+  virtual void OnCloseAccountChooser() = 0;
  protected:
   virtual ~PasswordDialogController() = default;
 };
diff --git a/chrome/browser/ui/passwords/password_dialog_controller_impl.cc b/chrome/browser/ui/passwords/password_dialog_controller_impl.cc
index f70710f..bb4d6ab4c 100644
--- a/chrome/browser/ui/passwords/password_dialog_controller_impl.cc
+++ b/chrome/browser/ui/passwords/password_dialog_controller_impl.cc
@@ -7,6 +7,7 @@
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/ui/passwords/account_chooser_prompt.h"
 #include "chrome/browser/ui/passwords/manage_passwords_view_utils.h"
+#include "chrome/browser/ui/passwords/passwords_model_delegate.h"
 #include "components/autofill/core/common/password_form.h"
 #include "components/browser_sync/browser/profile_sync_service.h"
 #include "components/password_manager/core/browser/password_bubble_experiment.h"
@@ -19,12 +20,17 @@
 }
 }  // namespace
 
-PasswordDialogControllerImpl::PasswordDialogControllerImpl(Profile* profle)
+PasswordDialogControllerImpl::PasswordDialogControllerImpl(
+    Profile* profle,
+    PasswordsModelDelegate* delegate)
     : profile_(profle),
+      delegate_(delegate),
       current_dialog_(nullptr) {
 }
 
-PasswordDialogControllerImpl::~PasswordDialogControllerImpl() = default;
+PasswordDialogControllerImpl::~PasswordDialogControllerImpl() {
+  ResetDialog();
+}
 
 void PasswordDialogControllerImpl::ShowAccountChooser(
     AccountChooserPrompt* dialog,
@@ -58,14 +64,20 @@
 }
 
 void PasswordDialogControllerImpl::OnSmartLockLinkClicked() {
-  // TODO(vasilii): notify the UI controller.
+  delegate_->NavigateToExternalPasswordManager();
 }
 
 void PasswordDialogControllerImpl::OnChooseCredentials(
     const autofill::PasswordForm& password_form,
     password_manager::CredentialType credential_type) {
   ResetDialog();
-  // TODO(vasilii): notify the UI controller.
+  delegate_->ChooseCredential(password_form, credential_type);
+}
+
+void PasswordDialogControllerImpl::OnCloseAccountChooser() {
+  current_dialog_ = nullptr;
+  // The dialog isn't a bubble but ManagePasswordsUIController handles this.
+  delegate_->OnBubbleHidden();
 }
 
 void PasswordDialogControllerImpl::ResetDialog() {
diff --git a/chrome/browser/ui/passwords/password_dialog_controller_impl.h b/chrome/browser/ui/passwords/password_dialog_controller_impl.h
index bf36852..4ff7dcc 100644
--- a/chrome/browser/ui/passwords/password_dialog_controller_impl.h
+++ b/chrome/browser/ui/passwords/password_dialog_controller_impl.h
@@ -12,12 +12,14 @@
 #include "chrome/browser/ui/passwords/password_dialog_controller.h"
 
 class AccountChooserPrompt;
+class PasswordsModelDelegate;
 class Profile;
 
 // A UI controller responsible for the account chooser dialog.
 class PasswordDialogControllerImpl : public PasswordDialogController {
  public:
-  explicit PasswordDialogControllerImpl(Profile* profle);
+  PasswordDialogControllerImpl(Profile* profle,
+                               PasswordsModelDelegate* delegate);
   ~PasswordDialogControllerImpl() override;
 
   // Pop up the account chooser dialog.
@@ -32,12 +34,14 @@
   void OnChooseCredentials(
       const autofill::PasswordForm& password_form,
       password_manager::CredentialType credential_type) override;
+  void OnCloseAccountChooser() override;
 
  private:
   // Release |current_dialog_| and close the open dialog.
   void ResetDialog();
 
   Profile* const profile_;
+  PasswordsModelDelegate* const delegate_;
   AccountChooserPrompt* current_dialog_;
   std::vector<scoped_ptr<autofill::PasswordForm>> local_credentials_;
   std::vector<scoped_ptr<autofill::PasswordForm>> federated_credentials_;
diff --git a/chrome/browser/ui/passwords/password_dialog_controller_impl_unittest.cc b/chrome/browser/ui/passwords/password_dialog_controller_impl_unittest.cc
index 0e3e664..aed00f4 100644
--- a/chrome/browser/ui/passwords/password_dialog_controller_impl_unittest.cc
+++ b/chrome/browser/ui/passwords/password_dialog_controller_impl_unittest.cc
@@ -10,9 +10,11 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ui/passwords/account_chooser_prompt.h"
+#include "chrome/browser/ui/passwords/manage_passwords_ui_controller_mock.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/autofill/core/common/password_form.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/web_contents_tester.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -44,30 +46,67 @@
   return form;
 }
 
+class PasswordDialogControllerTest : public testing::Test {
+ public:
+  PasswordDialogControllerTest()
+      : test_web_contents_(content::WebContentsTester::CreateTestWebContents(
+            &profile_, nullptr)),
+        ui_controller_mock_(new StrictMock<ManagePasswordsUIControllerMock>(
+            test_web_contents_.get())),
+        controller_(&profile_, ui_controller_mock_) {
+  }
 
-TEST(PasswordDialogControllerTest, Show) {
-  content::TestBrowserThreadBundle thread_bundle;
-  TestingProfile profile;
-  PasswordDialogControllerImpl controller(&profile);
+  ManagePasswordsUIControllerMock& ui_controller_mock() {
+    return *ui_controller_mock_;
+  }
+
+  PasswordDialogControllerImpl& controller() { return controller_; }
+
+ private:
+  content::TestBrowserThreadBundle thread_bundle_;
+  TestingProfile profile_;
+  scoped_ptr<content::WebContents> test_web_contents_;
+  // Owned by |test_web_contents_|.
+  ManagePasswordsUIControllerMock* ui_controller_mock_;
+  PasswordDialogControllerImpl controller_;
+};
+
+TEST_F(PasswordDialogControllerTest, ShowAccountChooser) {
   StrictMock<MockAccountChooserPrompt> prompt;
   autofill::PasswordForm local_form = GetLocalForm();
   autofill::PasswordForm idp_form = GetFederationProviderForm();
   std::vector<scoped_ptr<autofill::PasswordForm>> locals;
   locals.push_back(make_scoped_ptr(new autofill::PasswordForm(local_form)));
+  autofill::PasswordForm* local_form_ptr = locals[0].get();
   std::vector<scoped_ptr<autofill::PasswordForm>> federations;
   federations.push_back(make_scoped_ptr(new autofill::PasswordForm(idp_form)));
 
   EXPECT_CALL(prompt, Show());
-  controller.ShowAccountChooser(&prompt,
-                                std::move(locals), std::move(federations));
-  EXPECT_THAT(controller.GetLocalForms(), ElementsAre(Pointee(local_form)));
-  EXPECT_THAT(controller.GetFederationsForms(), ElementsAre(Pointee(idp_form)));
+  controller().ShowAccountChooser(&prompt,
+                                  std::move(locals), std::move(federations));
+  EXPECT_THAT(controller().GetLocalForms(), ElementsAre(Pointee(local_form)));
+  EXPECT_THAT(controller().GetFederationsForms(),
+              ElementsAre(Pointee(idp_form)));
 
   // Close the dialog.
   EXPECT_CALL(prompt, ControllerGone());
-  controller.OnChooseCredentials(
-      autofill::PasswordForm(),
-      password_manager::CredentialType::CREDENTIAL_TYPE_EMPTY);
+  EXPECT_CALL(ui_controller_mock(), ChooseCredential(
+      local_form,
+      password_manager::CredentialType::CREDENTIAL_TYPE_PASSWORD));
+  controller().OnChooseCredentials(
+      *local_form_ptr,
+      password_manager::CredentialType::CREDENTIAL_TYPE_PASSWORD);
+}
+
+TEST_F(PasswordDialogControllerTest, AccountChooserClosed) {
+  StrictMock<MockAccountChooserPrompt> prompt;
+  EXPECT_CALL(prompt, Show());
+  controller().ShowAccountChooser(&prompt,
+                                  PasswordDialogController::FormsVector(),
+                                  PasswordDialogController::FormsVector());
+
+  EXPECT_CALL(ui_controller_mock(), OnBubbleHidden());
+  controller().OnCloseAccountChooser();
 }
 
 }  // namespace
diff --git a/chrome/browser/ui/views/passwords/account_chooser_dialog_view.cc b/chrome/browser/ui/views/passwords/account_chooser_dialog_view.cc
index 64054f7..56eca17 100644
--- a/chrome/browser/ui/views/passwords/account_chooser_dialog_view.cc
+++ b/chrome/browser/ui/views/passwords/account_chooser_dialog_view.cc
@@ -106,6 +106,11 @@
   return l10n_util::GetStringUTF16(IDS_APP_CANCEL);
 }
 
+void AccountChooserDialogView::OnClosed() {
+  if (controller_)
+    controller_->OnCloseAccountChooser();
+}
+
 gfx::Size AccountChooserDialogView::GetPreferredSize() const {
   return gfx::Size(kDesiredWidth, GetHeightForWidth(kDesiredWidth));
 }
@@ -168,3 +173,8 @@
   // the buttons.
   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
 }
+
+AccountChooserPrompt* CreateAccountChooserPromptView(
+    PasswordDialogController* controller, content::WebContents* web_contents) {
+  return new AccountChooserDialogView(controller, web_contents);
+}
diff --git a/chrome/browser/ui/views/passwords/account_chooser_dialog_view.h b/chrome/browser/ui/views/passwords/account_chooser_dialog_view.h
index 0d87d1f..283252b5 100644
--- a/chrome/browser/ui/views/passwords/account_chooser_dialog_view.h
+++ b/chrome/browser/ui/views/passwords/account_chooser_dialog_view.h
@@ -40,6 +40,7 @@
   // DialogDelegate:
   int GetDialogButtons() const override;
   base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
+  void OnClosed() override;
 
   // views::View
   gfx::Size GetPreferredSize() const override;
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view_browsertest.cc b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view_interactive_uitest.cc
similarity index 83%
rename from chrome/browser/ui/views/passwords/manage_passwords_bubble_view_browsertest.cc
rename to chrome/browser/ui/views/passwords/manage_passwords_bubble_view_interactive_uitest.cc
index 988cd5b..6ded4c3 100644
--- a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view_interactive_uitest.cc
@@ -291,60 +291,6 @@
   EXPECT_FALSE(IsBubbleShowing());
 }
 
-IN_PROC_BROWSER_TEST_F(ManagePasswordsBubbleViewTest, ChooseCredential) {
-  GURL origin("https://example.com");
-  ScopedVector<autofill::PasswordForm> local_credentials;
-  test_form()->origin = origin;
-  test_form()->display_name = base::ASCIIToUTF16("Peter");
-  test_form()->username_value = base::ASCIIToUTF16("pet12@gmail.com");
-  test_form()->icon_url = GURL("broken url");
-  local_credentials.push_back(new autofill::PasswordForm(*test_form()));
-  ScopedVector<autofill::PasswordForm> federated_credentials;
-  GURL icon_url("https://google.com/icon.png");
-  test_form()->icon_url = icon_url;
-  test_form()->display_name = base::ASCIIToUTF16("Peter Pen");
-  test_form()->federation_url = GURL("https://google.com/federation");
-  federated_credentials.push_back(new autofill::PasswordForm(*test_form()));
-
-  // Prepare to capture the network request.
-  TestURLFetcherCallback url_callback;
-  net::FakeURLFetcherFactory factory(
-      NULL,
-      base::Bind(&TestURLFetcherCallback::CreateURLFetcher,
-                 base::Unretained(&url_callback)));
-  factory.SetFakeResponse(icon_url, std::string(), net::HTTP_OK,
-                          net::URLRequestStatus::FAILED);
-  EXPECT_CALL(url_callback, OnRequestDone(icon_url));
-
-  SetupChooseCredentials(std::move(local_credentials),
-                         std::move(federated_credentials), origin);
-  EXPECT_TRUE(IsBubbleShowing());
-  EXPECT_CALL(*this, OnChooseCredential(
-      Field(&password_manager::CredentialInfo::type,
-            password_manager::CredentialType::CREDENTIAL_TYPE_EMPTY)));
-  ManagePasswordsBubbleView::CloseBubble();
-}
-
-IN_PROC_BROWSER_TEST_F(ManagePasswordsBubbleViewTest, ChooseCredentialNoFocus) {
-  GURL origin("https://example.com");
-  ScopedVector<autofill::PasswordForm> local_credentials;
-  test_form()->origin = origin;
-  test_form()->display_name = base::ASCIIToUTF16("Peter");
-  test_form()->username_value = base::ASCIIToUTF16("pet12@gmail.com");
-  local_credentials.push_back(new autofill::PasswordForm(*test_form()));
-  ScopedVector<autofill::PasswordForm> federated_credentials;
-
-  // Open another window with focus.
-  Browser* focused_window = CreateBrowser(browser()->profile());
-  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(focused_window));
-  content::RunAllPendingInMessageLoop();
-
-  EXPECT_FALSE(browser()->window()->IsActive());
-  SetupChooseCredentials(std::move(local_credentials),
-                         std::move(federated_credentials), origin);
-  EXPECT_TRUE(IsBubbleShowing());
-}
-
 IN_PROC_BROWSER_TEST_F(ManagePasswordsBubbleViewTest, AutoSignin) {
   // The switch enables the new UI.
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_icon_view_browsertest.cc b/chrome/browser/ui/views/passwords/manage_passwords_icon_view_interactive_uitest.cc
similarity index 100%
rename from chrome/browser/ui/views/passwords/manage_passwords_icon_view_browsertest.cc
rename to chrome/browser/ui/views/passwords/manage_passwords_icon_view_interactive_uitest.cc
diff --git a/chrome/browser/ui/views/passwords/password_dialog_view_browsertest.cc b/chrome/browser/ui/views/passwords/password_dialog_view_browsertest.cc
new file mode 100644
index 0000000..208fd20
--- /dev/null
+++ b/chrome/browser/ui/views/passwords/password_dialog_view_browsertest.cc
@@ -0,0 +1,163 @@
+// 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 "base/strings/utf_string_conversions.h"
+#include "chrome/browser/password_manager/chrome_password_manager_client.h"
+#include "chrome/browser/ui/autofill/chrome_autofill_client.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/views/passwords/account_chooser_dialog_view.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "net/url_request/test_url_fetcher_factory.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using ::testing::Field;
+
+namespace {
+
+// A helper class that will create FakeURLFetcher and record the requested URLs.
+class TestURLFetcherCallback {
+ public:
+  scoped_ptr<net::FakeURLFetcher> CreateURLFetcher(
+      const GURL& url,
+      net::URLFetcherDelegate* d,
+      const std::string& response_data,
+      net::HttpStatusCode response_code,
+      net::URLRequestStatus::Status status) {
+    OnRequestDone(url);
+    return scoped_ptr<net::FakeURLFetcher>(new net::FakeURLFetcher(
+        url, d, response_data, response_code, status));
+  }
+
+  MOCK_METHOD1(OnRequestDone, void(const GURL&));
+};
+
+// ManagePasswordsUIController subclass to capture the dialog instance
+class TestManagePasswordsUIController : public ManagePasswordsUIController {
+ public:
+  explicit TestManagePasswordsUIController(content::WebContents* web_contents);
+
+  AccountChooserPrompt* CreateAccountChooser(
+      PasswordDialogController* controller) override;
+
+  AccountChooserPrompt* current_dialog() const { return current_dialog_; }
+
+ private:
+  AccountChooserPrompt* current_dialog_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestManagePasswordsUIController);
+};
+
+TestManagePasswordsUIController::TestManagePasswordsUIController(
+    content::WebContents* web_contents)
+    : ManagePasswordsUIController(web_contents),
+      current_dialog_(nullptr) {
+  // Attach TestManagePasswordsUIController to |web_contents| so the default
+  // ManagePasswordsUIController isn't created.
+  // Do not silently replace an existing ManagePasswordsUIController because it
+  // unregisters itself in WebContentsDestroyed().
+  EXPECT_FALSE(web_contents->GetUserData(UserDataKey()));
+  web_contents->SetUserData(UserDataKey(), this);
+}
+
+AccountChooserPrompt* TestManagePasswordsUIController::CreateAccountChooser(
+    PasswordDialogController* controller) {
+  current_dialog_ =
+      ManagePasswordsUIController::CreateAccountChooser(controller);
+  return current_dialog_;
+}
+
+class PasswordDialogViewTest : public InProcessBrowserTest {
+ public:
+  // InProcessBrowserTest:
+  void SetUpOnMainThread() override;
+
+  void SetupChooseCredentials(
+      ScopedVector<autofill::PasswordForm> local_credentials,
+      ScopedVector<autofill::PasswordForm> federated_credentials,
+      const GURL& origin);
+
+  TestManagePasswordsUIController* controller() const { return controller_; }
+
+  MOCK_METHOD1(OnChooseCredential,
+               void(const password_manager::CredentialInfo&));
+
+ private:
+  TestManagePasswordsUIController* controller_;
+};
+
+void PasswordDialogViewTest::SetUpOnMainThread() {
+  // Open a new tab with modified ManagePasswordsUIController.
+  content::WebContents* tab =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  content::WebContents* new_tab = content::WebContents::Create(
+      content::WebContents::CreateParams(tab->GetBrowserContext()));
+  ASSERT_TRUE(new_tab);
+
+  // ManagePasswordsUIController needs ChromePasswordManagerClient for logging.
+  // ChromePasswordManagerClient needs ChromeAutofillClient on creation.
+  autofill::ChromeAutofillClient::CreateForWebContents(new_tab);
+  ChromePasswordManagerClient::CreateForWebContentsWithAutofillClient(
+      new_tab,
+      autofill::ChromeAutofillClient::FromWebContents(new_tab));
+  ASSERT_TRUE(ChromePasswordManagerClient::FromWebContents(new_tab));
+  controller_ = new TestManagePasswordsUIController(new_tab);
+  browser()->tab_strip_model()->AppendWebContents(new_tab, true);
+
+  // Navigate to a Web URL.
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browser(), GURL("http://www.google.com")));
+  ASSERT_EQ(controller_, ManagePasswordsUIController::FromWebContents(new_tab));
+}
+
+void PasswordDialogViewTest::SetupChooseCredentials(
+    ScopedVector<autofill::PasswordForm> local_credentials,
+    ScopedVector<autofill::PasswordForm> federated_credentials,
+    const GURL& origin) {
+  controller()->OnChooseCredentials(
+      std::move(local_credentials), std::move(federated_credentials), origin,
+      base::Bind(&PasswordDialogViewTest::OnChooseCredential, this));
+  EXPECT_EQ(password_manager::ui::CREDENTIAL_REQUEST_STATE,
+            controller()->GetState());
+}
+
+IN_PROC_BROWSER_TEST_F(PasswordDialogViewTest, PopupAccountChooser) {
+  GURL origin("https://example.com");
+  ScopedVector<autofill::PasswordForm> local_credentials;
+  autofill::PasswordForm form;
+  form.origin = origin;
+  form.display_name = base::ASCIIToUTF16("Peter");
+  form.username_value = base::ASCIIToUTF16("peter@pan.test");
+  form.icon_url = GURL("broken url");
+  local_credentials.push_back(new autofill::PasswordForm(form));
+  GURL icon_url("https://google.com/icon.png");
+  form.icon_url = icon_url;
+  form.display_name = base::ASCIIToUTF16("Peter Pen");
+  form.federation_url = GURL("https://google.com/federation");
+  local_credentials.push_back(new autofill::PasswordForm(form));
+
+  // Prepare to capture the network request.
+  TestURLFetcherCallback url_callback;
+  net::FakeURLFetcherFactory factory(
+      NULL,
+      base::Bind(&TestURLFetcherCallback::CreateURLFetcher,
+                 base::Unretained(&url_callback)));
+  factory.SetFakeResponse(icon_url, std::string(), net::HTTP_OK,
+                          net::URLRequestStatus::FAILED);
+  EXPECT_CALL(url_callback, OnRequestDone(icon_url));
+
+  SetupChooseCredentials(std::move(local_credentials),
+                         ScopedVector<autofill::PasswordForm>(), origin);
+  ASSERT_TRUE(controller()->current_dialog());
+  AccountChooserDialogView* dialog =
+      static_cast<AccountChooserDialogView*>(controller()->current_dialog());
+  EXPECT_CALL(*this, OnChooseCredential(
+      Field(&password_manager::CredentialInfo::type,
+            password_manager::CredentialType::CREDENTIAL_TYPE_EMPTY)));
+  EXPECT_TRUE(dialog->Close());
+}
+
+}  // namespace
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 19309d9..35df53ed 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -413,8 +413,8 @@
       'browser/ssl/cert_verifier_browser_test.h',
       'browser/ssl/certificate_reporting_test_utils.cc',
       'browser/ssl/certificate_reporting_test_utils.h',
-      'browser/ssl/chrome_ssl_host_state_delegate_test.cc',
       'browser/ssl/chrome_security_state_model_client_browser_tests.cc',
+      'browser/ssl/chrome_ssl_host_state_delegate_test.cc',
       'browser/ssl/ssl_browser_tests.cc',
       'browser/ssl/ssl_client_certificate_selector_test.cc',
       'browser/ssl/ssl_client_certificate_selector_test.h',
@@ -660,6 +660,7 @@
       'browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc',
       'browser/ui/views/media_router/media_router_ui_browsertest.cc',
       'browser/ui/views/new_task_manager_view_browsertest.cc',
+      'browser/ui/views/passwords/password_dialog_view_browsertest.cc',
       'browser/ui/views/toolbar/browser_actions_container_browsertest.cc',
       'browser/ui/views/toolbar/toolbar_view_browsertest.cc',
       'browser/ui/views/translate/translate_bubble_view_browsertest.cc',
@@ -855,10 +856,10 @@
       'browser/safe_browsing/safe_browsing_blocking_page_test.cc',
       'browser/safe_browsing/safe_browsing_service_browsertest.cc',
       'browser/safe_browsing/safe_browsing_test.cc',
-      'renderer/safe_browsing/threat_dom_details_browsertest.cc',
       'renderer/safe_browsing/phishing_classifier_browsertest.cc',
       'renderer/safe_browsing/phishing_classifier_delegate_browsertest.cc',
       'renderer/safe_browsing/phishing_dom_feature_extractor_browsertest.cc',
+      'renderer/safe_browsing/threat_dom_details_browsertest.cc',
     ],
     'chrome_browser_tests_remoting_sources': [
       'test/remoting/auth_browsertest.cc',
@@ -1151,8 +1152,8 @@
       'browser/ui/views/location_bar/page_action_image_view_interactive_uitest.cc',
       'browser/ui/views/location_bar/star_view_browsertest.cc',
       'browser/ui/views/omnibox/omnibox_view_views_browsertest.cc',
-      'browser/ui/views/passwords/manage_passwords_bubble_view_browsertest.cc',
-      'browser/ui/views/passwords/manage_passwords_icon_view_browsertest.cc',
+      'browser/ui/views/passwords/manage_passwords_bubble_view_interactive_uitest.cc',
+      'browser/ui/views/passwords/manage_passwords_icon_view_interactive_uitest.cc',
       'browser/ui/views/ssl_client_certificate_selector_browsertest.cc',
       'browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc',
       'browser/ui/views/tabs/tab_drag_controller_interactive_uitest.h',
diff --git a/chrome/common/extensions/manifest_handlers/automation.cc b/chrome/common/extensions/manifest_handlers/automation.cc
index dfdb72c..2e22cb3 100644
--- a/chrome/common/extensions/manifest_handlers/automation.cc
+++ b/chrome/common/extensions/manifest_handlers/automation.cc
@@ -91,12 +91,11 @@
         automation_info_->matches, &regular_hosts, &permissions);
     std::set<std::string> hosts =
         permission_message_util::GetDistinctHosts(regular_hosts, true, true);
-    if (!hosts.empty()) {
-      permission_message_util::AddHostPermissions(
-          &permissions, hosts, automation_info_->interact
-                                   ? permission_message_util::kReadWrite
-                                   : permission_message_util::kReadOnly);
-    }
+    APIPermission::ID permission_id = automation_info_->interact
+                                          ? APIPermission::kHostReadWrite
+                                          : APIPermission::kHostReadOnly;
+    for (const auto& host : hosts)
+      permissions.insert(permission_id, base::UTF8ToUTF16(host));
   }
   return permissions;
 }
diff --git a/chrome/common/extensions/permissions/chrome_permission_message_provider.cc b/chrome/common/extensions/permissions/chrome_permission_message_provider.cc
index 4561243..cc2aae7 100644
--- a/chrome/common/extensions/permissions/chrome_permission_message_provider.cc
+++ b/chrome/common/extensions/permissions/chrome_permission_message_provider.cc
@@ -10,6 +10,7 @@
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
 #include "chrome/common/extensions/permissions/chrome_permission_message_rules.h"
 #include "chrome/grit/generated_resources.h"
 #include "extensions/common/extensions_client.h"
@@ -167,9 +168,9 @@
 
     std::set<std::string> hosts =
         permission_message_util::GetDistinctHosts(regular_hosts, true, true);
-    if (!hosts.empty()) {
-      permission_message_util::AddHostPermissions(
-          permission_ids, hosts, permission_message_util::kReadWrite);
+    for (const auto& host : hosts) {
+      permission_ids->insert(APIPermission::kHostReadWrite,
+                             base::UTF8ToUTF16(host));
     }
   }
 }
diff --git a/chrome/common/extensions/permissions/chrome_permission_message_rules.cc b/chrome/common/extensions/permissions/chrome_permission_message_rules.cc
index b56691489..dffd650 100644
--- a/chrome/common/extensions/permissions/chrome_permission_message_rules.cc
+++ b/chrome/common/extensions/permissions/chrome_permission_message_rules.cc
@@ -9,7 +9,6 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/grit/generated_resources.h"
-#include "grit/extensions_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace extensions {
@@ -119,40 +118,34 @@
   DISALLOW_COPY_AND_ASSIGN(SpaceSeparatedListFormatter);
 };
 
-// Creates a comma-separated list of permissions with the given PermissionID.
-// The list is inserted into the messages with the given IDs: one for each case
-// of 1-3 permissions, and the other for the case where there are 4 or more
-// permissions. In the case of 4 or more permissions, rather than insert the
-// list into the message, the permissions are displayed as submessages in the
-// resultant PermissionMessage.
-class CommaSeparatedListFormatter : public ChromePermissionMessageFormatter {
+// Creates a list of host permissions. If there are 1-3 hosts, they are inserted
+// directly into a message with a given ID. If there are more than 3, they are
+// displayed as list of submessages instead.
+class HostListFormatter : public ChromePermissionMessageFormatter {
  public:
-  CommaSeparatedListFormatter(int message_id_for_one_host,
-                              int message_id_for_two_hosts,
-                              int message_id_for_three_hosts,
-                              int message_id_for_many_hosts)
+  HostListFormatter(int message_id_for_one_host,
+                    int message_id_for_two_hosts,
+                    int message_id_for_three_hosts,
+                    int message_id_for_many_hosts)
       : message_id_for_one_host_(message_id_for_one_host),
         message_id_for_two_hosts_(message_id_for_two_hosts),
         message_id_for_three_hosts_(message_id_for_three_hosts),
         message_id_for_many_hosts_(message_id_for_many_hosts) {}
-  ~CommaSeparatedListFormatter() override {}
+  ~HostListFormatter() override {}
 
   PermissionMessage GetPermissionMessage(
       const PermissionIDSet& permissions) const override {
-    DCHECK(permissions.size() > 0);
+    DCHECK(!permissions.empty());
     std::vector<base::string16> hostnames =
-        permissions.GetAllPermissionParameters();
-    PermissionMessages messages;
-    if (hostnames.size() <= 3) {
+        GetHostMessages(permissions.GetAllPermissionParameters());
+    int message_id = message_id_for_hosts(hostnames.size());
+    if (hostnames.size() <= kMaxHostsInMainMessage) {
       return PermissionMessage(
-          l10n_util::GetStringFUTF16(message_id_for_hosts(hostnames.size()),
-                                     hostnames, NULL),
+          l10n_util::GetStringFUTF16(message_id, hostnames, nullptr),
           permissions);
     }
-
-    return PermissionMessage(
-        l10n_util::GetStringUTF16(message_id_for_many_hosts_), permissions,
-        hostnames);
+    return PermissionMessage(l10n_util::GetStringUTF16(message_id), permissions,
+                             hostnames);
   }
 
  private:
@@ -169,12 +162,29 @@
     }
   }
 
+  std::vector<base::string16> GetHostMessages(
+      const std::vector<base::string16>& hosts) const {
+    int msg_id = hosts.size() <= kMaxHostsInMainMessage
+                     ? IDS_EXTENSION_PROMPT_WARNING_HOST_AND_SUBDOMAIN
+                     : IDS_EXTENSION_PROMPT_WARNING_HOST_AND_SUBDOMAIN_LIST;
+    std::vector<base::string16> messages;
+    for (const base::string16& host : hosts) {
+      messages.push_back(
+          host[0] == '*' && host[1] == '.'
+              ? l10n_util::GetStringFUTF16(msg_id, host.substr(2))
+              : host);
+    }
+    return messages;
+  }
+
+  static const int kMaxHostsInMainMessage = 3;
+
   int message_id_for_one_host_;
   int message_id_for_two_hosts_;
   int message_id_for_three_hosts_;
   int message_id_for_many_hosts_;
 
-  DISALLOW_COPY_AND_ASSIGN(CommaSeparatedListFormatter);
+  DISALLOW_COPY_AND_ASSIGN(HostListFormatter);
 };
 
 class USBDevicesFormatter : public ChromePermissionMessageFormatter {
@@ -372,17 +382,16 @@
         APIPermission::kProcesses, APIPermission::kTab,
         APIPermission::kTopSites, APIPermission::kWebNavigation}},
 
-      {new CommaSeparatedListFormatter(IDS_EXTENSION_PROMPT_WARNING_1_HOST,
-                                       IDS_EXTENSION_PROMPT_WARNING_2_HOSTS,
-                                       IDS_EXTENSION_PROMPT_WARNING_3_HOSTS,
-                                       IDS_EXTENSION_PROMPT_WARNING_HOSTS_LIST),
+      {new HostListFormatter(IDS_EXTENSION_PROMPT_WARNING_1_HOST,
+                             IDS_EXTENSION_PROMPT_WARNING_2_HOSTS,
+                             IDS_EXTENSION_PROMPT_WARNING_3_HOSTS,
+                             IDS_EXTENSION_PROMPT_WARNING_HOSTS_LIST),
        {APIPermission::kHostReadWrite},
        {}},
-      {new CommaSeparatedListFormatter(
-           IDS_EXTENSION_PROMPT_WARNING_1_HOST_READ_ONLY,
-           IDS_EXTENSION_PROMPT_WARNING_2_HOSTS_READ_ONLY,
-           IDS_EXTENSION_PROMPT_WARNING_3_HOSTS_READ_ONLY,
-           IDS_EXTENSION_PROMPT_WARNING_HOSTS_LIST_READ_ONLY),
+      {new HostListFormatter(IDS_EXTENSION_PROMPT_WARNING_1_HOST_READ_ONLY,
+                             IDS_EXTENSION_PROMPT_WARNING_2_HOSTS_READ_ONLY,
+                             IDS_EXTENSION_PROMPT_WARNING_3_HOSTS_READ_ONLY,
+                             IDS_EXTENSION_PROMPT_WARNING_HOSTS_LIST_READ_ONLY),
        {APIPermission::kHostReadOnly},
        {}},
 
diff --git a/chrome/renderer/external_extension.cc b/chrome/renderer/external_extension.cc
index 99b03a8..f3a60cf 100644
--- a/chrome/renderer/external_extension.cc
+++ b/chrome/renderer/external_extension.cc
@@ -118,7 +118,7 @@
     return;
 
   GURL osdd_url = GURL(webframe->document().url()).Resolve(osdd_string);
-  if (!osdd_url.is_empty() && osdd_url.is_valid()) {
+  if (osdd_url.is_valid()) {
     webframe->didCallAddSearchProvider();
     render_view->Send(new ChromeViewHostMsg_PageHasOSDD(
         render_view->GetRoutingID(), webframe->document().url(), osdd_url,
diff --git a/components/scheduler/renderer/renderer_scheduler_impl.cc b/components/scheduler/renderer/renderer_scheduler_impl.cc
index 5402dbee..d739302 100644
--- a/components/scheduler/renderer/renderer_scheduler_impl.cc
+++ b/components/scheduler/renderer/renderer_scheduler_impl.cc
@@ -618,10 +618,10 @@
   }
   MainThreadOnly().touchstart_expected_soon = touchstart_expected_soon;
 
-  base::TimeDelta expected_idle_duration =
-      MainThreadOnly().idle_time_estimator.GetExpectedIdleDuration(
-          MainThreadOnly().compositor_frame_interval);
-  MainThreadOnly().expected_idle_duration = expected_idle_duration;
+  base::TimeDelta longest_jank_free_task_duration =
+      EstimateLongestJankFreeTaskDuration();
+  MainThreadOnly().longest_jank_free_task_duration =
+      longest_jank_free_task_duration;
 
   bool loading_tasks_seem_expensive = false;
   bool timer_tasks_seem_expensive = false;
@@ -630,10 +630,10 @@
   if (!MainThreadOnly().begin_frame_not_expected_soon) {
     loading_tasks_seem_expensive =
         MainThreadOnly().loading_task_cost_estimator.expected_task_duration() >
-        expected_idle_duration;
+        longest_jank_free_task_duration;
     timer_tasks_seem_expensive =
         MainThreadOnly().timer_task_cost_estimator.expected_task_duration() >
-        expected_idle_duration;
+        longest_jank_free_task_duration;
   }
   MainThreadOnly().timer_tasks_seem_expensive = timer_tasks_seem_expensive;
   MainThreadOnly().loading_tasks_seem_expensive = loading_tasks_seem_expensive;
@@ -856,6 +856,26 @@
   return UseCase::NONE;
 }
 
+base::TimeDelta RendererSchedulerImpl::EstimateLongestJankFreeTaskDuration()
+    const {
+  switch (MainThreadOnly().current_use_case) {
+    case UseCase::TOUCHSTART:
+    case UseCase::COMPOSITOR_GESTURE:
+    case UseCase::LOADING:
+    case UseCase::NONE:
+      return base::TimeDelta::FromMilliseconds(kRailsResponseTimeMillis);
+
+    case UseCase::MAIN_THREAD_GESTURE:
+    case UseCase::SYNCHRONIZED_GESTURE:
+      return MainThreadOnly().idle_time_estimator.GetExpectedIdleDuration(
+          MainThreadOnly().compositor_frame_interval);
+
+    default:
+      NOTREACHED();
+      return base::TimeDelta::FromMilliseconds(kRailsResponseTimeMillis);
+  }
+}
+
 bool RendererSchedulerImpl::CanEnterLongIdlePeriod(
     base::TimeTicks now,
     base::TimeDelta* next_long_idle_period_delay_out) {
@@ -983,8 +1003,9 @@
                        .timer_task_cost_estimator.expected_task_duration()
                        .InMillisecondsF());
   // TODO(skyostil): Can we somehow trace how accurate these estimates were?
-  state->SetDouble("expected_idle_duration",
-                   MainThreadOnly().expected_idle_duration.InMillisecondsF());
+  state->SetDouble(
+      "longest_jank_free_task_duration",
+      MainThreadOnly().longest_jank_free_task_duration.InMillisecondsF());
   state->SetDouble(
       "compositor_frame_interval",
       MainThreadOnly().compositor_frame_interval.InMillisecondsF());
diff --git a/components/scheduler/renderer/renderer_scheduler_impl.h b/components/scheduler/renderer/renderer_scheduler_impl.h
index 0dd4da3..52868c9 100644
--- a/components/scheduler/renderer/renderer_scheduler_impl.h
+++ b/components/scheduler/renderer/renderer_scheduler_impl.h
@@ -250,6 +250,10 @@
   // nagigation. This function does that. Must be called from the main thread.
   void ResetForNavigationLocked();
 
+  // Estimates the maximum task length that won't cause a jank based on the
+  // current system state. Must be called from the main thread.
+  base::TimeDelta EstimateLongestJankFreeTaskDuration() const;
+
   SchedulerHelper helper_;
   IdleHelper idle_helper_;
   ThrottlingHelper throttling_helper_;
@@ -283,7 +287,7 @@
     base::TimeTicks current_policy_expiration_time;
     base::TimeTicks estimated_next_frame_begin;
     base::TimeDelta compositor_frame_interval;
-    base::TimeDelta expected_idle_duration;
+    base::TimeDelta longest_jank_free_task_duration;
     int timer_queue_suspend_count;  // TIMER_TASK_QUEUE suspended if non-zero.
     int navigation_task_expected_count;
     bool renderer_hidden;
diff --git a/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc b/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc
index 31b24a8..87d5cc3 100644
--- a/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc
+++ b/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc
@@ -179,6 +179,7 @@
  public:
   using RendererSchedulerImpl::OnIdlePeriodEnded;
   using RendererSchedulerImpl::OnIdlePeriodStarted;
+  using RendererSchedulerImpl::EstimateLongestJankFreeTaskDuration;
 
   RendererSchedulerImplForTest(
       scoped_refptr<SchedulerTqmDelegate> main_task_runner)
@@ -428,6 +429,12 @@
     scheduler_->DidCommitFrameToCompositor();
   }
 
+  void SimulateMainThreadCompositorTask(
+      base::TimeDelta begin_main_frame_duration) {
+    clock_->Advance(begin_main_frame_duration);
+    scheduler_->DidCommitFrameToCompositor();
+  }
+
   void SimulateTimerTask(base::TimeDelta duration) {
     clock_->Advance(duration);
     simulate_timer_task_ran_ = true;
@@ -537,6 +544,11 @@
         RendererSchedulerImpl::kSuspendTimersWhenBackgroundedDelayMillis);
   }
 
+  static base::TimeDelta rails_response_time() {
+    return base::TimeDelta::FromMilliseconds(
+        RendererSchedulerImpl::kRailsResponseTimeMillis);
+  }
+
   template <typename E>
   static void CallForEachEnumValue(E first,
                                    E last,
@@ -2465,6 +2477,45 @@
   }
 }
 
+TEST_F(RendererSchedulerImplTest,
+       FourtyMsTimer_NotBlocked_CompositorScrolling) {
+  EnableTaskBlocking();
+  scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
+  RunUntilIdle();
+  for (int i = 0; i < 20; i++) {
+    simulate_timer_task_ran_ = false;
+
+    cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create(
+        BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
+        base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL);
+    begin_frame_args.on_critical_path = false;
+    scheduler_->WillBeginFrame(begin_frame_args);
+    scheduler_->DidAnimateForInputOnCompositorThread();
+
+    compositor_task_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
+                   base::Unretained(this),
+                   base::TimeDelta::FromMilliseconds(8)));
+    timer_task_runner_->PostTask(
+        FROM_HERE, base::Bind(&RendererSchedulerImplTest::SimulateTimerTask,
+                              base::Unretained(this),
+                              base::TimeDelta::FromMilliseconds(40)));
+
+    RunUntilIdle();
+    EXPECT_TRUE(simulate_timer_task_ran_) << " i = " << i;
+    EXPECT_EQ(RendererScheduler::UseCase::COMPOSITOR_GESTURE, CurrentUseCase())
+        << " i = " << i;
+    EXPECT_FALSE(LoadingTasksSeemExpensive()) << " i = " << i;
+    EXPECT_FALSE(TimerTasksSeemExpensive()) << " i = " << i;
+
+    base::TimeDelta time_till_next_frame =
+        EstimatedNextFrameBegin() - clock_->NowTicks();
+    if (time_till_next_frame > base::TimeDelta())
+      clock_->Advance(time_till_next_frame);
+  }
+}
+
 TEST_F(RendererSchedulerImplTest, ExpensiveTimer_Blocked) {
   EnableTaskBlocking();
   scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
@@ -2509,4 +2560,74 @@
   }
 }
 
+TEST_F(RendererSchedulerImplTest,
+       EstimateLongestJankFreeTaskDuration_UseCase_NONE) {
+  EXPECT_EQ(UseCase::NONE, CurrentUseCase());
+  EXPECT_EQ(rails_response_time(),
+            scheduler_->EstimateLongestJankFreeTaskDuration());
+}
+
+TEST_F(RendererSchedulerImplTest,
+       EstimateLongestJankFreeTaskDuration_UseCase_COMPOSITOR_GESTURE) {
+  SimulateCompositorGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START);
+  EXPECT_EQ(UseCase::COMPOSITOR_GESTURE,
+            ForceUpdatePolicyAndGetCurrentUseCase());
+  EXPECT_EQ(rails_response_time(),
+            scheduler_->EstimateLongestJankFreeTaskDuration());
+}
+
+// TODO(alexclarke): Reenable once we've reinstaed the Loading UseCase.
+TEST_F(RendererSchedulerImplTest,
+       DISABLED_EstimateLongestJankFreeTaskDuration_UseCase_) {
+  scheduler_->OnNavigationStarted();
+  EXPECT_EQ(UseCase::LOADING, ForceUpdatePolicyAndGetCurrentUseCase());
+  EXPECT_EQ(rails_response_time(),
+            scheduler_->EstimateLongestJankFreeTaskDuration());
+}
+
+TEST_F(RendererSchedulerImplTest,
+       EstimateLongestJankFreeTaskDuration_UseCase_MAIN_THREAD_GESTURE) {
+  cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create(
+      BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
+      base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL);
+  begin_frame_args.on_critical_path = false;
+  scheduler_->WillBeginFrame(begin_frame_args);
+
+  compositor_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(
+          &RendererSchedulerImplTest::SimulateMainThreadGestureCompositorTask,
+          base::Unretained(this), base::TimeDelta::FromMilliseconds(5)));
+
+  RunUntilIdle();
+  EXPECT_EQ(UseCase::MAIN_THREAD_GESTURE, CurrentUseCase());
+
+  // 16ms frame - 5ms compositor work = 11ms for other stuff.
+  EXPECT_EQ(base::TimeDelta::FromMilliseconds(11),
+            scheduler_->EstimateLongestJankFreeTaskDuration());
+}
+
+TEST_F(RendererSchedulerImplTest,
+       EstimateLongestJankFreeTaskDuration_UseCase_SYNCHRONIZED_GESTURE) {
+  SimulateCompositorGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START);
+
+  cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create(
+      BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
+      base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL);
+  begin_frame_args.on_critical_path = true;
+  scheduler_->WillBeginFrame(begin_frame_args);
+
+  compositor_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
+                 base::Unretained(this), base::TimeDelta::FromMilliseconds(5)));
+
+  RunUntilIdle();
+  EXPECT_EQ(UseCase::SYNCHRONIZED_GESTURE, CurrentUseCase());
+
+  // 16ms frame - 5ms compositor work = 11ms for other stuff.
+  EXPECT_EQ(base::TimeDelta::FromMilliseconds(11),
+            scheduler_->EstimateLongestJankFreeTaskDuration());
+}
+
 }  // namespace scheduler
diff --git a/content/browser/screen_orientation/screen_orientation_browsertest.cc b/content/browser/screen_orientation/screen_orientation_browsertest.cc
index 77675b99..ca895018 100644
--- a/content/browser/screen_orientation/screen_orientation_browsertest.cc
+++ b/content/browser/screen_orientation/screen_orientation_browsertest.cc
@@ -227,18 +227,22 @@
 
 // Check that when --disable-screen-orientation-lock is passed to the command
 // line, screen.orientation.lock() correctly reports to not be supported.
-// Flaky: https://crbug.com/498236
-IN_PROC_BROWSER_TEST_F(ScreenOrientationLockDisabledBrowserTest,
-                       DISABLED_NotSupported) {
+IN_PROC_BROWSER_TEST_F(ScreenOrientationLockDisabledBrowserTest, NotSupported) {
   GURL test_url = GetTestUrl("screen_orientation",
                              "screen_orientation_lock_disabled.html");
 
-  TestNavigationObserver navigation_observer(shell()->web_contents(), 2);
+  TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
   shell()->LoadURL(test_url);
   navigation_observer.Wait();
 
-  EXPECT_EQ("NotSupportedError",
-            shell()->web_contents()->GetLastCommittedURL().ref());
+  {
+    ASSERT_TRUE(ExecuteScript(shell()->web_contents(), "run();"));
+
+    TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+    navigation_observer.Wait();
+    EXPECT_EQ("NotSupportedError",
+              shell()->web_contents()->GetLastCommittedURL().ref());
+  }
 }
 #endif // defined(OS_ANDROID)
 
diff --git a/content/test/data/screen_orientation/screen_orientation_lock_disabled.html b/content/test/data/screen_orientation/screen_orientation_lock_disabled.html
index e7faecf..26aae23 100644
--- a/content/test/data/screen_orientation/screen_orientation_lock_disabled.html
+++ b/content/test/data/screen_orientation/screen_orientation_lock_disabled.html
@@ -3,11 +3,13 @@
 <head>
 </head>
 <script>
+function run() {
   screen.orientation.lock('portrait-secondary').then(function() {
     document.location.hash = '#success';
   }, function(e) {
     document.location.hash = '#' + e.name;
   });
+}
 </script>
 <body>
   <div>Starting...</div>
diff --git a/extensions/common/permissions/permission_message_util.cc b/extensions/common/permissions/permission_message_util.cc
index b69e65b..0ee3abf 100644
--- a/extensions/common/permissions/permission_message_util.cc
+++ b/extensions/common/permissions/permission_message_util.cc
@@ -7,14 +7,9 @@
 #include <stddef.h>
 #include <vector>
 
-#include "base/strings/string16.h"
 #include "base/strings/string_split.h"
-#include "base/strings/utf_string_conversions.h"
-#include "extensions/common/permissions/api_permission_set.h"
 #include "extensions/common/url_pattern_set.h"
-#include "grit/extensions_strings.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
-#include "ui/base/l10n/l10n_util.h"
 #include "url/url_constants.h"
 
 using extensions::URLPatternSet;
@@ -38,46 +33,6 @@
 
 namespace permission_message_util {
 
-// The number of host messages supported. The first N - 1 of these messages are
-// specific for the number of hosts; the last one is a catch-all for N or more
-// hosts.
-static const int kNumMessages = 4;
-
-// Gets a list of hosts to display in a permission message from the given list
-// of hosts from the manifest.
-std::vector<base::string16> GetHostListFromHosts(
-    const std::set<std::string>& hosts) {
-  int host_msg_id = hosts.size() < kNumMessages
-                        ? IDS_EXTENSION_PROMPT_WARNING_HOST_AND_SUBDOMAIN
-                        : IDS_EXTENSION_PROMPT_WARNING_HOST_AND_SUBDOMAIN_LIST;
-  std::vector<base::string16> host_list;
-  for (const std::string& host : hosts) {
-    host_list.push_back(
-        host[0] == '*' && host[1] == '.'
-            ? l10n_util::GetStringFUTF16(host_msg_id,
-                                         base::UTF8ToUTF16(host.substr(2)))
-            : base::UTF8ToUTF16(host));
-  }
-  DCHECK(host_list.size());
-  return host_list;
-}
-
-void AddHostPermissions(extensions::PermissionIDSet* permissions,
-                        const std::set<std::string>& hosts,
-                        PermissionMessageProperties properties) {
-  std::vector<base::string16> host_list = GetHostListFromHosts(hosts);
-
-  // Create a separate permission for each host, and add it to the permissions
-  // list.
-  // TODO(sashab): Add coalescing rules for kHostReadOnly and kHostReadWrite
-  // to mimic the current behavior of GetHostListFromHosts() above.
-  extensions::APIPermission::ID permission_id =
-      properties == kReadOnly ? extensions::APIPermission::kHostReadOnly
-                              : extensions::APIPermission::kHostReadWrite;
-  for (const auto& host : host_list)
-    permissions->insert(permission_id, host);
-}
-
 std::set<std::string> GetDistinctHosts(const URLPatternSet& host_patterns,
                                        bool include_rcd,
                                        bool exclude_file_scheme) {
diff --git a/extensions/common/permissions/permission_message_util.h b/extensions/common/permissions/permission_message_util.h
index 5e33c07..66dd01d 100644
--- a/extensions/common/permissions/permission_message_util.h
+++ b/extensions/common/permissions/permission_message_util.h
@@ -9,19 +9,11 @@
 #include <string>
 
 namespace extensions {
-class PermissionIDSet;
 class URLPatternSet;
 }
 
 namespace permission_message_util {
 
-enum PermissionMessageProperties { kReadOnly, kReadWrite };
-
-// Adds the appropriate permissions from the given |hosts| to |permissions|.
-void AddHostPermissions(extensions::PermissionIDSet* permissions,
-                        const std::set<std::string>& hosts,
-                        PermissionMessageProperties properties);
-
 std::set<std::string> GetDistinctHosts(
     const extensions::URLPatternSet& host_patterns,
     bool include_rcd,
diff --git a/extensions/extensions_strings.grd b/extensions/extensions_strings.grd
index 0ccbcbdd..ecdc0fa 100644
--- a/extensions/extensions_strings.grd
+++ b/extensions/extensions_strings.grd
@@ -189,14 +189,6 @@
         extension <ph name="EXTENSION_NAME">$1<ex>Adblock</ex></ph>
       </message>
 
-      <!-- Host access permissions. Please keep alphabetized. -->
-      <message name="IDS_EXTENSION_PROMPT_WARNING_HOST_AND_SUBDOMAIN" desc="Permission string requesting access to data on a website and its sub-domains.">
-        all <ph name="WEBSITE_1">$1<ex>google.com</ex></ph> sites
-      </message>
-      <message name="IDS_EXTENSION_PROMPT_WARNING_HOST_AND_SUBDOMAIN_LIST" desc="Single entry permission string requesting access to data on a website and its sub-domains.">
-        All <ph name="WEBSITE_1">$1<ex>google.com</ex></ph> sites
-      </message>
-
       <!-- Policy strings. Please keep alphabetized. -->
       <message name="IDS_EXTENSION_CANT_INSTALL_POLICY_BLOCKED" desc="Error message when a user tries to install an extension that is blocked by administrator policy.">
         <ph name="EXTENSION_NAME">$1<ex>Google Talk</ex></ph> (extension ID "<ph name="EXTENSION_ID">$2<ex>nckgahadagoaajjgafhacjanaoiihapd</ex></ph>") is blocked by the administrator.
diff --git a/third_party/WebKit/LayoutTests/http/tests/notifications/resources/serviceworker-notification-event.js b/third_party/WebKit/LayoutTests/http/tests/notifications/resources/serviceworker-notification-event.js
index a46d320e..91ca1368 100644
--- a/third_party/WebKit/LayoutTests/http/tests/notifications/resources/serviceworker-notification-event.js
+++ b/third_party/WebKit/LayoutTests/http/tests/notifications/resources/serviceworker-notification-event.js
@@ -1,30 +1,41 @@
 importScripts('../../serviceworker/resources/worker-testharness.js');
-importScripts('/resources/testharness-helpers.js');
 
-test(function() {
+let messagePort = null;
+addEventListener('message', workerEvent => {
+    messagePort = workerEvent.data;
+    messagePort.postMessage('ready');
+});
+
+addEventListener('notificationclick', e => runTest(e.notification));
+
+// Test body for the serviceworker-notification-event.html layout test.
+function runTest(notification) {
     assert_true('NotificationEvent' in self);
 
-    var event = new NotificationEvent('NotificationEvent');
+    assert_throws(null, () => new NotificationEvent('NotificationEvent'));
+    assert_throws(null, () => new NotificationEvent('NotificationEvent', {}));
+
+    const event = new NotificationEvent('NotificationEvent', { notification });
+
     assert_equals(event.type, 'NotificationEvent');
-    assert_will_be_idl_attribute(event, 'notification');
-    assert_will_be_idl_attribute(event, 'action');
+    assert_idl_attribute(event, 'notification');
+    assert_idl_attribute(event, 'action');
     assert_equals(event.cancelable, false);
     assert_equals(event.bubbles, false);
-    assert_equals(event.notification, null);
-    assert_equals(event.action, "");
+    assert_equals(event.notification, notification);
+    assert_equals(event.action, '');
     assert_inherits(event, 'waitUntil');
 
-    var eventWithInit = new NotificationEvent('NotificationEvent',
-                                              { cancelable: true,
-                                                bubbles: true
-                                              });
-    assert_equals(eventWithInit.cancelable, true);
-    assert_equals(eventWithInit.bubbles, true);
+    const customEvent = new NotificationEvent('NotificationEvent', {
+                            notification: notification,
+                            bubbles: true,
+                            cancelable: true });
 
-}, 'NotificationEvent is exposed, and has the expected interface.');
+    assert_equals(customEvent.type, 'NotificationEvent');
+    assert_equals(customEvent.cancelable, true);
+    assert_equals(customEvent.bubbles, true);
+    assert_equals(customEvent.notification, notification);
 
-test(function() {
-    assert_will_be_idl_attribute(self, 'onnotificationclick',
-                                 'The notificationclick event exists.');
-
-}, 'The notificationclick event exists on the global scope.');
+    // Signal to the document that the test has finished running.
+    messagePort.postMessage(true /* success */);
+}
diff --git a/third_party/WebKit/LayoutTests/http/tests/notifications/serviceworker-notification-event.html b/third_party/WebKit/LayoutTests/http/tests/notifications/serviceworker-notification-event.html
index d91d6508..51ed274 100644
--- a/third_party/WebKit/LayoutTests/http/tests/notifications/serviceworker-notification-event.html
+++ b/third_party/WebKit/LayoutTests/http/tests/notifications/serviceworker-notification-event.html
@@ -5,15 +5,50 @@
     <script src="../resources/testharness.js"></script>
     <script src="../resources/testharnessreport.js"></script>
     <script src="../serviceworker/resources/test-helpers.js"></script>
+    <script src="resources/test-helpers.js"></script>
   </head>
   <body>
     <script>
       // Tests that the NotificationEvent object is exposed in a ServiceWorker
-      // and exposes the "notification" and "waitUntil" members, as well as the
-      // "notificationclick" and "notificationerror" events.
-      service_worker_test(
-          'resources/serviceworker-notification-event.js',
-          'Exposure of the NotificationEvent object in a ServiceWorker.');
+      // and exposes the "notification", "action" and "waitUntil" members.
+      //
+      // Because the NotificationEvent must be created with a notification, a
+      // notification is shown and clicked on prior to running the actual test
+      // in the Service Worker (serviceworker-notification-event.js).
+      async_test(function(test) {
+          var scope = 'resources/scope/' + location.pathname,
+              script = 'resources/serviceworker-notification-event.js';
+
+          testRunner.setPermission('notifications', 'granted', location.origin, location.origin);
+
+          var workerInfo = null;
+          getActiveServiceWorkerWithMessagePort(test, script, scope).then(function(info) {
+              workerInfo = info;
+
+              // (1) Display a Web Notification from the document.
+              assert_inherits(workerInfo.registration, 'showNotification', 'showNotification() must be exposed.');
+              return workerInfo.registration.showNotification(scope, {
+                  body: 'Hello, world!',
+                  icon: '/icon.png'
+              });
+          }).then(function() {
+              // (2) Simulate a click on the notification that has been displayed.
+              testRunner.simulateWebNotificationClick(scope);
+
+              workerInfo.port.addEventListener('message', function(event) {
+                  if (typeof event.data != 'boolean') {
+                      assert_unreached('Received an invalid message from the Service Worker.');
+                      return;
+                  }
+
+                  // (3) Verify that the tests were successful in the Service Worker.
+                  assert_true(event.data);
+
+                  test.done();
+              });
+          }).catch(unreached_rejection(test));
+
+      }, 'The NotificationEvent exposes the expected semantics in a Service Worker.');
     </script>
   </body>
-</html>
+</html>
\ No newline at end of file
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
index 203b3d8..506828c 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -295,6 +295,13 @@
     return cssValuePool().createIdentifierValue(range.consumeIncludingWhitespace().id());
 }
 
+static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumeIdentRange(CSSParserTokenRange& range, CSSValueID lower, CSSValueID upper)
+{
+    if (range.peek().id() < lower || range.peek().id() > upper)
+        return nullptr;
+    return consumeIdent(range);
+}
+
 static PassRefPtrWillBeRawPtr<CSSCustomIdentValue> consumeCustomIdent(CSSParserTokenRange& range)
 {
     if (range.peek().type() != IdentToken)
@@ -1107,7 +1114,7 @@
 
 static PassRefPtrWillBeRawPtr<CSSValue> consumeGenericFamily(CSSParserTokenRange& range)
 {
-    return consumeIdent<CSSValueSerif, CSSValueSansSerif, CSSValueCursive, CSSValueFantasy, CSSValueMonospace, CSSValueWebkitBody>(range);
+    return consumeIdentRange(range, CSSValueSerif, CSSValueWebkitBody);
 }
 
 static PassRefPtrWillBeRawPtr<CSSValueList> consumeFontFamily(CSSParserTokenRange& range)
@@ -2191,7 +2198,7 @@
         range.consumeIncludingWhitespace();
         return cssValuePool().createValue(percent, CSSPrimitiveValue::UnitType::Percentage);
     }
-    return consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Forbid);
+    return consumeLengthOrPercent(range, cssParserMode, ValueRangeAll);
 }
 
 static PassRefPtrWillBeRawPtr<CSSValue> consumePositionX(CSSParserTokenRange& range, CSSParserMode cssParserMode)
@@ -2316,7 +2323,7 @@
     CSSValueID id = range.peek().id();
     if (id == CSSValueBaseline || id == CSSValueSub || id == CSSValueSuper)
         return consumeIdent(range);
-    return consumeLengthOrPercent(range, SVGAttributeMode, ValueRangeAll, UnitlessQuirk::Forbid);
+    return consumeLengthOrPercent(range, SVGAttributeMode, ValueRangeAll);
 }
 
 static PassRefPtrWillBeRawPtr<CSSValue> consumeImageSet(CSSParserTokenRange& range, const CSSParserContext& context)
@@ -2934,6 +2941,14 @@
     return CSSValuePair::create(parsedValue1.release(), parsedValue2.release(), CSSValuePair::DropIdenticalValues);
 }
 
+static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumeVerticalAlign(CSSParserTokenRange& range, CSSParserMode cssParserMode)
+{
+    RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue = consumeIdentRange(range, CSSValueBaseline, CSSValueWebkitBaselineMiddle);
+    if (!parsedValue)
+        parsedValue = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Allow);
+    return parsedValue.release();
+}
+
 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSingleValue(CSSPropertyID unresolvedProperty)
 {
     CSSPropertyID property = resolveCSSPropertyID(unresolvedProperty);
@@ -3154,6 +3169,8 @@
     case CSSPropertyFillOpacity:
     case CSSPropertyStopOpacity:
     case CSSPropertyFloodOpacity:
+    case CSSPropertyOpacity:
+    case CSSPropertyWebkitBoxFlex:
         return consumeNumber(m_range, ValueRangeAll);
     case CSSPropertyBaselineShift:
         return consumeBaselineShift(m_range);
@@ -3191,6 +3208,16 @@
     case CSSPropertyBorderBottomLeftRadius:
     case CSSPropertyBorderBottomRightRadius:
         return consumeBorderRadiusCorner(m_range, m_context.mode());
+    case CSSPropertyWebkitBoxFlexGroup:
+        return consumeInteger(m_range, 0);
+    case CSSPropertyOrder:
+        return consumeInteger(m_range);
+    case CSSPropertyTextUnderlinePosition:
+        // auto | [ under || [ left | right ] ], but we only support auto | under for now
+        ASSERT(RuntimeEnabledFeatures::css3TextDecorationsEnabled());
+        return consumeIdent<CSSValueAuto, CSSValueUnder>(m_range);
+    case CSSPropertyVerticalAlign:
+        return consumeVerticalAlign(m_range, m_context.mode());
     default:
         return nullptr;
     }
diff --git a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
index 761c7c3..4287922 100644
--- a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
@@ -403,16 +403,6 @@
             validPrimitive = validUnit(value, FLength | FNonNeg | unitless);
         break;
 
-    case CSSPropertyVerticalAlign:
-        // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
-        // <percentage> | <length> | inherit
-
-        if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle)
-            validPrimitive = true;
-        else
-            validPrimitive = validUnit(value, FLength | FPercent | FUnitlessQuirk);
-        break;
-
     case CSSPropertyBottom:               // <length> | <percentage> | auto | inherit
     case CSSPropertyLeft:                 // <length> | <percentage> | auto | inherit
     case CSSPropertyRight:                // <length> | <percentage> | auto | inherit
@@ -423,12 +413,6 @@
             validPrimitive = validUnit(value, FLength | FPercent | FUnitlessQuirk);
         break;
 
-    case CSSPropertyTextUnderlinePosition:
-        // auto | [ under || [ left | right ] ], but we only support auto | under for now
-        ASSERT(RuntimeEnabledFeatures::css3TextDecorationsEnabled());
-        validPrimitive = (id == CSSValueAuto || id == CSSValueUnder);
-        break;
-
     case CSSPropertySrc:
     case CSSPropertyUnicodeRange:
         /* @font-face only descriptors */
@@ -493,17 +477,6 @@
         ASSERT(RuntimeEnabledFeatures::cssFontSizeAdjustEnabled());
         validPrimitive = (id == CSSValueNone) ? true : validUnit(value, FNumber | FNonNeg);
         break;
-    case CSSPropertyOpacity:
-    case CSSPropertyWebkitBoxFlex:
-        validPrimitive = validUnit(value, FNumber);
-        break;
-    case CSSPropertyWebkitBoxFlexGroup:
-        validPrimitive = validUnit(value, FInteger | FNonNeg);
-        break;
-    case CSSPropertyOrder:
-        validPrimitive = validUnit(value, FInteger);
-        break;
-
     case CSSPropertyJustifyContent:
         ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
         parsedValue = parseContentDistributionOverflowPosition();
@@ -821,6 +794,8 @@
     case CSSPropertyFillOpacity:
     case CSSPropertyStopOpacity:
     case CSSPropertyFloodOpacity:
+    case CSSPropertyOpacity:
+    case CSSPropertyWebkitBoxFlex:
     case CSSPropertyBaselineShift:
     case CSSPropertyStrokeMiterlimit:
     case CSSPropertyStrokeWidth:
@@ -849,6 +824,10 @@
     case CSSPropertyBorderBottomRightRadius:
     case CSSPropertyBorderRadius:
     case CSSPropertyAliasWebkitBorderRadius:
+    case CSSPropertyWebkitBoxFlexGroup:
+    case CSSPropertyOrder:
+    case CSSPropertyTextUnderlinePosition:
+    case CSSPropertyVerticalAlign:
         validPrimitive = false;
         break;
 
diff --git a/third_party/WebKit/Source/modules/notifications/NotificationEvent.idl b/third_party/WebKit/Source/modules/notifications/NotificationEvent.idl
index 2d4045d..42617777 100644
--- a/third_party/WebKit/Source/modules/notifications/NotificationEvent.idl
+++ b/third_party/WebKit/Source/modules/notifications/NotificationEvent.idl
@@ -5,7 +5,7 @@
 // https://notifications.spec.whatwg.org/#service-worker-api
 
 [
-    Constructor(DOMString type, optional NotificationEventInit eventInitDict),
+    Constructor(DOMString type, NotificationEventInit eventInitDict),
     Exposed=ServiceWorker,
     RuntimeEnabled=Notifications,
 ] interface NotificationEvent : ExtendableEvent {
diff --git a/third_party/WebKit/Source/modules/notifications/NotificationEventInit.idl b/third_party/WebKit/Source/modules/notifications/NotificationEventInit.idl
index 460ee7a6..79ab16b 100644
--- a/third_party/WebKit/Source/modules/notifications/NotificationEventInit.idl
+++ b/third_party/WebKit/Source/modules/notifications/NotificationEventInit.idl
@@ -5,6 +5,6 @@
 // https://notifications.spec.whatwg.org/#notificationevent
 
 dictionary NotificationEventInit : ExtendableEventInit {
-    Notification notification;
+    required Notification notification;
     DOMString action = "";
 };
diff --git a/third_party/brotli/README.chromium b/third_party/brotli/README.chromium
index 972cdb3..813e758 100644
--- a/third_party/brotli/README.chromium
+++ b/third_party/brotli/README.chromium
@@ -1,6 +1,6 @@
 Name: Brotli
 URL: https://github.com/google/brotli
-Version: c90ec29f54e9165df815b0f1311cfddb1be4afad
+Version: 66db08156eba94f1fb0f77b6af519e4adedea8bf
 License: Apache 2.0
 License File: LICENSE
 Security Critical: yes
@@ -11,8 +11,8 @@
 to decode WOFF 2.0 fonts.
 
 Local Modifications:
-- This only includes the dec/ directory and the README.md file,
-  removing unneeded direcories such as encoder, tests, and tools.
+- This only includes the dec/ directory, the README.md and the LICENSE
+  files, removing unneeded direcories such as encoder, tests, and tools.
 - .gitignore: Added.
 - BUILD.gn: Added.
 - brotli.gyp: Added.
diff --git a/third_party/brotli/dec/bit_reader.h b/third_party/brotli/dec/bit_reader.h
index f390348..468afe1 100644
--- a/third_party/brotli/dec/bit_reader.h
+++ b/third_party/brotli/dec/bit_reader.h
@@ -18,6 +18,7 @@
 #ifndef BROTLI_DEC_BIT_READER_H_
 #define BROTLI_DEC_BIT_READER_H_
 
+#include <stdio.h>
 #include <string.h>
 #include "./port.h"
 #include "./types.h"
diff --git a/third_party/brotli/dec/decode.c b/third_party/brotli/dec/decode.c
index bd0d2132..5d4af1d9 100644
--- a/third_party/brotli/dec/decode.c
+++ b/third_party/brotli/dec/decode.c
@@ -73,6 +73,34 @@
 
 #define NUM_DISTANCE_SHORT_CODES 16
 
+BrotliState* BrotliCreateState(
+    brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) {
+  BrotliState* state = 0;
+  if (!alloc_func && !free_func) {
+    state = (BrotliState*)malloc(sizeof(BrotliState));
+  } else if (alloc_func && free_func) {
+    state = (BrotliState*)alloc_func(opaque, sizeof(BrotliState));
+  }
+  if (state == 0) {
+    (void)BROTLI_FAILURE();
+    return 0;
+  }
+  BrotliStateInitWithCustomAllocators(state, alloc_func, free_func, opaque);
+  return state;
+}
+
+/* Deinitializes and frees BrotliState instance. */
+void BrotliDestroyState(BrotliState* state) {
+  if (!state) {
+    return;
+  } else {
+    brotli_free_func free_func = state->free_func;
+    void* opaque = state->memory_manager_opaque;
+    BrotliStateCleanup(state);
+    free_func(opaque, state);
+  }
+}
+
 /* Decodes a number in the range [9..24], by reading 1 - 7 bits.
    Precondition: bit-reader accumulator has at least 7 bits. */
 static uint32_t DecodeWindowBits(BrotliBitReader* br) {
@@ -907,7 +935,7 @@
       s->context_index = 0;
       BROTLI_LOG_UINT(context_map_size);
       BROTLI_LOG_UINT(*num_htrees);
-      *context_map_arg = (uint8_t*)malloc((size_t)context_map_size);
+      *context_map_arg = (uint8_t*)BROTLI_ALLOC(s, (size_t)context_map_size);
       if (*context_map_arg == 0) {
         return BROTLI_FAILURE();
       }
@@ -1006,7 +1034,7 @@
 
 /* Decodes a command or literal and updates block type ringbuffer.
    Reads 3..54 bits. */
-static int BROTLI_INLINE DecodeBlockTypeAndLength(int safe,
+static BROTLI_INLINE int DecodeBlockTypeAndLength(int safe,
     BrotliState* s, int tree_type) {
   uint32_t max_block_type = s->num_block_types[tree_type];
   int tree_offset = tree_type * BROTLI_HUFFMAN_MAX_TABLE_SIZE;
@@ -1048,7 +1076,7 @@
 
 /* Decodes the block type and updates the state for literal context.
    Reads 3..54 bits. */
-static int BROTLI_INLINE DecodeLiteralBlockSwitchInternal(int safe,
+static BROTLI_INLINE int DecodeLiteralBlockSwitchInternal(int safe,
     BrotliState* s) {
   uint8_t context_mode;
   uint32_t context_offset;
@@ -1075,7 +1103,7 @@
 
 /* Block switch for insert/copy length.
    Reads 3..54 bits. */
-static int BROTLI_INLINE DecodeCommandBlockSwitchInternal(int safe,
+static BROTLI_INLINE int DecodeCommandBlockSwitchInternal(int safe,
     BrotliState* s) {
   if (!DecodeBlockTypeAndLength(safe, s, 1)) {
     return 0;
@@ -1093,7 +1121,7 @@
 
 /* Block switch for distance codes.
    Reads 3..54 bits. */
-static int BROTLI_INLINE DecodeDistanceBlockSwitchInternal(int safe,
+static BROTLI_INLINE int DecodeDistanceBlockSwitchInternal(int safe,
     BrotliState* s) {
   if (!DecodeBlockTypeAndLength(safe, s, 2)) {
     return 0;
@@ -1255,7 +1283,7 @@
   }
 
   s->ringbuffer_mask = s->ringbuffer_size - 1;
-  s->ringbuffer = (uint8_t*)malloc((size_t)(s->ringbuffer_size +
+  s->ringbuffer = (uint8_t*)BROTLI_ALLOC(s, (size_t)(s->ringbuffer_size +
       kRingBufferWriteAheadSlack + kBrotliMaxDictionaryWordLength));
   if (s->ringbuffer == 0) {
     return 0;
@@ -1289,7 +1317,7 @@
   return BROTLI_RESULT_SUCCESS;
 }
 
-static void BROTLI_INLINE TakeDistanceFromRingBuffer(BrotliState* s) {
+static BROTLI_INLINE void TakeDistanceFromRingBuffer(BrotliState* s) {
   if (s->distance_code == 0) {
     --s->dist_rb_idx;
     s->distance_code = s->dist_rb[s->dist_rb_idx & 3];
@@ -1329,7 +1357,7 @@
 }
 
 /* Precondition: s->distance_code < 0 */
-static int BROTLI_INLINE ReadDistanceInternal(int safe,
+static BROTLI_INLINE int ReadDistanceInternal(int safe,
     BrotliState* s, BrotliBitReader* br) {
   int distval;
   BrotliBitReaderState memento;
@@ -1386,15 +1414,15 @@
   return 1;
 }
 
-static void BROTLI_INLINE ReadDistance(BrotliState* s, BrotliBitReader* br) {
+static BROTLI_INLINE void ReadDistance(BrotliState* s, BrotliBitReader* br) {
   ReadDistanceInternal(0, s, br);
 }
 
-static int BROTLI_INLINE SafeReadDistance(BrotliState* s, BrotliBitReader* br) {
+static BROTLI_INLINE int SafeReadDistance(BrotliState* s, BrotliBitReader* br) {
   return ReadDistanceInternal(1, s, br);
 }
 
-static int BROTLI_INLINE ReadCommandInternal(int safe,
+static BROTLI_INLINE int ReadCommandInternal(int safe,
     BrotliState* s, BrotliBitReader* br, int* insert_length) {
   uint32_t cmd_code;
   uint32_t insert_len_extra = 0;
@@ -1432,12 +1460,12 @@
   return 1;
 }
 
-static void BROTLI_INLINE ReadCommand(BrotliState* s, BrotliBitReader* br,
+static BROTLI_INLINE void ReadCommand(BrotliState* s, BrotliBitReader* br,
     int* insert_length) {
   ReadCommandInternal(0, s, br, insert_length);
 }
 
-static int BROTLI_INLINE SafeReadCommand(BrotliState* s, BrotliBitReader* br,
+static BROTLI_INLINE int SafeReadCommand(BrotliState* s, BrotliBitReader* br,
     int* insert_length) {
   return ReadCommandInternal(1, s, br, insert_length);
 }
@@ -1833,10 +1861,10 @@
   size_t total_out;
 
   if (s->legacy_input_buffer == 0) {
-    s->legacy_input_buffer = (uint8_t*)malloc(kBufferSize);
+    s->legacy_input_buffer = (uint8_t*)BROTLI_ALLOC(s, kBufferSize);
   }
   if (s->legacy_output_buffer == 0) {
-    s->legacy_output_buffer = (uint8_t*)malloc(kBufferSize);
+    s->legacy_output_buffer = (uint8_t*)BROTLI_ALLOC(s, kBufferSize);
   }
   if (s->legacy_input_buffer == 0 || s->legacy_output_buffer == 0) {
     return BROTLI_FAILURE();
@@ -2010,7 +2038,7 @@
             s->max_backward_distance - s->custom_dict_size;
 
         /* Allocate memory for both block_type_trees and block_len_trees. */
-        s->block_type_trees = (HuffmanCode*)malloc(
+        s->block_type_trees = (HuffmanCode*)BROTLI_ALLOC(s,
             6 * BROTLI_HUFFMAN_MAX_TABLE_SIZE * sizeof(HuffmanCode));
         if (s->block_type_trees == 0) {
           result = BROTLI_FAILURE();
@@ -2145,7 +2173,8 @@
         BROTLI_LOG_UINT(s->num_direct_distance_codes);
         BROTLI_LOG_UINT(s->distance_postfix_bits);
         s->distance_postfix_mask = (int)BitMask(s->distance_postfix_bits);
-        s->context_modes = (uint8_t*)malloc((size_t)s->num_block_types[0]);
+        s->context_modes =
+            (uint8_t*)BROTLI_ALLOC(s, (size_t)s->num_block_types[0]);
         if (s->context_modes == 0) {
           result = BROTLI_FAILURE();
           break;
@@ -2188,13 +2217,13 @@
           if (result != BROTLI_RESULT_SUCCESS) {
             break;
           }
-          BrotliHuffmanTreeGroupInit(
-              &s->literal_hgroup, kNumLiteralCodes, s->num_literal_htrees);
-          BrotliHuffmanTreeGroupInit(
-              &s->insert_copy_hgroup, kNumInsertAndCopyCodes,
+          BrotliHuffmanTreeGroupInit(s, &s->literal_hgroup, kNumLiteralCodes,
+                                     s->num_literal_htrees);
+          BrotliHuffmanTreeGroupInit(s, &s->insert_copy_hgroup,
+                                     kNumInsertAndCopyCodes,
               s->num_block_types[1]);
-          BrotliHuffmanTreeGroupInit(
-              &s->distance_hgroup, num_distance_codes, s->num_dist_htrees);
+          BrotliHuffmanTreeGroupInit(s, &s->distance_hgroup, num_distance_codes,
+                                     s->num_dist_htrees);
           if (s->literal_hgroup.codes == 0 ||
               s->insert_copy_hgroup.codes == 0 ||
               s->distance_hgroup.codes == 0) {
diff --git a/third_party/brotli/dec/decode.h b/third_party/brotli/dec/decode.h
index 78a156e..57b68615 100644
--- a/third_party/brotli/dec/decode.h
+++ b/third_party/brotli/dec/decode.h
@@ -51,6 +51,16 @@
 }
 #endif
 
+/* Creates the instance of BrotliState and initializes it. alloc_func and
+   free_func MUST be both zero or both non-zero. In the case they are both zero,
+   default memory allocators are used. opaque parameter is passed to alloc_func
+   and free_func when they are called. */
+BrotliState* BrotliCreateState(
+    brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque);
+
+/* Deinitializes and frees BrotliState instance. */
+void BrotliDestroyState(BrotliState* state);
+
 /* Sets *decoded_size to the decompressed size of the given encoded stream. */
 /* This function only works if the encoded buffer has a single meta block, */
 /* or if it has two meta-blocks, where the first is uncompressed and the */
diff --git a/third_party/brotli/dec/huffman.c b/third_party/brotli/dec/huffman.c
index 0628c36..a580aae 100644
--- a/third_party/brotli/dec/huffman.c
+++ b/third_party/brotli/dec/huffman.c
@@ -362,24 +362,6 @@
   return goal_size;
 }
 
-void BrotliHuffmanTreeGroupInit(HuffmanTreeGroup* group, uint32_t alphabet_size,
-                                uint32_t ntrees) {
-  /* Pack two mallocs into one */
-  const size_t code_size =
-      sizeof(HuffmanCode) * (size_t)(ntrees * BROTLI_HUFFMAN_MAX_TABLE_SIZE);
-  const size_t htree_size = sizeof(HuffmanCode*) * (size_t)ntrees;
-  char *p = (char*)malloc(code_size + htree_size);
-  group->alphabet_size = (uint16_t)alphabet_size;
-  group->num_htrees = (uint16_t)ntrees;
-  group->codes = (HuffmanCode*)p;
-  group->htrees = (HuffmanCode**)(p + code_size);
-}
-
-void BrotliHuffmanTreeGroupRelease(HuffmanTreeGroup* group) {
-  BROTLI_FREE(group->codes);
-  group->htrees = NULL;
-}
-
 #if defined(__cplusplus) || defined(c_plusplus)
 }    /* extern "C" */
 #endif
diff --git a/third_party/brotli/dec/huffman.h b/third_party/brotli/dec/huffman.h
index bb67f4b..783cd7d 100644
--- a/third_party/brotli/dec/huffman.h
+++ b/third_party/brotli/dec/huffman.h
@@ -70,10 +70,6 @@
   uint16_t num_htrees;
 } HuffmanTreeGroup;
 
-void BrotliHuffmanTreeGroupInit(HuffmanTreeGroup* group,
-                                uint32_t alphabet_size, uint32_t ntrees);
-void BrotliHuffmanTreeGroupRelease(HuffmanTreeGroup* group);
-
 #if defined(__cplusplus) || defined(c_plusplus)
 }    /* extern "C" */
 #endif
diff --git a/third_party/brotli/dec/port.h b/third_party/brotli/dec/port.h
index f8fc4a8..2f5b0ce 100644
--- a/third_party/brotli/dec/port.h
+++ b/third_party/brotli/dec/port.h
@@ -237,8 +237,10 @@
 #define BROTLI_HAS_UBFX 0
 #endif
 
-#define BROTLI_FREE(X) { \
-  free(X); \
+#define BROTLI_ALLOC(S, L) S->alloc_func(S->memory_manager_opaque, L)
+
+#define BROTLI_FREE(S, X) { \
+  S->free_func(S->memory_manager_opaque, X); \
   X = NULL; \
 }
 
diff --git a/third_party/brotli/dec/state.c b/third_party/brotli/dec/state.c
index f4f239a..32c1eceb 100644
--- a/third_party/brotli/dec/state.c
+++ b/third_party/brotli/dec/state.c
@@ -23,7 +23,32 @@
 extern "C" {
 #endif
 
+static void* DefaultAllocFunc(void* opaque, size_t size) {
+  BROTLI_UNUSED(opaque);
+  return malloc(size);
+}
+
+static void DefaultFreeFunc(void* opaque, void* address) {
+  BROTLI_UNUSED(opaque);
+  free(address);
+}
+
 void BrotliStateInit(BrotliState* s) {
+  BrotliStateInitWithCustomAllocators(s, 0, 0, 0);
+}
+
+void BrotliStateInitWithCustomAllocators(BrotliState* s,
+    brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) {
+  if (!alloc_func) {
+    s->alloc_func = DefaultAllocFunc;
+    s->free_func = DefaultFreeFunc;
+    s->memory_manager_opaque = 0;
+  } else {
+    s->alloc_func = alloc_func;
+    s->free_func = free_func;
+    s->memory_manager_opaque = opaque;
+  }
+
   BrotliInitBitReader(&s->br);
   s->state = BROTLI_STATE_UNINITED;
   s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NONE;
@@ -120,22 +145,22 @@
 }
 
 void BrotliStateCleanupAfterMetablock(BrotliState* s) {
-  BROTLI_FREE(s->context_modes);
-  BROTLI_FREE(s->context_map);
-  BROTLI_FREE(s->dist_context_map);
+  BROTLI_FREE(s, s->context_modes);
+  BROTLI_FREE(s, s->context_map);
+  BROTLI_FREE(s, s->dist_context_map);
 
-  BrotliHuffmanTreeGroupRelease(&s->literal_hgroup);
-  BrotliHuffmanTreeGroupRelease(&s->insert_copy_hgroup);
-  BrotliHuffmanTreeGroupRelease(&s->distance_hgroup);
+  BrotliHuffmanTreeGroupRelease(s, &s->literal_hgroup);
+  BrotliHuffmanTreeGroupRelease(s, &s->insert_copy_hgroup);
+  BrotliHuffmanTreeGroupRelease(s, &s->distance_hgroup);
 }
 
 void BrotliStateCleanup(BrotliState* s) {
   BrotliStateCleanupAfterMetablock(s);
 
-  BROTLI_FREE(s->ringbuffer);
-  BROTLI_FREE(s->block_type_trees);
-  BROTLI_FREE(s->legacy_input_buffer);
-  BROTLI_FREE(s->legacy_output_buffer);
+  BROTLI_FREE(s, s->ringbuffer);
+  BROTLI_FREE(s, s->block_type_trees);
+  BROTLI_FREE(s, s->legacy_input_buffer);
+  BROTLI_FREE(s, s->legacy_output_buffer);
 }
 
 int BrotliStateIsStreamStart(const BrotliState* s) {
@@ -147,6 +172,23 @@
   return s->state == BROTLI_STATE_DONE;
 }
 
+void BrotliHuffmanTreeGroupInit(BrotliState* s, HuffmanTreeGroup* group,
+    uint32_t alphabet_size, uint32_t ntrees) {
+  /* Pack two allocations into one */
+  const size_t code_size =
+      sizeof(HuffmanCode) * (size_t)(ntrees * BROTLI_HUFFMAN_MAX_TABLE_SIZE);
+  const size_t htree_size = sizeof(HuffmanCode*) * (size_t)ntrees;
+  char *p = (char*)BROTLI_ALLOC(s, code_size + htree_size);
+  group->alphabet_size = (uint16_t)alphabet_size;
+  group->num_htrees = (uint16_t)ntrees;
+  group->codes = (HuffmanCode*)p;
+  group->htrees = (HuffmanCode**)(p + code_size);
+}
+
+void BrotliHuffmanTreeGroupRelease(BrotliState* s, HuffmanTreeGroup* group) {
+  BROTLI_FREE(s, group->codes);
+  group->htrees = NULL;
+}
 
 #if defined(__cplusplus) || defined(c_plusplus)
 } /* extern "C" */
diff --git a/third_party/brotli/dec/state.h b/third_party/brotli/dec/state.h
index 0d9329b..2adf26c8 100644
--- a/third_party/brotli/dec/state.h
+++ b/third_party/brotli/dec/state.h
@@ -106,6 +106,10 @@
   BrotliRunningState state;
   BrotliBitReader br;
 
+  brotli_alloc_func alloc_func;
+  brotli_free_func free_func;
+  void* memory_manager_opaque;
+
   /* Temporary storage for remaining input. */
   union {
     uint64_t u64;
@@ -234,10 +238,16 @@
 typedef struct BrotliStateStruct BrotliState;
 
 void BrotliStateInit(BrotliState* s);
+void BrotliStateInitWithCustomAllocators(BrotliState* s,
+                                         brotli_alloc_func alloc_func,
+                                         brotli_free_func free_func,
+                                         void* opaque);
 void BrotliStateCleanup(BrotliState* s);
 void BrotliStateMetablockBegin(BrotliState* s);
 void BrotliStateCleanupAfterMetablock(BrotliState* s);
-
+void BrotliHuffmanTreeGroupInit(BrotliState* s, HuffmanTreeGroup* group,
+                                uint32_t alphabet_size, uint32_t ntrees);
+void BrotliHuffmanTreeGroupRelease(BrotliState* s, HuffmanTreeGroup* group);
 
 /* Returns 1, if s is in a state where we have not read any input bytes yet,
    and 0 otherwise */
diff --git a/third_party/brotli/dec/types.h b/third_party/brotli/dec/types.h
index 8a9cc4a8..096b5911 100644
--- a/third_party/brotli/dec/types.h
+++ b/third_party/brotli/dec/types.h
@@ -33,4 +33,15 @@
 #include <stdint.h>
 #endif  /* defined(_MSC_VER) && (_MSC_VER < 1600) */
 
+/* Allocating function pointer. Function MUST return 0 in the case of failure.
+   Otherwise it MUST return a valid pointer to a memory region of at least
+   size length. Neither items nor size are allowed to be 0.
+   opaque argument is a pointer provided by client and could be used to bind
+   function to specific object (memory pool). */
+typedef void* (*brotli_alloc_func) (void* opaque, size_t size);
+
+/* Deallocating function pointer. Function SHOULD be no-op in the case the
+   address is 0. */
+typedef void  (*brotli_free_func)  (void* opaque, void* address);
+
 #endif  /* BROTLI_DEC_TYPES_H_ */
diff --git a/third_party/libjingle/BUILD.gn b/third_party/libjingle/BUILD.gn
index 9a80a44..3843e44c 100644
--- a/third_party/libjingle/BUILD.gn
+++ b/third_party/libjingle/BUILD.gn
@@ -296,7 +296,6 @@
   # as is supported in the GYP build. It's not clear what this is used for.
   source_set("libjingle_webrtc_common") {
     sources = [
-      "overrides/talk/media/webrtc/webrtcexport.h",
       "source/talk/app/webrtc/audiotrack.cc",
       "source/talk/app/webrtc/audiotrack.h",
       "source/talk/app/webrtc/datachannel.cc",
diff --git a/third_party/openh264/BUILD.gn b/third_party/openh264/BUILD.gn
index 5d8e796..1b1ea41 100644
--- a/third_party/openh264/BUILD.gn
+++ b/third_party/openh264/BUILD.gn
@@ -14,9 +14,8 @@
   cflags = []
   defines = []
 
-  # Compiler warnings to ignore.
-  if (!is_win) {
-    # GCC/clang flags
+  # GCC and clang flags. MSVS (is_win && !is_clang) does not use cflags.
+  if (!is_win || is_clang) {
     cflags += [
       "-Wno-format",
       "-Wno-header-hygiene",
diff --git a/third_party/openh264/openh264.gyp b/third_party/openh264/openh264.gyp
index e461ee6..4d46bfc 100644
--- a/third_party/openh264/openh264.gyp
+++ b/third_party/openh264/openh264.gyp
@@ -9,41 +9,52 @@
   ],
   # Settings shared by all openh264 targets.
   'target_defaults': {
-    'variables': {
-      'conditions': [
-        ['OS!="win"', {
-          # GCC/clang flags
+    'conditions': [
+      ['OS!="win"', {
+        # GCC and clang flags.
+        'variables': {
           'openh264_cflags_add': [
             '-Wno-format',
-            '-Wno-header-hygiene',
             '-Wno-unused-value',
           ],
           'openh264_cflags_remove': [
             '-Wall',
             '-Wheader-hygiene',
           ],
-        },{
-          # Windows uses 'msvs_disabled_warnings' instead, for MSVC flags.
-          'openh264_cflags_add': [],
-          'openh264_cflags_remove': [],
-        }],
-      ],
-    },
-    'cflags': [ '<@(openh264_cflags_add)' ],
-    'cflags!': [ '<@(openh264_cflags_remove)' ],
-    'xcode_settings': {
-      'WARNING_CFLAGS': [ '<@(openh264_cflags_add)' ],
-      'WARNING_CFLAGS!': [ '<@(openh264_cflags_remove)' ],
-    },
-    'msvs_disabled_warnings': [
-      4324,  # structure was padded
-      4245,  # signed/unsigned mismatch
-      4701,  # uninitialized variable used
-      4702,  # unreachable code
-    ],
-
-    # Platform-specific defines.
-    'conditions': [
+        },
+        'cflags': [ '<@(openh264_cflags_add)' ],
+        'cflags!': [ '<@(openh264_cflags_remove)' ],
+        'xcode_settings': {
+          'WARNING_CFLAGS': [ '<@(openh264_cflags_add)' ],
+          'WARNING_CFLAGS!': [ '<@(openh264_cflags_remove)' ],
+        },
+      }, {
+        # The land of special cases: Windows.
+        'conditions': [
+          ['clang==0', {
+            # MSVS compiler uses warning numbers instead of cflags.
+            'msvs_disabled_warnings': [
+              4324,  # structure was padded
+              4245,  # signed/unsigned mismatch
+              4701,  # uninitialized variable used
+              4702,  # unreachable code
+            ],
+          }, {
+            # For clang on windows, |cflags| is mysteriously ignored and we
+            # resort to using |AdditionalOptions| instead.
+            'msvs_settings': {
+              'VCCLCompilerTool': {
+                'AdditionalOptions!': [
+                  '-Wheader-hygiene',
+                ],
+                'AdditionalOptions': [
+                  '-Wno-unused-value',
+                ],
+              },
+            },
+          }],
+        ],
+      }],
       ['OS=="android"', {
         'defines': [
           # Android NDK is necessary for its cpufeatures and this define is
diff --git a/tools/android/loading/devtools_monitor.py b/tools/android/loading/devtools_monitor.py
index d4847cd81..fc652d2 100644
--- a/tools/android/loading/devtools_monitor.py
+++ b/tools/android/loading/devtools_monitor.py
@@ -173,3 +173,25 @@
   def GetEvents(self):
     """Returns a list of collected events, finalizing the state if necessary."""
     pass
+
+  def ToJsonDict(self):
+    """Serializes to a dictionary, to be dumped as JSON.
+
+    Returns:
+      A dict that can be dumped by the json module, and loaded by
+      FromJsonDict().
+    """
+    pass
+
+  @classmethod
+  def FromJsonDict(cls, json_dict):
+    """Returns a Track instance constructed from data dumped by
+       Track.ToJsonDict().
+
+    Args:
+      json_data: (dict) Parsed from a JSON file using the json module.
+
+    Returns:
+      a Track instance.
+    """
+    pass
diff --git a/tools/android/loading/request_track.py b/tools/android/loading/request_track.py
index 995c574..de3fd115 100644
--- a/tools/android/loading/request_track.py
+++ b/tools/android/loading/request_track.py
@@ -94,16 +94,20 @@
     request_time = self.timing.request_time
     return (timestamp - request_time) * 1000
 
-  def ToDict(self):
+  def ToJsonDict(self):
     return copy.deepcopy(self.__dict__)
 
   @classmethod
-  def FromDict(cls, data_dict):
+  def FromJsonDict(cls, data_dict):
     result = Request()
     for (k, v) in data_dict.items():
       setattr(result, k, v)
     return result
 
+  # For testing.
+  def __eq__(self, o):
+    return self.__dict__ == o.__dict__
+
 
 class RequestTrack(devtools_monitor.Track):
   """Aggregates request data."""
@@ -135,6 +139,20 @@
                       % len(self._requests_in_flight))
     return self._requests
 
+  def ToJsonDict(self):
+    if self._requests_in_flight:
+      logging.warning('Requests in flight, will be ignored in the dump')
+    return {'events': [request.ToJsonDict() for request in self._requests]}
+
+  @classmethod
+  def FromJsonDict(cls, json_dict):
+    assert 'events' in json_dict
+    result = RequestTrack(None)
+    requests = [Request.FromJsonDict(request)
+                for request in json_dict['events']]
+    result._requests = requests
+    return result
+
   def _RequestWillBeSent(self, request_id, params):
     # Several "requestWillBeSent" events can be dispatched in a row in the case
     # of redirects.
@@ -239,6 +257,9 @@
     self._completed_requests_by_id[request_id] = request
     self._requests.append(request)
 
+  def __eq__(self, o):
+    return self._requests == o._requests
+
 
 RequestTrack._METHOD_TO_HANDLER = {
     'Network.requestWillBeSent': RequestTrack._RequestWillBeSent,
diff --git a/tools/android/loading/request_track_unittest.py b/tools/android/loading/request_track_unittest.py
index 5a25b813..459e2de 100644
--- a/tools/android/loading/request_track_unittest.py
+++ b/tools/android/loading/request_track_unittest.py
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import json
 import unittest
 
 from request_track import (Request, RequestTrack, _TimingFromDict)
@@ -242,6 +243,17 @@
         RequestTrackTestCase._DATA_RECEIVED_2['params']['encodedDataLength'],
         r.data_chunks[1][1])
 
+  def testCanSerialize(self):
+    self._ValidSequence(self.request_track)
+    json_dict = self.request_track.ToJsonDict()
+    _ = json.dumps(json_dict)  # Should not raise an exception.
+
+  def testCanDeserialize(self):
+    self._ValidSequence(self.request_track)
+    json_dict = self.request_track.ToJsonDict()
+    request_track = RequestTrack.FromJsonDict(json_dict)
+    self.assertEquals(self.request_track, request_track)
+
   @classmethod
   def _ValidSequence(cls, request_track):
     request_track.Handle(
diff --git a/tools/android/loading/trace_recorder.py b/tools/android/loading/trace_recorder.py
index a3f289b..6e638c4 100755
--- a/tools/android/loading/trace_recorder.py
+++ b/tools/android/loading/trace_recorder.py
@@ -28,8 +28,9 @@
     self._connection = connection
     self._events = []
     self._main_frame_id = None
-    self._connection.RegisterListener('Page.frameStartedLoading', self)
-    self._connection.RegisterListener('Page.frameStoppedLoading', self)
+    if self._connection:
+      self._connection.RegisterListener('Page.frameStartedLoading', self)
+      self._connection.RegisterListener('Page.frameStoppedLoading', self)
 
   def Handle(self, method, msg):
     params = msg['params']
@@ -47,6 +48,17 @@
   def GetEvents(self):
     return self._events
 
+  def ToJsonDict(self):
+    return {'events': [event for event in self._events]}
+
+  @classmethod
+  def FromJsonDict(cls, json_dict):
+    assert 'events' in json_dict
+    result = PageTrack(None)
+    events = [event for event in json_dict['events']]
+    result._events = events
+    return result
+
 
 class AndroidTraceRecorder(object):
   """Records a loading trace."""
diff --git a/url/gurl_unittest.cc b/url/gurl_unittest.cc
index 1320609..abc3f106 100644
--- a/url/gurl_unittest.cc
+++ b/url/gurl_unittest.cc
@@ -67,7 +67,12 @@
 // the parser is already tested and works, so we are mostly interested if the
 // object does the right thing with the results.
 TEST(GURLTest, Components) {
+  GURL empty_url(WStringToUTF16(L""));
+  EXPECT_TRUE(empty_url.is_empty());
+  EXPECT_FALSE(empty_url.is_valid());
+
   GURL url(WStringToUTF16(L"http://user:pass@google.com:99/foo;bar?q=a#ref"));
+  EXPECT_FALSE(url.is_empty());
   EXPECT_TRUE(url.is_valid());
   EXPECT_TRUE(url.SchemeIs("http"));
   EXPECT_FALSE(url.SchemeIsFile());