diff --git a/DEPS b/DEPS
index 3a72844..fa07614 100644
--- a/DEPS
+++ b/DEPS
@@ -145,11 +145,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': '6ef31815a694c7e8555c9217288af19f21af4901',
+  'skia_revision': '5e2c489a335cc52155f983cc065565681e476d1f',
   # 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': '1d37448e10c317e8aa120892ee1c6ec7512130ed',
+  'v8_revision': '83ed30595d74cd1ea3f4396984df34e8987669cc',
   # 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.
@@ -157,15 +157,15 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '956770025c8ca163847b5c21da596f07d024d1dd',
+  'angle_revision': '2251102112312a9762898ce785afce6adc4f5ca3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': '34c59c9b88b76564cf534aad2f0033a472182d87',
+  'swiftshader_revision': '5e4e8b0af5fa0b00de29c77ecf56014e409b53c0',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '12c357b447a45e4a10a96426e84c4fa495774108',
+  'pdfium_revision': '5e97d0125fd968b043ce7e39e7a6409595343234',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -280,7 +280,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': 'b6d7c537088835c386bc7850d85300f9f72d4cf6',
+  'dawn_revision': '35670f183a730beb8e11aecf75272053560b0ac3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -814,7 +814,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '7588713317d681bbf37e7df716c691bfbecd3524',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '811aead064fba1e209195aa5830eb00b1c19ad1b',
       'condition': 'checkout_linux',
   },
 
@@ -829,7 +829,7 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'c267899484bac0f024a10b32452d4cee6ffa6068',
+      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '7e90794dfac8e32ce3ecc14029046d7e05fd91b2',
       'condition': 'checkout_linux',
   },
 
@@ -839,7 +839,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '9fc459b69c7840c3c67d2359cd8931e962bcae84',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'e765f652958c26fb12f5843b9160b15c7adad347',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1212,7 +1212,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '827c26f6435e3515ee54d0f4fb5846ec51e2811e',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '5c7d9733468d518942b2cbfe471999c403503c39',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1380,7 +1380,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'abaae129d9a0c6e1e092067e0b105475df43352e',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '34aee67c11454e6c20c1a48702e92b48062cd2bf',
+    Var('webrtc_git') + '/src.git' + '@' + '01525f9e03384601605ccaa5603481f1de860444',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1421,7 +1421,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@7741db7456bc7c76d7a91975efa47a8292a6d90b',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@f9fbd0f9b5e93d2a36984ca8e0328e436d8b576d',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/browser/aw_metrics_service_client.cc b/android_webview/browser/aw_metrics_service_client.cc
index 7b27757a..247ee6d 100644
--- a/android_webview/browser/aw_metrics_service_client.cc
+++ b/android_webview/browser/aw_metrics_service_client.cc
@@ -59,6 +59,17 @@
 // - WebView uses the low-entropy source for all studies, so there would be
 //   crosstalk between the metrics sampling study and all other studies.
 bool IsInSample(const std::string& client_id) {
+  // TODO(ntfschr): remove these CHECK()s when we rule this out as the culprit
+  // for https://crbug.com/992250.
+  CHECK_EQ(36u, client_id.length()) << "client ID should be 36 chars exactly";
+  for (const char& c : client_id) {
+    bool char_is_digit = (c >= '0' && c <= '9');
+    bool char_is_a_through_f = (c >= 'a' && c <= 'f');
+    bool char_is_hyphen = (c == '-');
+    CHECK(char_is_digit || char_is_a_through_f || char_is_hyphen)
+        << "client_id should be composed of [0-9a-f] or '-'.";
+  }
+
   // client_id comes from base::GenerateGUID(), so its value is random/uniform,
   // except for a few bit positions with fixed values, and some hyphens. Rather
   // than separating the random payload from the fixed bits, just hash the whole
diff --git a/android_webview/browser/js_java_interaction/js_api_handler.cc b/android_webview/browser/js_java_interaction/js_api_handler.cc
index da29cda..7471e4c 100644
--- a/android_webview/browser/js_java_interaction/js_api_handler.cc
+++ b/android_webview/browser/js_java_interaction/js_api_handler.cc
@@ -24,7 +24,7 @@
 }
 
 void JsApiHandler::PostMessage(
-    const std::string& message,
+    const base::string16& message,
     std::vector<mojo::ScopedMessagePipeHandle> ports) {
   DCHECK(render_frame_host_);
 
@@ -50,7 +50,7 @@
 
   JNIEnv* env = base::android::AttachCurrentThread();
   aw_contents->OnPostMessage(
-      env, base::android::ConvertUTF8ToJavaString(env, message),
+      env, base::android::ConvertUTF16ToJavaString(env, message),
       base::android::ConvertUTF8ToJavaString(env, source_origin.Serialize()),
       web_contents->GetMainFrame() == render_frame_host_,
       base::android::ToJavaIntArray(env, int_ports.data(), int_ports.size()));
diff --git a/android_webview/browser/js_java_interaction/js_api_handler.h b/android_webview/browser/js_java_interaction/js_api_handler.h
index feeefa8..9952e7a 100644
--- a/android_webview/browser/js_java_interaction/js_api_handler.h
+++ b/android_webview/browser/js_java_interaction/js_api_handler.h
@@ -5,10 +5,10 @@
 #ifndef ANDROID_WEBVIEW_BROWSER_JS_JAVA_INTERACTION_JS_API_HANDLER_H_
 #define ANDROID_WEBVIEW_BROWSER_JS_JAVA_INTERACTION_JS_API_HANDLER_H_
 
-#include <string>
 #include <vector>
 
 #include "android_webview/common/js_java_interaction/interfaces.mojom.h"
+#include "base/strings/string16.h"
 #include "mojo/public/cpp/bindings/associated_receiver.h"
 #include "mojo/public/cpp/bindings/associated_remote.h"
 #include "mojo/public/cpp/bindings/pending_associated_receiver.h"
@@ -32,7 +32,7 @@
       mojo::PendingAssociatedReceiver<mojom::JsApiHandler> pending_receiver);
 
   // mojom::JsApiHandler implementation.
-  void PostMessage(const std::string& message,
+  void PostMessage(const base::string16& message,
                    std::vector<mojo::ScopedMessagePipeHandle> ports) override;
 
  private:
diff --git a/android_webview/browser/js_java_interaction/js_java_configurator_host.cc b/android_webview/browser/js_java_interaction/js_java_configurator_host.cc
index 8dc26b0..147dcabd 100644
--- a/android_webview/browser/js_java_interaction/js_java_configurator_host.cc
+++ b/android_webview/browser/js_java_interaction/js_java_configurator_host.cc
@@ -28,16 +28,14 @@
     bool need_to_inject_js_object,
     const base::android::JavaParamRef<jstring>& js_object_name,
     const base::android::JavaParamRef<jobjectArray>& allowed_origin_rules) {
-  std::string native_js_object_name;
-  base::android::ConvertJavaStringToUTF8(env, js_object_name,
-                                         &native_js_object_name);
+  base::android::ConvertJavaStringToUTF16(env, js_object_name,
+                                          &js_object_name_);
 
   std::vector<std::string> native_allowed_origin_rules;
   AppendJavaStringArrayToStringVector(env, allowed_origin_rules,
                                       &native_allowed_origin_rules);
 
   need_to_inject_js_object_ = need_to_inject_js_object;
-  js_object_name_ = native_js_object_name;
   allowed_origin_rules_ = net::ProxyBypassRules();
   for (auto& rule : native_allowed_origin_rules) {
     if (!allowed_origin_rules_.AddRuleFromString(rule)) {
diff --git a/android_webview/browser/js_java_interaction/js_java_configurator_host.h b/android_webview/browser/js_java_interaction/js_java_configurator_host.h
index 16cc3da..b943dab 100644
--- a/android_webview/browser/js_java_interaction/js_java_configurator_host.h
+++ b/android_webview/browser/js_java_interaction/js_java_configurator_host.h
@@ -5,11 +5,9 @@
 #ifndef ANDROID_WEBVIEW_BROWSER_JS_JAVA_INTERACTION_JS_JAVA_CONFIGURATOR_HOST_H_
 #define ANDROID_WEBVIEW_BROWSER_JS_JAVA_INTERACTION_JS_JAVA_CONFIGURATOR_HOST_H_
 
-#include <string>
-#include <vector>
-
 #include "android_webview/common/js_java_interaction/interfaces.mojom.h"
 #include "base/android/scoped_java_ref.h"
+#include "base/strings/string16.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "net/proxy_resolution/proxy_bypass_rules.h"
 #include "services/network/public/mojom/proxy_config.mojom.h"
@@ -46,7 +44,7 @@
   void NotifyFrame(content::RenderFrameHost* render_frame_host);
 
   bool need_to_inject_js_object_ = false;
-  std::string js_object_name_;
+  base::string16 js_object_name_;
   // We use ProxyBypassRules because it has the functionality that suitable
   // here, but it is not for proxy bypass.
   net::ProxyBypassRules allowed_origin_rules_;
diff --git a/android_webview/common/js_java_interaction/interfaces.mojom b/android_webview/common/js_java_interaction/interfaces.mojom
index ab80e75..0fc719b 100644
--- a/android_webview/common/js_java_interaction/interfaces.mojom
+++ b/android_webview/common/js_java_interaction/interfaces.mojom
@@ -4,6 +4,7 @@
 
 module android_webview.mojom;
 
+import "mojo/public/mojom/base/string16.mojom";
 import "services/network/public/mojom/proxy_config.mojom";
 
 // For JavaScript postMessage() API, implemented by browser.
@@ -12,7 +13,8 @@
   // the current frame |origin|.
   // The |message| is an opaque type and the contents are defined by the client
   // of this API.
-  PostMessage(string message, array<handle<message_pipe>> ports);
+  PostMessage(mojo_base.mojom.String16 message,
+              array<handle<message_pipe>> ports);
 };
 
 // For browser to configure renderer, implemented by renderer.
@@ -21,6 +23,7 @@
   // a JavaScript object with the given |js_object_name| based on
   // |need_to_inject_js_object| flag. Only frames with the origin matches
   // |allowed_origin_rules| will have the object injected.
-  SetJsApiService(bool need_to_inject_js_object, string js_object_name,
+  SetJsApiService(bool need_to_inject_js_object,
+                  mojo_base.mojom.String16 js_object_name,
                   network.mojom.ProxyBypassRules allowed_origin_rules);
 };
\ No newline at end of file
diff --git a/android_webview/renderer/js_java_interaction/js_binding.cc b/android_webview/renderer/js_java_interaction/js_binding.cc
index 65b0d43..9a684e30 100644
--- a/android_webview/renderer/js_java_interaction/js_binding.cc
+++ b/android_webview/renderer/js_java_interaction/js_binding.cc
@@ -4,7 +4,6 @@
 
 #include "android_webview/renderer/js_java_interaction/js_binding.h"
 
-#include <string>
 #include <vector>
 
 #include "base/strings/string_util.h"
@@ -32,7 +31,7 @@
 // static
 std::unique_ptr<JsBinding> JsBinding::Install(
     content::RenderFrame* render_frame,
-    const std::string& js_object_name) {
+    const base::string16& js_object_name) {
   CHECK(!js_object_name.empty())
       << "JavaScript wrapper name shouldn't be empty";
 
@@ -72,7 +71,7 @@
 }
 
 void JsBinding::PostMessage(gin::Arguments* args) {
-  std::string message;
+  base::string16 message;
   if (!args->GetNext(&message)) {
     args->ThrowError();
     return;
diff --git a/android_webview/renderer/js_java_interaction/js_binding.h b/android_webview/renderer/js_java_interaction/js_binding.h
index 4e37254..5c28c09 100644
--- a/android_webview/renderer/js_java_interaction/js_binding.h
+++ b/android_webview/renderer/js_java_interaction/js_binding.h
@@ -9,6 +9,7 @@
 
 #include "android_webview/common/js_java_interaction/interfaces.mojom.h"
 #include "base/auto_reset.h"
+#include "base/strings/string16.h"
 #include "gin/arguments.h"
 #include "gin/wrappable.h"
 #include "mojo/public/cpp/bindings/associated_remote.h"
@@ -27,8 +28,9 @@
 class JsBinding : public gin::Wrappable<JsBinding> {
  public:
   static gin::WrapperInfo kWrapperInfo;
-  static std::unique_ptr<JsBinding> Install(content::RenderFrame* render_frame,
-                                            const std::string& js_object_name);
+  static std::unique_ptr<JsBinding> Install(
+      content::RenderFrame* render_frame,
+      const base::string16& js_object_name);
 
   ~JsBinding() final;
 
diff --git a/android_webview/renderer/js_java_interaction/js_java_configurator.cc b/android_webview/renderer/js_java_interaction/js_java_configurator.cc
index 701e4b0b..6b2e974 100644
--- a/android_webview/renderer/js_java_interaction/js_java_configurator.cc
+++ b/android_webview/renderer/js_java_interaction/js_java_configurator.cc
@@ -25,7 +25,7 @@
 
 void JsJavaConfigurator::SetJsApiService(
     bool need_to_inject_js_object,
-    const std::string& js_object_name,
+    const base::string16& js_object_name,
     const net::ProxyBypassRules& allowed_origin_rules) {
   need_to_inject_js_object_ = need_to_inject_js_object;
   js_object_name_ = js_object_name;
diff --git a/android_webview/renderer/js_java_interaction/js_java_configurator.h b/android_webview/renderer/js_java_interaction/js_java_configurator.h
index ed0b078..048b0c0 100644
--- a/android_webview/renderer/js_java_interaction/js_java_configurator.h
+++ b/android_webview/renderer/js_java_interaction/js_java_configurator.h
@@ -5,10 +5,8 @@
 #ifndef ANDROID_WEBVIEW_RENDERER_JS_JAVA_INTERACTION_JS_JAVA_CONFIGURATOR_H_
 #define ANDROID_WEBVIEW_RENDERER_JS_JAVA_INTERACTION_JS_JAVA_CONFIGURATOR_H_
 
-#include <string>
-#include <vector>
-
 #include "android_webview/common/js_java_interaction/interfaces.mojom.h"
+#include "base/strings/string16.h"
 #include "content/public/renderer/render_frame_observer.h"
 #include "mojo/public/cpp/bindings/associated_receiver.h"
 #include "net/proxy_resolution/proxy_bypass_rules.h"
@@ -30,7 +28,7 @@
   // mojom::Configurator implementation
   void SetJsApiService(
       bool inject_js_object,
-      const std::string& js_object_name,
+      const base::string16& js_object_name,
       const net::ProxyBypassRules& allowed_origin_rules) override;
 
   // RenderFrameObserver implementation
@@ -45,7 +43,7 @@
   bool IsOriginMatch();
 
   bool need_to_inject_js_object_ = false;
-  std::string js_object_name_;
+  base::string16 js_object_name_;
   // We use ProxyBypassRules because it has the functionality that suitable
   // here, but it is not for proxy bypass.
   net::ProxyBypassRules js_object_allowed_origin_rules_;
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 5759f80b..b7f1e63 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -1527,6 +1527,9 @@
       <message name="IDS_ASH_LOGIN_POD_PASSWORD_TAP_PLACEHOLDER" desc="Text to display as placeholder in the password field when the user can click/tap their profile picture to unlock.">
         Select your photo
       </message>
+      <message name="IDS_ASH_LOGIN_POD_PASSWORD_SMART_CARD_PIN_PLACEHOLDER" desc="Text to display as placeholder in the password field on the Login or Lock screen when the smart card PIN is requested.">
+        Smart card PIN
+      </message>
       <message name="IDS_ASH_LOGIN_ERROR_AUTHENTICATING" desc="Couldn't sign in because password is invalid">
         Sorry, your password couldn't be verified. Please try again.
       </message>
@@ -1692,6 +1695,12 @@
       <message name="IDS_ASH_LOGIN_PARENT_ACCESS_NEXT_NUMBER_PROMPT" desc="Accessible prompt read when next access code input field has been focused. Asks user to enter next piece of the access code.">
         Next number
       </message>
+      <message name="IDS_ASH_LOGIN_SMART_CARD_SIGN_IN_MESSAGE" desc="Label for the button shown in the user pod that starts signing in via a smart card.">
+        Sign in with smart card
+      </message>
+      <message name="IDS_ASH_LOGIN_SMART_CARD_SIGN_IN_FAILURE_MESSAGE" desc="Message shown in the user pod when the sign in attempt via a smart card fails.">
+        Couldn’t recognize your smart card. Try again.
+      </message>
 
       <!-- Multi-profiles intro dialog -->
       <message name="IDS_ASH_MULTIPROFILES_INTRO_HEADLINE" desc="Describes which feature multi-profiles intro dialog presents.">
diff --git a/ash/ash_strings_grd/IDS_ASH_LOGIN_POD_PASSWORD_SMART_CARD_PIN_PLACEHOLDER.png.sha1 b/ash/ash_strings_grd/IDS_ASH_LOGIN_POD_PASSWORD_SMART_CARD_PIN_PLACEHOLDER.png.sha1
new file mode 100644
index 0000000..5a7e621
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_LOGIN_POD_PASSWORD_SMART_CARD_PIN_PLACEHOLDER.png.sha1
@@ -0,0 +1 @@
+c29aeb9b9a37e6d56634bc3c62093819ac29da9d
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_LOGIN_SMART_CARD_SIGN_IN_FAILURE_MESSAGE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_LOGIN_SMART_CARD_SIGN_IN_FAILURE_MESSAGE.png.sha1
new file mode 100644
index 0000000..9cdb1de38
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_LOGIN_SMART_CARD_SIGN_IN_FAILURE_MESSAGE.png.sha1
@@ -0,0 +1 @@
+c861ffeea450a04e09976aa3583b47b224a248c1
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_LOGIN_SMART_CARD_SIGN_IN_MESSAGE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_LOGIN_SMART_CARD_SIGN_IN_MESSAGE.png.sha1
new file mode 100644
index 0000000..f879d6f
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_LOGIN_SMART_CARD_SIGN_IN_MESSAGE.png.sha1
@@ -0,0 +1 @@
+ea11d470a9b22d0378b31cf3aab15e1c2e8d3f4c
\ No newline at end of file
diff --git a/ash/login/ui/lock_screen_media_controls_view.cc b/ash/login/ui/lock_screen_media_controls_view.cc
index 43b2398..a296126 100644
--- a/ash/login/ui/lock_screen_media_controls_view.cc
+++ b/ash/login/ui/lock_screen_media_controls_view.cc
@@ -19,12 +19,15 @@
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
+#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/message_center/message_center.h"
 #include "ui/message_center/vector_icons.h"
 #include "ui/views/background.h"
 #include "ui/views/controls/button/image_button_factory.h"
 #include "ui/views/controls/image_view.h"
+#include "ui/views/controls/label.h"
 #include "ui/views/layout/box_layout.h"
 
 namespace ash {
@@ -48,6 +51,8 @@
 constexpr int kMinimumArtworkSize = 50;
 constexpr int kDesiredArtworkSize = 80;
 constexpr gfx::Size kArtworkSize = gfx::Size(80, 80);
+constexpr int kArtworkRowSeparator = 10;
+constexpr gfx::Size kArtworkRowPreferredSize = gfx::Size(300, 10);
 constexpr gfx::Size kMediaButtonSize = gfx::Size(38, 38);
 constexpr int kMediaButtonRowSeparator = 24;
 constexpr gfx::Insets kButtonRowInsets = gfx::Insets(10, 0, 0, 0);
@@ -156,11 +161,54 @@
       std::make_unique<MediaControlsHeaderView>(base::BindOnce(
           &LockScreenMediaControlsView::Dismiss, base::Unretained(this))));
 
+  // |artwork_row| contains the session artwork, artist and track info.
+  auto artwork_row = std::make_unique<NonAccessibleView>();
+  artwork_row->SetPreferredSize(kArtworkRowPreferredSize);
+  auto* artwork_row_layout =
+      artwork_row->SetLayoutManager(std::make_unique<views::BoxLayout>(
+          views::BoxLayout::Orientation::kHorizontal, gfx::Insets(),
+          kArtworkRowSeparator));
+  artwork_row_layout->set_cross_axis_alignment(
+      views::BoxLayout::CrossAxisAlignment::kCenter);
+  artwork_row_layout->set_main_axis_alignment(
+      views::BoxLayout::MainAxisAlignment::kStart);
+
   auto session_artwork = std::make_unique<views::ImageView>();
   session_artwork->SetPreferredSize(kArtworkSize);
-  session_artwork->SetHorizontalAlignment(
-      views::ImageView::Alignment::kLeading);
-  session_artwork_ = contents_view_->AddChildView(std::move(session_artwork));
+  session_artwork_ = artwork_row->AddChildView(std::move(session_artwork));
+
+  // |track_column| contains the title and artist labels of the current media
+  // session.
+  auto track_column = std::make_unique<NonAccessibleView>();
+  auto* track_column_layout =
+      track_column->SetLayoutManager(std::make_unique<views::BoxLayout>(
+          views::BoxLayout::Orientation::kVertical));
+  track_column_layout->set_main_axis_alignment(
+      views::BoxLayout::MainAxisAlignment::kCenter);
+
+  const gfx::FontList& base_font_list = views::Label::GetDefaultFontList();
+
+  auto title_label = std::make_unique<views::Label>();
+  title_label->SetFontList(base_font_list.Derive(
+      2, gfx::Font::FontStyle::NORMAL, gfx::Font::Weight::BOLD));
+  title_label->SetEnabledColor(SK_ColorWHITE);
+  title_label->SetAutoColorReadabilityEnabled(false);
+  title_label->SetElideBehavior(gfx::ELIDE_TAIL);
+  title_label->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT);
+  title_label_ = track_column->AddChildView(std::move(title_label));
+
+  auto artist_label = std::make_unique<views::Label>();
+  artist_label->SetFontList(base_font_list.Derive(
+      0, gfx::Font::FontStyle::NORMAL, gfx::Font::Weight::LIGHT));
+  artist_label->SetEnabledColor(SK_ColorWHITE);
+  artist_label->SetAutoColorReadabilityEnabled(false);
+  artist_label->SetElideBehavior(gfx::ELIDE_TAIL);
+  artist_label->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT);
+  artist_label_ = track_column->AddChildView(std::move(artist_label));
+
+  artwork_row->AddChildView(std::move(track_column));
+
+  contents_view_->AddChildView(std::move(artwork_row));
 
   progress_ = contents_view_->AddChildView(
       std::make_unique<media_message_center::MediaControlsProgressView>(
@@ -340,6 +388,9 @@
           : session_metadata.source_title;
   header_row_->SetAppName(source_title);
 
+  title_label_->SetText(session_metadata.title);
+  artist_label_->SetText(session_metadata.artist);
+
   accessible_name_ =
       media_message_center::GetAccessibleNameFromMetadata(session_metadata);
 }
@@ -517,16 +568,19 @@
       media_message_center::GetTopVisibleActions(enabled_actions_,
                                                  ignored_actions, kMaxActions);
 
+  bool should_invalidate = false;
   for (auto* view : button_row_->children()) {
     views::Button* action_button = views::Button::AsButton(view);
     bool should_show = base::Contains(
         visible_actions,
         media_message_center::GetActionFromButtonTag(*action_button));
+    should_invalidate |= should_show != action_button->GetVisible();
 
     action_button->SetVisible(should_show);
   }
 
-  PreferredSizeChanged();
+  if (should_invalidate)
+    button_row_->InvalidateLayout();
 }
 
 void LockScreenMediaControlsView::SetIsPlaying(bool playing) {
diff --git a/ash/login/ui/lock_screen_media_controls_view.h b/ash/login/ui/lock_screen_media_controls_view.h
index 32ba818..630f7f7 100644
--- a/ash/login/ui/lock_screen_media_controls_view.h
+++ b/ash/login/ui/lock_screen_media_controls_view.h
@@ -20,6 +20,7 @@
 }
 
 namespace views {
+class Label;
 class ImageView;
 class ToggleImageButton;
 }  // namespace views
@@ -200,6 +201,8 @@
   // Container views attached to |contents_view_|.
   MediaControlsHeaderView* header_row_ = nullptr;
   views::ImageView* session_artwork_ = nullptr;
+  views::Label* title_label_ = nullptr;
+  views::Label* artist_label_ = nullptr;
   NonAccessibleView* button_row_ = nullptr;
   views::ToggleImageButton* play_pause_button_ = nullptr;
   media_message_center::MediaControlsProgressView* progress_ = nullptr;
diff --git a/ash/login/ui/lock_screen_media_controls_view_unittest.cc b/ash/login/ui/lock_screen_media_controls_view_unittest.cc
index 297ef3e..5078f15 100644
--- a/ash/login/ui/lock_screen_media_controls_view_unittest.cc
+++ b/ash/login/ui/lock_screen_media_controls_view_unittest.cc
@@ -21,6 +21,7 @@
 #include "ui/views/animation/bounds_animator.h"
 #include "ui/views/animation/bounds_animator_observer.h"
 #include "ui/views/controls/image_view.h"
+#include "ui/views/controls/label.h"
 
 namespace ash {
 
@@ -202,6 +203,14 @@
     return media_controls_view_->session_artwork_;
   }
 
+  views::Label* title_label() const {
+    return media_controls_view_->title_label_;
+  }
+
+  views::Label* artist_label() const {
+    return media_controls_view_->artist_label_;
+  }
+
   media_message_center::MediaControlsProgressView* progress_view() const {
     return media_controls_view_->progress_;
   }
@@ -237,18 +246,26 @@
 };
 
 TEST_F(LockScreenMediaControlsViewTest, DoNotUpdateMetadataBetweenSessions) {
-  // Set app name for current session
+  // Set metadata for current session
   media_session::MediaMetadata metadata;
   metadata.source_title = kTestAppName;
+  metadata.title = base::ASCIIToUTF16("title");
+  metadata.artist = base::ASCIIToUTF16("artist");
+
   media_controls_view_->MediaSessionMetadataChanged(metadata);
 
   // Simulate new media session starting.
   metadata.source_title = base::ASCIIToUTF16("AppName2");
+  metadata.title = base::ASCIIToUTF16("title2");
+  metadata.artist = base::ASCIIToUTF16("artist2");
+
   SimulateMediaSessionChanged(
       media_session::mojom::MediaPlaybackState::kPlaying);
   media_controls_view_->MediaSessionMetadataChanged(metadata);
 
   EXPECT_EQ(kTestAppName, GetAppName());
+  EXPECT_EQ(base::ASCIIToUTF16("title"), title_label()->GetText());
+  EXPECT_EQ(base::ASCIIToUTF16("artist"), artist_label()->GetText());
 }
 
 TEST_F(LockScreenMediaControlsViewTest, DoNotUpdateArtworkBetweenSessions) {
@@ -533,7 +550,7 @@
   EXPECT_EQ(kAppIconSize, icon_view()->GetImage().height());
 }
 
-TEST_F(LockScreenMediaControlsViewTest, UpdateAppName) {
+TEST_F(LockScreenMediaControlsViewTest, UpdateMetadata) {
   // Verify that the app name is initialized to the default.
   EXPECT_EQ(
       message_center::MessageCenter::Get()->GetSystemNotificationAppName(),
@@ -542,16 +559,21 @@
   media_session::MediaMetadata metadata;
   media_controls_view_->MediaSessionMetadataChanged(metadata);
 
-  // Verify that default name is used if no name is provided.
+  // Verify that default app name is used if no name is provided.
   EXPECT_EQ(
       message_center::MessageCenter::Get()->GetSystemNotificationAppName(),
       GetAppName());
 
   metadata.source_title = kTestAppName;
+  metadata.title = base::ASCIIToUTF16("title");
+  metadata.artist = base::ASCIIToUTF16("artist");
+
   media_controls_view_->MediaSessionMetadataChanged(metadata);
 
-  // Verify that the provided app name is used.
+  // Verify that the provided data is used.
   EXPECT_EQ(kTestAppName, GetAppName());
+  EXPECT_EQ(metadata.title, title_label()->GetText());
+  EXPECT_EQ(metadata.artist, artist_label()->GetText());
 }
 
 TEST_F(LockScreenMediaControlsViewTest, UpdateImagesConvertColors) {
diff --git a/ash/login/ui/login_auth_user_view.cc b/ash/login/ui/login_auth_user_view.cc
index 8013578c..e352e58 100644
--- a/ash/login/ui/login_auth_user_view.cc
+++ b/ash/login/ui/login_auth_user_view.cc
@@ -533,14 +533,14 @@
   }
 
   base::string16 GetTextForLabelButton() const {
-    // TODO(crbug.com/983103): Put localized strings after the string review.
     switch (state_) {
       case State::kInitial:
       case State::kAuthenticating:
-        return base::ASCIIToUTF16("Unlock with smart card");
+        return l10n_util::GetStringUTF16(
+            IDS_ASH_LOGIN_SMART_CARD_SIGN_IN_MESSAGE);
       case State::kFailure:
-        return base::UTF8ToUTF16(
-            "Couldn’t recognize your smart card. Try again.");
+        return l10n_util::GetStringUTF16(
+            IDS_ASH_LOGIN_SMART_CARD_SIGN_IN_FAILURE_MESSAGE);
     }
   }
 
@@ -948,8 +948,8 @@
   // Note: both |security_token_pin_request_| and |has_tap| must have higher
   // priority than |has_pin| when determining the placeholder.
   if (security_token_pin_request_) {
-    // TODO(crbug.com/983103): Put the localized string after the string review.
-    password_view_->SetPlaceholderText(base::UTF8ToUTF16("smart card PIN"));
+    password_view_->SetPlaceholderText(l10n_util::GetStringUTF16(
+        IDS_ASH_LOGIN_POD_PASSWORD_SMART_CARD_PIN_PLACEHOLDER));
   } else if (has_tap) {
     password_view_->SetPlaceholderText(
         l10n_util::GetStringUTF16(IDS_ASH_LOGIN_POD_PASSWORD_TAP_PLACEHOLDER));
diff --git a/ash/login/ui/media_controls_header_view.cc b/ash/login/ui/media_controls_header_view.cc
index bb98d2f..15cd7dd 100644
--- a/ash/login/ui/media_controls_header_view.cc
+++ b/ash/login/ui/media_controls_header_view.cc
@@ -30,16 +30,29 @@
 constexpr int kHeaderTextFontSize = 12;
 constexpr gfx::Insets kIconPadding = gfx::Insets(1, 1, 1, 1);
 constexpr gfx::Insets kAppNamePadding = gfx::Insets(0, 10, 0, 0);
+constexpr gfx::Size kAppNamePreferredSize = gfx::Size(200, 10);
 constexpr int kIconCornerRadius = 1;
 constexpr gfx::Size kCloseButtonSize = gfx::Size(20, 20);
 constexpr int kCloseButtonIconSize = 18;
-constexpr gfx::Size kSpacerPreferredSize = gfx::Size(10, 5);
+constexpr gfx::Size kSpacerPreferredSize = gfx::Size(5, 5);
 
 }  // namespace
 
 MediaControlsHeaderView::MediaControlsHeaderView(
     base::OnceClosure close_button_cb)
     : close_button_cb_(std::move(close_button_cb)) {
+  const views::FlexSpecification kAppNameFlex =
+      views::FlexSpecification::ForSizeRule(
+          views::MinimumFlexSizeRule::kScaleToZero,
+          views::MaximumFlexSizeRule::kPreferred)
+          .WithOrder(1);
+
+  const views::FlexSpecification kSpacerFlex =
+      views::FlexSpecification::ForSizeRule(
+          views::MinimumFlexSizeRule::kScaleToMinimum,
+          views::MaximumFlexSizeRule::kUnbounded)
+          .WithOrder(2);
+
   auto* layout = SetLayoutManager(std::make_unique<views::FlexLayout>());
   layout->SetInteriorMargin(kHeaderViewInsets);
 
@@ -65,15 +78,15 @@
   app_name_view->SetEnabledColor(SK_ColorWHITE);
   app_name_view->SetAutoColorReadabilityEnabled(false);
   app_name_view->SetBorder(views::CreateEmptyBorder(kAppNamePadding));
+  app_name_view->SetPreferredSize(kAppNamePreferredSize);
+  app_name_view->SetProperty(views::kFlexBehaviorKey, kAppNameFlex);
+  app_name_view->SetElideBehavior(gfx::ELIDE_TAIL);
   app_name_view_ = AddChildView(std::move(app_name_view));
 
   // Space between app name and close button.
   auto spacer = std::make_unique<NonAccessibleView>();
   spacer->SetPreferredSize(kSpacerPreferredSize);
-  spacer->SetProperty(views::kFlexBehaviorKey,
-                      views::FlexSpecification::ForSizeRule(
-                          views::MinimumFlexSizeRule::kScaleToMinimum,
-                          views::MaximumFlexSizeRule::kUnbounded));
+  spacer->SetProperty(views::kFlexBehaviorKey, kSpacerFlex);
   AddChildView(std::move(spacer));
 
   auto close_button = CreateVectorImageButton(this);
diff --git a/ash/public/cpp/session/session_controller.h b/ash/public/cpp/session/session_controller.h
index f9386c8..bf5fc61 100644
--- a/ash/public/cpp/session/session_controller.h
+++ b/ash/public/cpp/session/session_controller.h
@@ -77,9 +77,6 @@
   // Adds a countdown timer to the system tray menu and creates or updates a
   // notification saying the session length is limited (e.g. a public session in
   // a library). Setting |length_limit| to zero removes the notification.
-  // NOTE: Chrome enforces the limit, not ash. Ash could enforce it if local
-  // state prefs and user activity monitoring were available under mustash.
-  // http://crbug.com/729808
   virtual void SetSessionLengthLimit(base::TimeDelta length_limit,
                                      base::TimeTicks start_time) = 0;
 
diff --git a/ash/style/default_color_constants.h b/ash/style/default_color_constants.h
index 32fe744..f211dae 100644
--- a/ash/style/default_color_constants.h
+++ b/ash/style/default_color_constants.h
@@ -25,6 +25,8 @@
     SkColorSetA(SK_ColorBLACK, 0x23);  // 14%
 constexpr SkColor kSeparatorOnDarkBackgroundColor =
     SkColorSetA(SK_ColorWHITE, 0x23);  // 14%
+
+constexpr SkColor kNotificationBackgroundColor = SK_ColorWHITE;
 //----------------------------------End----------------------------------------
 
 #endif  // ASH_STYLE_DEFAULT_COLOR_CONSTANTS_H_
diff --git a/ash/system/audio/unified_volume_view.cc b/ash/system/audio/unified_volume_view.cc
index 03e9005..de6a30b 100644
--- a/ash/system/audio/unified_volume_view.cc
+++ b/ash/system/audio/unified_volume_view.cc
@@ -9,6 +9,7 @@
 #include "ash/system/audio/unified_volume_slider_controller.h"
 #include "ash/system/tray/tray_constants.h"
 #include "ash/system/tray/tray_popup_utils.h"
+#include "ash/system/unified/unified_system_tray_view.h"
 #include "base/i18n/rtl.h"
 #include "base/stl_util.h"
 #include "components/vector_icons/vector_icons.h"
@@ -110,13 +111,15 @@
   std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override {
     return TrayPopupUtils::CreateInkDropRipple(
         TrayPopupInkDropStyle::FILL_BOUNDS, this,
-        GetInkDropCenterBasedOnLastEvent(), kIconOnDarkBackgroundColor);
+        GetInkDropCenterBasedOnLastEvent(),
+        UnifiedSystemTrayView::GetBackgroundColor());
   }
 
   std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight()
       const override {
     return TrayPopupUtils::CreateInkDropHighlight(
-        TrayPopupInkDropStyle::FILL_BOUNDS, this, kIconOnDarkBackgroundColor);
+        TrayPopupInkDropStyle::FILL_BOUNDS, this,
+        UnifiedSystemTrayView::GetBackgroundColor());
   }
 
   std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override {
diff --git a/ash/system/message_center/unified_message_center_view.cc b/ash/system/message_center/unified_message_center_view.cc
index ac83bdd..1b5ed74 100644
--- a/ash/system/message_center/unified_message_center_view.cc
+++ b/ash/system/message_center/unified_message_center_view.cc
@@ -27,7 +27,6 @@
 #include "ui/gfx/animation/linear_animation.h"
 #include "ui/gfx/canvas.h"
 #include "ui/message_center/message_center.h"
-#include "ui/message_center/public/cpp/message_center_constants.h"
 #include "ui/message_center/views/message_view.h"
 #include "ui/views/animation/flood_fill_ink_drop_ripple.h"
 #include "ui/views/animation/ink_drop_highlight.h"
@@ -91,6 +90,10 @@
     label()->SetFontList(views::Label::GetDefaultFontList().Derive(
         1, gfx::Font::NORMAL, gfx::Font::Weight::MEDIUM));
     TrayPopupUtils::ConfigureTrayPopupButton(this);
+
+    background_color_ = AshColorProvider::Get()->DeprecatedGetBaseLayerColor(
+        AshColorProvider::BaseLayerType::kTransparentWithoutBlur,
+        kNotificationBackgroundColor);
   }
 
   ~StackingBarClearAllButton() override = default;
@@ -126,13 +129,13 @@
   std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override {
     return TrayPopupUtils::CreateInkDropRipple(
         TrayPopupInkDropStyle::FILL_BOUNDS, this,
-        GetInkDropCenterBasedOnLastEvent(), SK_ColorBLACK);
+        GetInkDropCenterBasedOnLastEvent(), background_color_);
   }
 
   std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight()
       const override {
     return TrayPopupUtils::CreateInkDropHighlight(
-        TrayPopupInkDropStyle::FILL_BOUNDS, this, SK_ColorBLACK);
+        TrayPopupInkDropStyle::FILL_BOUNDS, this, background_color_);
   }
 
   std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override {
@@ -152,6 +155,8 @@
   }
 
  private:
+  SkColor background_color_ = gfx::kPlaceholderColor;
+
   DISALLOW_COPY_AND_ASSIGN(StackingBarClearAllButton);
 };
 
@@ -227,7 +232,9 @@
 
 void StackingNotificationCounterView::OnPaint(gfx::Canvas* canvas) {
   cc::PaintFlags flags;
-  flags.setColor(message_center::kNotificationBackgroundColor);
+  flags.setColor(AshColorProvider::Get()->DeprecatedGetBaseLayerColor(
+      AshColorProvider::BaseLayerType::kTransparentWithoutBlur,
+      kNotificationBackgroundColor));
   flags.setStyle(cc::PaintFlags::kFill_Style);
   flags.setAntiAlias(true);
 
diff --git a/ash/system/network/vpn_list_view.cc b/ash/system/network/vpn_list_view.cc
index b499ae40..35b4475dd1 100644
--- a/ash/system/network/vpn_list_view.cc
+++ b/ash/system/network/vpn_list_view.cc
@@ -26,6 +26,7 @@
 #include "ash/system/tray/tray_popup_utils.h"
 #include "ash/system/tray/tri_view.h"
 #include "ash/system/tray/view_click_listener.h"
+#include "ash/system/unified/unified_system_tray_view.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chromeos/network/network_connect.h"
 #include "chromeos/services/network_config/public/cpp/cros_network_config_util.h"
@@ -127,7 +128,8 @@
         gfx::CreateVectorIcon(kSystemMenuAddConnectionIcon, image_color);
     SystemMenuButton* add_vpn_button =
         new SystemMenuButton(this, icon, icon, button_accessible_name_id);
-    add_vpn_button->SetInkDropColor(image_color);
+    add_vpn_button->SetInkDropColor(
+        UnifiedSystemTrayView::GetBackgroundColor());
     add_vpn_button->SetEnabled(true);
     tri_view->AddView(TriView::Container::END, add_vpn_button);
   }
diff --git a/ash/system/tray/actionable_view.cc b/ash/system/tray/actionable_view.cc
index 7da908d..803e7fe 100644
--- a/ash/system/tray/actionable_view.cc
+++ b/ash/system/tray/actionable_view.cc
@@ -4,8 +4,6 @@
 
 #include "ash/system/tray/actionable_view.h"
 
-#include "ash/public/cpp/ash_constants.h"
-#include "ash/system/tray/tray_constants.h"
 #include "ash/system/tray/tray_popup_utils.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/events/keycodes/keyboard_codes.h"
@@ -28,8 +26,6 @@
       destroyed_(nullptr),
       ink_drop_style_(ink_drop_style) {
   SetFocusBehavior(FocusBehavior::ALWAYS);
-  set_ink_drop_base_color(kTrayPopupInkDropBaseColor);
-  set_ink_drop_visible_opacity(kTrayPopupInkDropRippleOpacity);
   set_has_ink_drop_action_on_click(false);
   set_notify_enter_exit_on_child(true);
   SetFocusPainter(TrayPopupUtils::CreateFocusPainter());
@@ -77,13 +73,18 @@
 
 std::unique_ptr<views::InkDropRipple> ActionableView::CreateInkDropRipple()
     const {
+  // TODO(minch): Do not hard code the background color. Add it as a constructor
+  // argument to ActionableView.
   return TrayPopupUtils::CreateInkDropRipple(
-      ink_drop_style_, this, GetInkDropCenterBasedOnLastEvent());
+      ink_drop_style_, this, GetInkDropCenterBasedOnLastEvent(), SK_ColorWHITE);
 }
 
 std::unique_ptr<views::InkDropHighlight>
 ActionableView::CreateInkDropHighlight() const {
-  return TrayPopupUtils::CreateInkDropHighlight(ink_drop_style_, this);
+  // TODO(minch): Do not hard code the background color. Add it as a constructor
+  // argument to ActionableView.
+  return TrayPopupUtils::CreateInkDropHighlight(ink_drop_style_, this,
+                                                SK_ColorWHITE);
 }
 
 void ActionableView::ButtonPressed(Button* sender, const ui::Event& event) {
diff --git a/ash/system/tray/system_menu_button.cc b/ash/system/tray/system_menu_button.cc
index ecd0d7a..d0eb83c 100644
--- a/ash/system/tray/system_menu_button.cc
+++ b/ash/system/tray/system_menu_button.cc
@@ -4,8 +4,6 @@
 
 #include "ash/system/tray/system_menu_button.h"
 
-#include "ash/public/cpp/ash_constants.h"
-#include "ash/public/cpp/ash_features.h"
 #include "ash/system/tray/tray_constants.h"
 #include "ash/system/tray/tray_popup_ink_drop_style.h"
 #include "ash/system/tray/tray_popup_utils.h"
@@ -14,9 +12,6 @@
 #include "ui/views/animation/flood_fill_ink_drop_ripple.h"
 #include "ui/views/animation/ink_drop_highlight.h"
 #include "ui/views/animation/ink_drop_impl.h"
-#include "ui/views/animation/ink_drop_mask.h"
-#include "ui/views/animation/square_ink_drop_ripple.h"
-#include "ui/views/painter.h"
 #include "ui/views/view_class_properties.h"
 
 namespace ash {
@@ -76,19 +71,22 @@
   return TrayPopupUtils::CreateInkDrop(this);
 }
 
+// TODO(minch): Do not hard code the background color for InkDropRipple and
+// InkDropHighlight. Add it as a constructor argument to SystemMenuButton.
+// Then, |ink_drop_color_| related logic can be removed.
 std::unique_ptr<views::InkDropRipple> SystemMenuButton::CreateInkDropRipple()
     const {
   return TrayPopupUtils::CreateInkDropRipple(
       TrayPopupInkDropStyle::HOST_CENTERED, this,
       GetInkDropCenterBasedOnLastEvent(),
-      ink_drop_color_.value_or(kTrayPopupInkDropBaseColor));
+      ink_drop_color_.value_or(SK_ColorWHITE));
 }
 
 std::unique_ptr<views::InkDropHighlight>
 SystemMenuButton::CreateInkDropHighlight() const {
   return TrayPopupUtils::CreateInkDropHighlight(
       TrayPopupInkDropStyle::HOST_CENTERED, this,
-      ink_drop_color_.value_or(kTrayPopupInkDropBaseColor));
+      ink_drop_color_.value_or(SK_ColorWHITE));
 }
 
 const char* SystemMenuButton::GetClassName() const {
diff --git a/ash/system/tray/tray_background_view.cc b/ash/system/tray/tray_background_view.cc
index 72305fc..12fd5eff 100644
--- a/ash/system/tray/tray_background_view.cc
+++ b/ash/system/tray/tray_background_view.cc
@@ -17,6 +17,7 @@
 #include "ash/shelf/shelf_layout_manager.h"
 #include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
+#include "ash/style/ash_color_provider.h"
 #include "ash/system/model/system_tray_model.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/system/status_area_widget_delegate.h"
@@ -293,9 +294,13 @@
 
 std::unique_ptr<views::InkDropRipple> TrayBackgroundView::CreateInkDropRipple()
     const {
+  // TODO(minch): Do not hard code the color, get the background color of shelf
+  // instead.
+  const AshColorProvider::RippleAttributes ripple_attributes =
+      AshColorProvider::Get()->GetRippleAttributes(SK_ColorBLACK);
   return std::make_unique<views::FloodFillInkDropRipple>(
       size(), GetBackgroundInsets(), GetInkDropCenterBasedOnLastEvent(),
-      GetInkDropBaseColor(), ink_drop_visible_opacity());
+      ripple_attributes.base_color, ripple_attributes.inkdrop_opacity);
 }
 
 std::unique_ptr<views::InkDropHighlight>
@@ -310,11 +315,15 @@
   const int icon_size = kTrayIconSize + 2 * kTrayImageItemPadding;
   bounds.set_width(bounds.width() + 2 * icon_size);
   bounds.set_height(bounds.height() + 2 * icon_size);
+  // TODO(minch): Do not hard code the color, get the background color of shelf
+  // instead.
+  const AshColorProvider::RippleAttributes ripple_attributes =
+      AshColorProvider::Get()->GetRippleAttributes(SK_ColorBLACK);
   std::unique_ptr<views::InkDropHighlight> highlight(
       new views::InkDropHighlight(bounds.size(), 0,
                                   gfx::RectF(bounds).CenterPoint(),
-                                  GetInkDropBaseColor()));
-  highlight->set_visible_opacity(kTrayPopupInkDropHighlightOpacity);
+                                  ripple_attributes.base_color));
+  highlight->set_visible_opacity(ripple_attributes.highlight_opacity);
   return highlight;
 }
 
@@ -475,5 +484,4 @@
   return insets;
 }
 
-
 }  // namespace ash
diff --git a/ash/system/tray/tray_constants.cc b/ash/system/tray/tray_constants.cc
index 8f35a1a5..5557ea8e 100644
--- a/ash/system/tray/tray_constants.cc
+++ b/ash/system/tray/tray_constants.cc
@@ -47,9 +47,6 @@
 const int kHitRegionPadding = 4;
 const int kHitRegionPaddingDense = 2;
 
-const SkColor kTrayPopupInkDropBaseColor = SK_ColorBLACK;
-const float kTrayPopupInkDropRippleOpacity = 0.06f;
-const float kTrayPopupInkDropHighlightOpacity = 0.08f;
 const int kTrayPopupInkDropInset = 4;
 const int kTrayPopupInkDropCornerRadius = 2;
 
diff --git a/ash/system/tray/tray_constants.h b/ash/system/tray/tray_constants.h
index 8ea7572e..3901a2f 100644
--- a/ash/system/tray/tray_constants.h
+++ b/ash/system/tray/tray_constants.h
@@ -104,16 +104,6 @@
 // The visual padding to the left of icons in the system menu.
 extern const int kMenuEdgeEffectivePadding;
 
-// The base color used for all ink drops in the system menu.
-extern const SkColor kTrayPopupInkDropBaseColor;
-
-// The opacity of the ink drop ripples for all ink drops in the system menu.
-extern const float kTrayPopupInkDropRippleOpacity;
-
-// The opacity of the ink drop ripples for all ink highlights in the system
-// menu.
-extern const float kTrayPopupInkDropHighlightOpacity;
-
 // The inset applied to clickable surfaces in the system menu that do not have
 // the ink drop filling the entire bounds.
 extern const int kTrayPopupInkDropInset;
@@ -133,8 +123,6 @@
     SkColorSetRGB(0x25, 0x81, 0xdf);
 constexpr SkColor kUnifiedMenuButtonColorDisabled =
     SkColorSetA(kUnifiedMenuButtonColor, 0xa);
-constexpr SkColor kUnifiedFeaturePodHoverColor =
-    SkColorSetRGB(0xff, 0xff, 0xff);
 constexpr SkColor kUnifiedRecordingIconColor = gfx::kGoogleRed300;
 
 constexpr gfx::Insets kUnifiedMenuItemPadding(0, 16, 16, 16);
diff --git a/ash/system/tray/tray_popup_utils.cc b/ash/system/tray/tray_popup_utils.cc
index 797c7a1..cd179c36 100644
--- a/ash/system/tray/tray_popup_utils.cc
+++ b/ash/system/tray/tray_popup_utils.cc
@@ -198,12 +198,8 @@
 void TrayPopupUtils::ConfigureTrayPopupButton(views::Button* button) {
   button->SetInstallFocusRingOnFocus(true);
   button->SetFocusForPlatform();
-
   button->SetInkDropMode(views::InkDropHostView::InkDropMode::ON);
   button->set_has_ink_drop_action_on_click(true);
-  button->set_ink_drop_base_color(kTrayPopupInkDropBaseColor);
-  button->set_ink_drop_visible_opacity(kTrayPopupInkDropRippleOpacity);
-  button->set_ink_drop_highlight_opacity(kTrayPopupInkDropHighlightOpacity);
 }
 
 void TrayPopupUtils::ConfigureAsStickyHeader(views::View* view) {
@@ -251,22 +247,28 @@
     TrayPopupInkDropStyle ink_drop_style,
     const views::View* host,
     const gfx::Point& center_point,
-    SkColor color) {
+    SkColor background_color) {
+  const AshColorProvider::RippleAttributes ripple_attributes =
+      AshColorProvider::Get()->GetRippleAttributes(background_color);
   return std::make_unique<views::FloodFillInkDropRipple>(
       host->size(), TrayPopupUtils::GetInkDropInsets(ink_drop_style),
-      center_point, color, kTrayPopupInkDropRippleOpacity);
+      center_point, ripple_attributes.base_color,
+      ripple_attributes.inkdrop_opacity);
 }
 
 std::unique_ptr<views::InkDropHighlight> TrayPopupUtils::CreateInkDropHighlight(
     TrayPopupInkDropStyle ink_drop_style,
     const views::View* host,
-    SkColor color) {
+    SkColor background_color) {
+  const AshColorProvider::RippleAttributes ripple_attributes =
+      AshColorProvider::Get()->GetRippleAttributes(background_color);
   const gfx::Rect bounds =
       TrayPopupUtils::GetInkDropBounds(ink_drop_style, host);
   std::unique_ptr<views::InkDropHighlight> highlight(
       new views::InkDropHighlight(bounds.size(), 0,
-                                  gfx::PointF(bounds.CenterPoint()), color));
-  highlight->set_visible_opacity(kTrayPopupInkDropHighlightOpacity);
+                                  gfx::PointF(bounds.CenterPoint()),
+                                  ripple_attributes.base_color));
+  highlight->set_visible_opacity(ripple_attributes.highlight_opacity);
   return highlight;
 }
 
diff --git a/ash/system/tray/tray_popup_utils.h b/ash/system/tray/tray_popup_utils.h
index 06ee842..b6337fa 100644
--- a/ash/system/tray/tray_popup_utils.h
+++ b/ash/system/tray/tray_popup_utils.h
@@ -154,7 +154,7 @@
       TrayPopupInkDropStyle ink_drop_style,
       const views::View* host,
       const gfx::Point& center_point,
-      SkColor color = kTrayPopupInkDropBaseColor);
+      SkColor background_color);
 
   // Creates in InkDropHighlight instance for |host| according to the
   // |ink_drop_style|.
@@ -164,7 +164,7 @@
   static std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight(
       TrayPopupInkDropStyle ink_drop_style,
       const views::View* host,
-      SkColor color = kTrayPopupInkDropBaseColor);
+      SkColor background_color);
 
   // Creates a SkPath matching the TrayPopupInkDropStyle. This path is normally
   // used to generate the focus ring and ink drop shapes.
diff --git a/ash/system/unified/custom_shape_button.cc b/ash/system/unified/custom_shape_button.cc
index f0687af..3054f56 100644
--- a/ash/system/unified/custom_shape_button.cc
+++ b/ash/system/unified/custom_shape_button.cc
@@ -6,6 +6,7 @@
 
 #include "ash/system/tray/tray_constants.h"
 #include "ash/system/tray/tray_popup_utils.h"
+#include "ash/system/unified/unified_system_tray_view.h"
 #include "ui/compositor/paint_recorder.h"
 #include "ui/gfx/image/image_skia_operations.h"
 #include "ui/gfx/skbitmap_operations.h"
@@ -71,13 +72,15 @@
     const {
   return TrayPopupUtils::CreateInkDropRipple(
       TrayPopupInkDropStyle::FILL_BOUNDS, this,
-      GetInkDropCenterBasedOnLastEvent(), kIconOnDarkBackgroundColor);
+      GetInkDropCenterBasedOnLastEvent(),
+      UnifiedSystemTrayView::GetBackgroundColor());
 }
 
 std::unique_ptr<views::InkDropHighlight>
 CustomShapeButton::CreateInkDropHighlight() const {
   return TrayPopupUtils::CreateInkDropHighlight(
-      TrayPopupInkDropStyle::FILL_BOUNDS, this, kIconOnDarkBackgroundColor);
+      TrayPopupInkDropStyle::FILL_BOUNDS, this,
+      UnifiedSystemTrayView::GetBackgroundColor());
 }
 
 std::unique_ptr<views::InkDropMask> CustomShapeButton::CreateInkDropMask()
diff --git a/ash/system/unified/feature_pod_button.cc b/ash/system/unified/feature_pod_button.cc
index c6b292c..c617ac2 100644
--- a/ash/system/unified/feature_pod_button.cc
+++ b/ash/system/unified/feature_pod_button.cc
@@ -9,6 +9,7 @@
 #include "ash/system/tray/tray_constants.h"
 #include "ash/system/tray/tray_popup_utils.h"
 #include "ash/system/unified/feature_pod_controller_base.h"
+#include "ash/system/unified/unified_system_tray_view.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/canvas.h"
@@ -83,13 +84,15 @@
 FeaturePodIconButton::CreateInkDropRipple() const {
   return TrayPopupUtils::CreateInkDropRipple(
       TrayPopupInkDropStyle::FILL_BOUNDS, this,
-      GetInkDropCenterBasedOnLastEvent(), kIconOnDarkBackgroundColor);
+      GetInkDropCenterBasedOnLastEvent(),
+      UnifiedSystemTrayView::GetBackgroundColor());
 }
 
 std::unique_ptr<views::InkDropHighlight>
 FeaturePodIconButton::CreateInkDropHighlight() const {
   return TrayPopupUtils::CreateInkDropHighlight(
-      TrayPopupInkDropStyle::FILL_BOUNDS, this, kIconOnDarkBackgroundColor);
+      TrayPopupInkDropStyle::FILL_BOUNDS, this,
+      UnifiedSystemTrayView::GetBackgroundColor());
 }
 
 std::unique_ptr<views::InkDropMask> FeaturePodIconButton::CreateInkDropMask()
@@ -189,13 +192,15 @@
 FeaturePodLabelButton::CreateInkDropRipple() const {
   return TrayPopupUtils::CreateInkDropRipple(
       TrayPopupInkDropStyle::FILL_BOUNDS, this,
-      GetInkDropCenterBasedOnLastEvent(), kUnifiedFeaturePodHoverColor);
+      GetInkDropCenterBasedOnLastEvent(),
+      UnifiedSystemTrayView::GetBackgroundColor());
 }
 
 std::unique_ptr<views::InkDropHighlight>
 FeaturePodLabelButton::CreateInkDropHighlight() const {
   return TrayPopupUtils::CreateInkDropHighlight(
-      TrayPopupInkDropStyle::FILL_BOUNDS, this, kUnifiedFeaturePodHoverColor);
+      TrayPopupInkDropStyle::FILL_BOUNDS, this,
+      UnifiedSystemTrayView::GetBackgroundColor());
 }
 
 std::unique_ptr<views::InkDropMask> FeaturePodLabelButton::CreateInkDropMask()
diff --git a/ash/system/unified/feature_pod_button.h b/ash/system/unified/feature_pod_button.h
index 92da75a..d4b8ce6 100644
--- a/ash/system/unified/feature_pod_button.h
+++ b/ash/system/unified/feature_pod_button.h
@@ -48,7 +48,7 @@
   DISALLOW_COPY_AND_ASSIGN(FeaturePodIconButton);
 };
 
-// Buton internally used in FeaturePodButton. Should not be used directly.
+// Button internally used in FeaturePodButton. Should not be used directly.
 class FeaturePodLabelButton : public views::Button {
  public:
   explicit FeaturePodLabelButton(views::ButtonListener* listener);
diff --git a/ash/system/unified/rounded_label_button.cc b/ash/system/unified/rounded_label_button.cc
index ea77543..cd97c75 100644
--- a/ash/system/unified/rounded_label_button.cc
+++ b/ash/system/unified/rounded_label_button.cc
@@ -6,6 +6,7 @@
 
 #include "ash/system/tray/tray_constants.h"
 #include "ash/system/tray/tray_popup_utils.h"
+#include "ash/system/unified/unified_system_tray_view.h"
 #include "ui/gfx/canvas.h"
 #include "ui/views/animation/ink_drop.h"
 #include "ui/views/animation/ink_drop_highlight.h"
@@ -63,13 +64,15 @@
     const {
   return TrayPopupUtils::CreateInkDropRipple(
       TrayPopupInkDropStyle::FILL_BOUNDS, this,
-      GetInkDropCenterBasedOnLastEvent(), kIconOnDarkBackgroundColor);
+      GetInkDropCenterBasedOnLastEvent(),
+      UnifiedSystemTrayView::GetBackgroundColor());
 }
 
 std::unique_ptr<views::InkDropHighlight>
 RoundedLabelButton::CreateInkDropHighlight() const {
   return TrayPopupUtils::CreateInkDropHighlight(
-      TrayPopupInkDropStyle::FILL_BOUNDS, this, kIconOnDarkBackgroundColor);
+      TrayPopupInkDropStyle::FILL_BOUNDS, this,
+      UnifiedSystemTrayView::GetBackgroundColor());
 }
 
 std::unique_ptr<views::InkDropMask> RoundedLabelButton::CreateInkDropMask()
diff --git a/ash/system/unified/top_shortcut_button.cc b/ash/system/unified/top_shortcut_button.cc
index 6ef800b..863a482d 100644
--- a/ash/system/unified/top_shortcut_button.cc
+++ b/ash/system/unified/top_shortcut_button.cc
@@ -6,6 +6,7 @@
 
 #include "ash/system/tray/tray_constants.h"
 #include "ash/system/tray/tray_popup_utils.h"
+#include "ash/system/unified/unified_system_tray_view.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/paint_vector_icon.h"
@@ -47,7 +48,6 @@
     SetTooltipText(l10n_util::GetStringUTF16(accessible_name_id));
 
   TrayPopupUtils::ConfigureTrayPopupButton(this);
-  set_ink_drop_base_color(kIconOnDarkBackgroundColor);
 
   auto path = std::make_unique<SkPath>();
   path->addOval(gfx::RectToSkRect(gfx::Rect(CalculatePreferredSize())));
@@ -74,6 +74,21 @@
   return TrayPopupUtils::CreateInkDrop(this);
 }
 
+std::unique_ptr<views::InkDropRipple> TopShortcutButton::CreateInkDropRipple()
+    const {
+  return TrayPopupUtils::CreateInkDropRipple(
+      TrayPopupInkDropStyle::FILL_BOUNDS, this,
+      GetInkDropCenterBasedOnLastEvent(),
+      UnifiedSystemTrayView::GetBackgroundColor());
+}
+
+std::unique_ptr<views::InkDropHighlight>
+TopShortcutButton::CreateInkDropHighlight() const {
+  return TrayPopupUtils::CreateInkDropHighlight(
+      TrayPopupInkDropStyle::FILL_BOUNDS, this,
+      UnifiedSystemTrayView::GetBackgroundColor());
+}
+
 const char* TopShortcutButton::GetClassName() const {
   return "TopShortcutButton";
 }
diff --git a/ash/system/unified/top_shortcut_button.h b/ash/system/unified/top_shortcut_button.h
index f29b4e12..f0382a2 100644
--- a/ash/system/unified/top_shortcut_button.h
+++ b/ash/system/unified/top_shortcut_button.h
@@ -29,6 +29,9 @@
   // views::ImageButton:
   void PaintButtonContents(gfx::Canvas* canvas) override;
   std::unique_ptr<views::InkDrop> CreateInkDrop() override;
+  std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override;
+  std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight()
+      const override;
   const char* GetClassName() const override;
 
  private:
diff --git a/ash/system/unified/unified_system_tray_view.cc b/ash/system/unified/unified_system_tray_view.cc
index df0aef7d..cea8ad3 100644
--- a/ash/system/unified/unified_system_tray_view.cc
+++ b/ash/system/unified/unified_system_tray_view.cc
@@ -230,6 +230,25 @@
   DISALLOW_COPY_AND_ASSIGN(FocusSearch);
 };
 
+// static
+SkColor UnifiedSystemTrayView::GetBackgroundColor() {
+  if (app_list_features::IsBackgroundBlurEnabled()) {
+    return AshColorProvider::Get()->DeprecatedGetBaseLayerColor(
+        AshColorProvider::BaseLayerType::kTransparentWithBlur,
+        kUnifiedMenuBackgroundColorWithBlur);
+  }
+  return AshColorProvider::Get()->DeprecatedGetBaseLayerColor(
+      AshColorProvider::BaseLayerType::kTransparentWithoutBlur,
+      kUnifiedMenuBackgroundColor);
+}
+
+// static
+std::unique_ptr<views::Background> UnifiedSystemTrayView::CreateBackground() {
+  return views::CreateBackgroundFromPainter(
+      views::Painter::CreateSolidRoundRectPainter(GetBackgroundColor(),
+                                                  kUnifiedTrayCornerRadius));
+}
+
 UnifiedSystemTrayView::UnifiedSystemTrayView(
     UnifiedSystemTrayController* controller,
     bool initially_expanded)
@@ -449,23 +468,6 @@
   return feature_pods_container_->GetVisibleCount();
 }
 
-// static
-std::unique_ptr<views::Background> UnifiedSystemTrayView::CreateBackground() {
-  SkColor bg_color = gfx::kPlaceholderColor;
-  if (app_list_features::IsBackgroundBlurEnabled()) {
-    bg_color = AshColorProvider::Get()->DeprecatedGetBaseLayerColor(
-        AshColorProvider::BaseLayerType::kTransparentWithBlur,
-        kUnifiedMenuBackgroundColorWithBlur);
-  } else {
-    bg_color = AshColorProvider::Get()->DeprecatedGetBaseLayerColor(
-        AshColorProvider::BaseLayerType::kTransparentWithoutBlur,
-        kUnifiedMenuBackgroundColor);
-  }
-  return views::CreateBackgroundFromPainter(
-      views::Painter::CreateSolidRoundRectPainter(bg_color,
-                                                  kUnifiedTrayCornerRadius));
-}
-
 void UnifiedSystemTrayView::OnGestureEvent(ui::GestureEvent* event) {
   gfx::Point screen_location = event->location();
   ConvertPointToScreen(this, &screen_location);
diff --git a/ash/system/unified/unified_system_tray_view.h b/ash/system/unified/unified_system_tray_view.h
index 112bfb9..a07a42e 100644
--- a/ash/system/unified/unified_system_tray_view.h
+++ b/ash/system/unified/unified_system_tray_view.h
@@ -60,6 +60,12 @@
 class ASH_EXPORT UnifiedSystemTrayView : public views::View,
                                          public views::FocusTraversable {
  public:
+  // Get the background color of unified system tray.
+  static SkColor GetBackgroundColor();
+
+  // Create background of UnifiedSystemTray with rounded corners.
+  static std::unique_ptr<views::Background> CreateBackground();
+
   UnifiedSystemTrayView(UnifiedSystemTrayController* controller,
                         bool initially_expanded);
   ~UnifiedSystemTrayView() override;
@@ -119,10 +125,6 @@
   // Returns the number of visible feature pods.
   int GetVisibleFeaturePodCount() const;
 
-  // Create background of UnifiedSystemTray that is semi-transparent and has
-  // rounded corners.
-  static std::unique_ptr<views::Background> CreateBackground();
-
   // views::View:
   void OnGestureEvent(ui::GestureEvent* event) override;
   void ChildPreferredSizeChanged(views::View* child) override;
diff --git a/ash/wm/overview/overview_grid.h b/ash/wm/overview/overview_grid.h
index c7c8dad..3d55a15e 100644
--- a/ash/wm/overview/overview_grid.h
+++ b/ash/wm/overview/overview_grid.h
@@ -304,6 +304,10 @@
 
   views::Widget* drop_target_widget() { return drop_target_widget_.get(); }
 
+  OverviewGridPreEventHandler* grid_pre_event_handler() {
+    return grid_pre_event_handler_.get();
+  }
+
  private:
   class TargetWindowObserver;
   friend class OverviewSessionTest;
diff --git a/ash/wm/overview/overview_grid_pre_event_handler.h b/ash/wm/overview/overview_grid_pre_event_handler.h
index 6a42b90..d6cb178d 100644
--- a/ash/wm/overview/overview_grid_pre_event_handler.h
+++ b/ash/wm/overview/overview_grid_pre_event_handler.h
@@ -28,11 +28,11 @@
   explicit OverviewGridPreEventHandler(OverviewGrid* grid);
   ~OverviewGridPreEventHandler() override;
 
- private:
   // ui::EventHandler:
   void OnMouseEvent(ui::MouseEvent* event) override;
   void OnGestureEvent(ui::GestureEvent* event) override;
 
+ private:
   void HandleClickOrTap(ui::Event* event);
 
   // Cached value of the OverviewGrid that handles a series of gesture scroll
diff --git a/ash/wm/overview/overview_item.cc b/ash/wm/overview/overview_item.cc
index 56246964..fc01c4d6 100644
--- a/ash/wm/overview/overview_item.cc
+++ b/ash/wm/overview/overview_item.cc
@@ -21,6 +21,7 @@
 #include "ash/wm/overview/overview_constants.h"
 #include "ash/wm/overview/overview_controller.h"
 #include "ash/wm/overview/overview_grid.h"
+#include "ash/wm/overview/overview_grid_pre_event_handler.h"
 #include "ash/wm/overview/overview_highlight_controller.h"
 #include "ash/wm/overview/overview_utils.h"
 #include "ash/wm/overview/overview_window_drag_controller.h"
@@ -812,6 +813,10 @@
 }
 
 void OverviewItem::HandleGestureEvent(ui::GestureEvent* event) {
+  if (ShouldUseTabletModeGridLayout()) {
+    HandleGestureEventForTabletModeLayout(event);
+    return;
+  }
   const gfx::PointF location = event->details().bounding_box_f().CenterPoint();
   switch (event->type()) {
     case ui::ET_GESTURE_TAP_DOWN:
@@ -841,6 +846,41 @@
   }
 }
 
+void OverviewItem::HandleGestureEventForTabletModeLayout(
+    ui::GestureEvent* event) {
+  const gfx::PointF location = event->details().bounding_box_f().CenterPoint();
+  switch (event->type()) {
+    case ui::ET_GESTURE_SCROLL_UPDATE:
+      if (IsDragItem())
+        HandleDragEvent(location);
+      else
+        overview_grid()->grid_pre_event_handler()->OnGestureEvent(event);
+      break;
+    case ui::ET_SCROLL_FLING_START:
+      HandleFlingStartEvent(location, event->details().velocity_x(),
+                            event->details().velocity_y());
+      break;
+    case ui::ET_GESTURE_SCROLL_END:
+      if (IsDragItem())
+        HandleReleaseEvent(location);
+      else
+        overview_grid()->grid_pre_event_handler()->OnGestureEvent(event);
+      break;
+    case ui::ET_GESTURE_LONG_PRESS:
+      HandlePressEvent(location, /*from_touch_gesture=*/true);
+      break;
+    case ui::ET_GESTURE_TAP:
+      overview_session_->SelectWindow(this);
+      break;
+    case ui::ET_GESTURE_END:
+      HandleGestureEndEvent();
+      break;
+    default:
+      overview_grid()->grid_pre_event_handler()->OnGestureEvent(event);
+      break;
+  }
+}
+
 bool OverviewItem::ShouldIgnoreGestureEvents() {
   return IsSlidingOutOverviewFromShelf();
 }
diff --git a/ash/wm/overview/overview_item.h b/ash/wm/overview/overview_item.h
index 1d896021..5ef3baa 100644
--- a/ash/wm/overview/overview_item.h
+++ b/ash/wm/overview/overview_item.h
@@ -185,6 +185,9 @@
   OverviewAnimationType GetExitOverviewAnimationType();
   OverviewAnimationType GetExitTransformAnimationType();
 
+  // If kNewOverviewLayout is on, use this function for handling events.
+  void HandleGestureEventForTabletModeLayout(ui::GestureEvent* event);
+
   // CaptionContainerView::EventDelegate:
   void HandleMouseEvent(const ui::MouseEvent& event) override;
   void HandleGestureEvent(ui::GestureEvent* event) override;
diff --git a/ash/wm/overview/overview_session.cc b/ash/wm/overview/overview_session.cc
index 600ace1..1df88147 100644
--- a/ash/wm/overview/overview_session.cc
+++ b/ash/wm/overview/overview_session.cc
@@ -755,11 +755,16 @@
   item->CloseWindow();
 }
 
-void OverviewSession::OnDisplayRemoved(const display::Display& display) {
-  // TODO(flackr): Keep window selection active on remaining displays.
+void OverviewSession::OnDisplayAdded(const display::Display& display) {
   EndOverview();
 }
 
+void OverviewSession::OnDisplayRemoved(const display::Display& display) {
+  // Removing a display causes a window activation which will end overview mode
+  // so that |OnDisplayRemoved| is never called.
+  NOTREACHED();
+}
+
 void OverviewSession::OnDisplayMetricsChanged(const display::Display& display,
                                               uint32_t metrics) {
   // For metrics changes that happen when the split view mode is active, the
@@ -881,7 +886,7 @@
 }
 
 void OverviewSession::OnShellDestroying() {
-  // Cancel selection will call |Shutodnw()|, which will remove observer.
+  // Cancel selection will call |Shutdown()|, which will remove observer.
   EndOverview();
 }
 
@@ -927,6 +932,11 @@
   // Notify |split_view_drag_indicators_| if split view mode ended.
   if (split_view_drag_indicators_ && state == SplitViewState::kNoSnap)
     split_view_drag_indicators_->OnSplitViewModeEnded();
+
+  // Transfer focus from |window| to |overview_focus_widget_| to match the
+  // behavior of entering overview mode in the beginning.
+  DCHECK(overview_focus_widget_);
+  wm::ActivateWindow(GetOverviewFocusWindow());
 }
 
 void OverviewSession::OnSplitViewDividerPositionChanged() {
diff --git a/ash/wm/overview/overview_session.h b/ash/wm/overview/overview_session.h
index 1d6450ef4..0fecfe38 100644
--- a/ash/wm/overview/overview_session.h
+++ b/ash/wm/overview/overview_session.h
@@ -239,6 +239,7 @@
   void OnHighlightedItemClosed(OverviewItem* item);
 
   // display::DisplayObserver:
+  void OnDisplayAdded(const display::Display& display) override;
   void OnDisplayRemoved(const display::Display& display) override;
   void OnDisplayMetricsChanged(const display::Display& display,
                                uint32_t metrics) override;
diff --git a/ash/wm/overview/overview_session_unittest.cc b/ash/wm/overview/overview_session_unittest.cc
index 6541a19..db18dd06 100644
--- a/ash/wm/overview/overview_session_unittest.cc
+++ b/ash/wm/overview/overview_session_unittest.cc
@@ -1086,29 +1086,6 @@
   EXPECT_FALSE(InOverviewSession());
 }
 
-// Regression test for crash when closing the last overview mode window under
-// SingleProcessMash. https://crbug.com/922293.
-TEST_F(OverviewSessionTest, DontRestoreFocusToUnparentedWindow) {
-  const gfx::Rect bounds(400, 400);
-  std::unique_ptr<aura::Window> parent = CreateTestWindow(bounds);
-  std::unique_ptr<aura::Window> child = CreateChildWindow(parent.get(), bounds);
-
-  // Enter overview with a focused child window. This simulates an app window
-  // web contents RenderWidgetHostViewAura.
-  child->Focus();
-  ToggleOverview();
-
-  // Simulate the asynchronous window teardown for used by client widgets.
-  // Hierarchy changes are processed first, so the child is removed from its
-  // parent, then the windows are destroyed.
-  parent->RemoveChild(child.get());
-  parent.reset();
-  child.reset();
-
-  // Overview mode exits without crashing.
-  EXPECT_FALSE(InOverviewSession());
-}
-
 // Tests that entering overview mode restores a window to its original
 // target location.
 TEST_F(OverviewSessionTest, QuickReentryRestoresInitialTransform) {
@@ -2821,11 +2798,25 @@
     EnterTabletMode();
   }
 
+  SplitViewController* split_view_controller() {
+    return Shell::Get()->split_view_controller();
+  }
+
   void GenerateScrollSequence(const gfx::Point& start, const gfx::Point& end) {
     GetEventGenerator()->GestureScrollSequence(
         start, end, base::TimeDelta::FromMilliseconds(10), 10);
   }
 
+ protected:
+  void DispatchLongPress(OverviewItem* item) {
+    ui::TouchEvent long_press(
+        ui::ET_GESTURE_LONG_PRESS,
+        gfx::ToRoundedPoint(item->target_bounds().CenterPoint()),
+        base::TimeTicks::Now(),
+        ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH));
+    GetEventGenerator()->Dispatch(&long_press);
+  }
+
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
 
@@ -2986,10 +2977,9 @@
 
   // Snap |window1| to the left and exit overview. |window2| should have higher
   // z-order now, since it is the MRU window.
-  auto* split_view_controller = Shell::Get()->split_view_controller();
-  split_view_controller->SnapWindow(window1.get(), SplitViewController::LEFT);
+  split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
   ToggleOverview();
-  ASSERT_EQ(SplitViewState::kBothSnapped, split_view_controller->state());
+  ASSERT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state());
   ASSERT_GT(IndexOf(window2.get(), window2->parent()),
             IndexOf(window1.get(), window1->parent()));
 
@@ -3006,6 +2996,103 @@
             IndexOf(window1.get(), window1->parent()));
 }
 
+// Test that scrolling occurs if started on top of a window using the window's
+// center-point as a start.
+TEST_F(OverviewSessionNewLayoutTest, CheckScrollingOnWindowItems) {
+  std::vector<std::unique_ptr<aura::Window>> windows(8);
+  for (int i = 7; i >= 0; --i)
+    windows[i] = CreateTestWindow();
+
+  ToggleOverview();
+  ASSERT_TRUE(InOverviewSession());
+
+  OverviewItem* leftmost_window =
+      GetOverviewItemInGridWithWindow(0, windows[0].get());
+  const gfx::Point topleft_window_center =
+      gfx::ToRoundedPoint(leftmost_window->target_bounds().CenterPoint());
+  const gfx::RectF left_bounds = leftmost_window->target_bounds();
+
+  GenerateScrollSequence(topleft_window_center, gfx::Point(-500, 50));
+  EXPECT_LT(leftmost_window->target_bounds(), left_bounds);
+}
+
+// Test that tapping a window in overview closes overview mode.
+TEST_F(OverviewSessionNewLayoutTest, CheckWindowActivateOnTap) {
+  base::UserActionTester user_action_tester;
+  std::vector<std::unique_ptr<aura::Window>> windows(8);
+  for (int i = 7; i >= 0; --i)
+    windows[i] = CreateTestWindow();
+  wm::ActivateWindow(windows[1].get());
+
+  ToggleOverview();
+  ASSERT_TRUE(InOverviewSession());
+
+  // Tap on |windows|1|| to exit overview.
+  GetEventGenerator()->GestureTapAt(
+      GetTransformedTargetBounds(windows[1].get()).CenterPoint());
+  EXPECT_EQ(
+      0, user_action_tester.GetActionCount(kActiveWindowChangedFromOverview));
+
+  // |windows|1|| remains active. Click on it to exit overview.
+  ASSERT_EQ(windows[1].get(), window_util::GetFocusedWindow());
+  ToggleOverview();
+  ClickWindow(windows[1].get());
+  EXPECT_EQ(
+      0, user_action_tester.GetActionCount(kActiveWindowChangedFromOverview));
+}
+
+// Tests that windows snap through long press and drag to left or right side of
+// the screen.
+TEST_F(OverviewSessionNewLayoutTest, DragOverviewWindowToSnap) {
+  const gfx::Rect bounds(400, 400);
+  std::unique_ptr<aura::Window> window1(CreateTestWindow(bounds));
+  std::unique_ptr<aura::Window> window2(CreateTestWindow(bounds));
+  std::unique_ptr<aura::Window> window3(CreateTestWindow(bounds));
+
+  ToggleOverview();
+  ASSERT_TRUE(overview_controller()->InOverviewSession());
+  ASSERT_FALSE(split_view_controller()->InSplitViewMode());
+
+  // Dispatches a long press event at the |overview_item1|'s current location to
+  // start dragging in SplitView. Drags |overview_item1| to the left border of
+  // the screen. SplitView should trigger and upon completing drag,
+  // |overview_item1| should snap to the left.
+  OverviewItem* overview_item1 =
+      GetOverviewItemInGridWithWindow(0, window1.get());
+  const gfx::PointF snap_left_location =
+      gfx::PointF(GetGridBounds().left_center());
+
+  DispatchLongPress(overview_item1);
+  overview_session()->Drag(
+      overview_item1,
+      gfx::PointF(overview_item1->target_bounds().left_center()));
+  overview_session()->CompleteDrag(overview_item1, snap_left_location);
+
+  ASSERT_TRUE(split_view_controller()->InSplitViewMode());
+  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->left_window(), window1.get());
+
+  // Dispatches a long press event at the |overview_item2|'s current location to
+  // start dragging in SplitView. Drags |overview_item2| to the right border of
+  // the screen. Upon completing drag, |overview_item2| should snap to the
+  // right.
+  OverviewItem* overview_item2 =
+      GetOverviewItemInGridWithWindow(0, window2.get());
+  const gfx::PointF snap_right_location =
+      gfx::PointF(GetGridBounds().right_center());
+
+  DispatchLongPress(overview_item2);
+  overview_session()->Drag(
+      overview_item2,
+      gfx::PointF(overview_item2->target_bounds().right_center()));
+  overview_session()->CompleteDrag(overview_item2, snap_right_location);
+
+  EXPECT_FALSE(InOverviewSession());
+  EXPECT_TRUE(split_view_controller()->InSplitViewMode());
+  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->right_window(), window2.get());
+}
+
 // Test the split view and overview functionalities in tablet mode.
 class SplitViewOverviewSessionTest : public OverviewSessionTest {
  public:
@@ -4368,6 +4455,29 @@
   EXPECT_TRUE(InOverviewSession());
 }
 
+// Tests closing a snapped window while in overview mode.
+TEST_F(SplitViewOverviewSessionTest, ClosingSplitViewWindow) {
+  const gfx::Rect bounds(400, 400);
+  std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
+  std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
+
+  ToggleOverview();
+  // Drag |window1| selector item to snap to left.
+  OverviewItem* overview_item1 =
+      GetOverviewItemInGridWithWindow(0, window1.get());
+  DragWindowTo(overview_item1, gfx::PointF(0, 0));
+  EXPECT_TRUE(overview_controller()->InOverviewSession());
+  EXPECT_TRUE(split_view_controller()->InSplitViewMode());
+
+  // Now close the snapped |window1|. We should remain in overview mode and the
+  // overview focus window should regain focus.
+  window1.reset();
+  EXPECT_TRUE(overview_controller()->InOverviewSession());
+  EXPECT_FALSE(split_view_controller()->InSplitViewMode());
+  EXPECT_EQ(overview_session()->GetOverviewFocusWindow(),
+            window_util::GetFocusedWindow());
+}
+
 // Test the split view and overview functionalities in clamshell mode. Split
 // view is only active when overview is active in clamshell mode.
 class SplitViewOverviewSessionInClamshellTest
@@ -4489,22 +4599,30 @@
             WindowStateType::kLeftSnapped);
   EXPECT_TRUE(overview_controller()->InOverviewSession());
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
+  // End overview, test that we'll not auto-snap a window to the right side of
+  // the screen.
+  EXPECT_EQ(WindowState::Get(window4.get())->GetStateType(),
+            WindowStateType::kDefault);
   ToggleOverview();
   EXPECT_EQ(WindowState::Get(window4.get())->GetStateType(),
-            WindowStateType::kRightSnapped);
+            WindowStateType::kDefault);
   EXPECT_FALSE(overview_controller()->InOverviewSession());
   EXPECT_FALSE(split_view_controller()->InSplitViewMode());
 
   // 5. Test if one window is snapped, the other window are showing in overview,
-  // activating an new window will open in splitview, which ends splitview and
-  // overview.
+  // activating an new window will not auto-snap the new window. Overview and
+  // splitview should be ended.
   ToggleOverview();
   overview_item1 = GetOverviewItemInGridWithWindow(grid_index, window1.get());
   DragWindowTo(overview_item1, gfx::PointF(0, 0));
   EXPECT_TRUE(overview_controller()->InOverviewSession());
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
   std::unique_ptr<aura::Window> window5(CreateWindow(bounds));
+  EXPECT_EQ(WindowState::Get(window5.get())->GetStateType(),
+            WindowStateType::kDefault);
   wm::ActivateWindow(window5.get());
+  EXPECT_EQ(WindowState::Get(window5.get())->GetStateType(),
+            WindowStateType::kDefault);
   EXPECT_FALSE(overview_controller()->InOverviewSession());
   EXPECT_FALSE(split_view_controller()->InSplitViewMode());
 
@@ -4523,6 +4641,22 @@
   EXPECT_FALSE(split_view_controller()->InSplitViewMode());
   // Overview bounds will adjust from snapped bounds to fullscreen bounds.
   EXPECT_EQ(GetGridBounds(), overview_bounds);
+
+  // 7. Test if split view mode is active, open the app list will not end
+  // overview and splitview.
+  overview_item3 = GetOverviewItemInGridWithWindow(grid_index, window3.get());
+  DragWindowTo(overview_item3, gfx::PointF(0, 0));
+  EXPECT_TRUE(overview_controller()->InOverviewSession());
+  EXPECT_TRUE(split_view_controller()->InSplitViewMode());
+  // Open app list.
+  AppListControllerImpl* app_list_controller =
+      Shell::Get()->app_list_controller();
+  app_list_controller->ToggleAppList(
+      display::Screen::GetScreen()->GetDisplayNearestWindow(window3.get()).id(),
+      app_list::AppListShowSource::kSearchKey, base::TimeTicks());
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(overview_controller()->InOverviewSession());
+  EXPECT_TRUE(split_view_controller()->InSplitViewMode());
 }
 
 // Test that if app list is visible when overview is open, overview should
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc
index b458070..4c5fb64 100644
--- a/ash/wm/splitview/split_view_controller.cc
+++ b/ash/wm/splitview/split_view_controller.cc
@@ -12,6 +12,7 @@
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/presentation_time_recorder.h"
 #include "ash/public/cpp/window_properties.h"
+#include "ash/scoped_animation_disabler.h"
 #include "ash/screen_util.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
@@ -406,6 +407,14 @@
     }
   }
 
+  // Disable the bounds change animation for a to-be-snapped window if the
+  // window has an un-identity transform. We'll do transform animation for the
+  // window in OnWindowSnapped() function.
+  std::unique_ptr<ScopedAnimationDisabler> animation_disabler;
+  auto iter = snapping_window_transformed_bounds_map_.find(window);
+  if (iter != snapping_window_transformed_bounds_map_.end())
+    animation_disabler = std::make_unique<ScopedAnimationDisabler>(window);
+
   if (WindowState::Get(window)->GetStateType() ==
       GetStateTypeFromSnapPosition(snap_position)) {
     // Update its snapped bounds as its bounds may not be the expected snapped
@@ -918,15 +927,6 @@
     return;
   }
 
-  // This may be called while SnapWindow is still underway because SnapWindow
-  // will end the overview start animations which will cause the overview focus
-  // window to be activated.
-  aura::Window* overview_focus_window =
-      GetOverviewSession() ? GetOverviewSession()->GetOverviewFocusWindow()
-                           : nullptr;
-  DCHECK(InSplitViewMode() ||
-         (overview_focus_window && overview_focus_window == gained_active));
-
   // If |gained_active| was activated as a side effect of a window disposition
   // change, do nothing. For example, when a snapped window is closed, another
   // window will be activated before OnWindowDestroying() is called. We should
@@ -934,12 +934,26 @@
   if (reason == ActivationReason::WINDOW_DISPOSITION_CHANGED)
     return;
 
-  // Only snap window that hasn't been snapped.
-  if (!gained_active || gained_active == left_window_ ||
-      gained_active == right_window_) {
+  // Only windows that are in the MRU list and are not already in split view can
+  // be auto-snapped.
+  if (!gained_active || IsWindowInSplitView(gained_active) ||
+      !base::Contains(
+          Shell::Get()->mru_window_tracker()->BuildMruWindowList(kActiveDesk),
+          gained_active)) {
     return;
   }
 
+  // We do not auto snap windows in clamshell splitview mode if a new window
+  // is activated when clamshell splitview mode is active. In this case we'll
+  // just end overview mode which will then end splitview mode.
+  // TODO(xdai): Handle this logic in OverivewSession::OnWindowActivating().
+  if (InClamshellSplitViewMode()) {
+    Shell::Get()->overview_controller()->EndOverview();
+    return;
+  }
+
+  DCHECK(InTabletSplitViewMode());
+
   // Do not snap the window if the activation change is caused by dragging a
   // window, or by dragging a tab. Note the two values WindowState::is_dragged()
   // and IsDraggingTabs() might not be exactly the same under certain
@@ -953,13 +967,6 @@
     return;
   }
 
-  // Only windows in MRU list can be snapped.
-  if (!base::Contains(
-          Shell::Get()->mru_window_tracker()->BuildMruWindowList(kActiveDesk),
-          gained_active)) {
-    return;
-  }
-
   // If the divider is animating, then |gained_active| cannot be snapped (and is
   // not already snapped either, because then we would have bailed out by now).
   // Then if |gained_active| is user-positionable, we should end split view
@@ -1025,16 +1032,18 @@
     return;
   }
 
-  OverviewGrid* current_grid =
-      overview_session->GetGridWithRootWindow(root_window);
-  if (!current_grid || current_grid->empty()) {
-    // If overview is ended with an empty overview grid, end split view as well
-    // if we're in clamshell splitview mode.
-    if (InClamshellSplitViewMode())
-      EndSplitView();
+  // If we're in clamshell splitview mode, do not auto snap overview window
+  // when overview ends.
+  if (split_view_type_ == SplitViewType::kClamshellType) {
+    EndSplitView();
     return;
   }
 
+  OverviewGrid* current_grid =
+      overview_session->GetGridWithRootWindow(root_window);
+  if (!current_grid || current_grid->empty())
+    return;
+
   // If split view mode is active but only has one snapped window when overview
   // mode is ending, retrieve the first snappable window in the overview window
   // grid and snap it.
@@ -1207,6 +1216,13 @@
     if (split_view_divider_)
       split_view_divider_->RemoveObservedWindow(window);
     Shell::Get()->shadow_controller()->UpdateShadowForWindow(window);
+
+    // It's possible that when we try to snap an ARC app window, while we are
+    // waiting for its state/bounds to the expected state/bounds, another window
+    // snap request comes in and causing the previous to-be-snapped window to
+    // be un-observed, in this case we should restore the previous to-be-snapped
+    // window's transform if it's unidentity.
+    RestoreTransformIfApplicable(window);
   }
 }
 
@@ -1685,8 +1701,6 @@
 }
 
 void SplitViewController::RestoreTransformIfApplicable(aura::Window* window) {
-  DCHECK(IsWindowInSplitView(window));
-
   // If the transform of the window has been changed, calculate a good starting
   // transform based on its transformed bounds before to be snapped.
   auto iter = snapping_window_transformed_bounds_map_.find(window);
diff --git a/ash/wm/tablet_mode/tablet_mode_window_state.cc b/ash/wm/tablet_mode/tablet_mode_window_state.cc
index fa8fecf..f8feb49e 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_state.cc
+++ b/ash/wm/tablet_mode/tablet_mode_window_state.cc
@@ -498,8 +498,6 @@
       // avoid flashing.
       if (window_state->IsMaximized())
         window_state->SetBoundsDirectCrossFade(bounds_in_parent);
-      else if (window_state->IsSnapped())
-        window_state->SetBoundsDirect(bounds_in_parent);
       else
         window_state->SetBoundsDirectAnimated(bounds_in_parent);
     }
diff --git a/ash/wm/window_cycle_controller.cc b/ash/wm/window_cycle_controller.cc
index d6b02a3..9c6ddce2 100644
--- a/ash/wm/window_cycle_controller.cc
+++ b/ash/wm/window_cycle_controller.cc
@@ -68,7 +68,6 @@
 
   window_cycle_list_ = std::make_unique<WindowCycleList>(window_list);
   event_filter_ = std::make_unique<WindowCycleEventFilter>();
-  cycle_start_time_ = base::Time::Now();
   base::RecordAction(base::UserMetricsAction("WindowCycleController_Cycle"));
   UMA_HISTOGRAM_COUNTS_100("Ash.WindowCycleController.Items",
                            window_list.size());
@@ -92,8 +91,6 @@
 }
 
 void WindowCycleController::StopCycling() {
-  UMA_HISTOGRAM_COUNTS_100("Ash.WindowCycleController.SelectionDepth",
-                           window_cycle_list_->current_index() + 1);
   window_cycle_list_.reset();
 
   aura::Window* active_window_after_window_cycle = GetActiveWindow(
@@ -101,8 +98,6 @@
 
   // Remove our key event filter.
   event_filter_.reset();
-  UMA_HISTOGRAM_MEDIUM_TIMES("Ash.WindowCycleController.CycleTime",
-                             base::Time::Now() - cycle_start_time_);
 
   if (active_window_after_window_cycle != nullptr &&
       active_window_before_window_cycle_ != active_window_after_window_cycle) {
diff --git a/ash/wm/window_cycle_controller.h b/ash/wm/window_cycle_controller.h
index 4e687b7..5c017d9 100644
--- a/ash/wm/window_cycle_controller.h
+++ b/ash/wm/window_cycle_controller.h
@@ -75,8 +75,6 @@
   // Non-null while actively cycling.
   std::unique_ptr<WindowCycleEventFilter> event_filter_;
 
-  base::Time cycle_start_time_;
-
   DISALLOW_COPY_AND_ASSIGN(WindowCycleController);
 };
 
diff --git a/ash/wm/window_util.cc b/ash/wm/window_util.cc
index 5516d338..2b92f46 100644
--- a/ash/wm/window_util.cc
+++ b/ash/wm/window_util.cc
@@ -22,7 +22,6 @@
 #include "ash/wm/window_positioning_utils.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/wm_event.h"
-#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/capture_client.h"
 #include "ui/aura/client/focus_client.h"
 #include "ui/aura/window.h"
@@ -185,11 +184,6 @@
                            -kResizeOutsideBoundsSize);
   gfx::Insets touch_extend =
       mouse_extend.Scale(kResizeOutsideBoundsScaleForTouch);
-  // TODO: EasyResizeWindowTargeter makes it so children get events outside
-  // their bounds. This only works in mash when mash is providing the non-client
-  // frame. Mus needs to support an api for the WindowManager that enables
-  // events to be dispatched to windows outside the windows bounds that this
-  // function calls into. http://crbug.com/679056.
   window->SetEventTargeter(std::make_unique<::wm::EasyResizeWindowTargeter>(
       mouse_extend, touch_extend));
 }
@@ -202,10 +196,6 @@
 
 void InstallResizeHandleWindowTargeterForWindow(aura::Window* window) {
   window->SetEventTargeter(std::make_unique<InteriorResizeHandleTargeter>());
-  // For Mash, ServerWindows will override the event targeter with a
-  // ServerWindowTargeter, so make sure it knows about the resize insets.
-  window->SetProperty(aura::client::kResizeHandleInset,
-                      kResizeInsideBoundsSize);
 }
 
 bool IsDraggingTabs(const aura::Window* window) {
diff --git a/base/memory/protected_memory_cfi.h b/base/memory/protected_memory_cfi.h
index a90023b..812e3cc 100644
--- a/base/memory/protected_memory_cfi.h
+++ b/base/memory/protected_memory_cfi.h
@@ -64,7 +64,9 @@
 template <typename T>
 auto UnsanitizedCfiCall(const ProtectedMemory<T>& PM) {
 #if PROTECTED_MEMORY_ENABLED
-  DCHECK(&PM >= ProtectedMemoryStart && &PM < ProtectedMemoryEnd);
+  DCHECK(&PM >= ProtectedMemoryStart && &PM < ProtectedMemoryEnd)
+      << "ProtectedMemoryStart=" << ProtectedMemoryStart << ", &PM=" << &PM
+      << ", ProtectedMemoryEnd=" << ProtectedMemoryEnd;
 #endif  // PROTECTED_MEMORY_ENABLED
   return internal::UnsanitizedCfiCall<T>(*PM);
 }
@@ -76,7 +78,9 @@
 template <typename T, typename Member>
 auto UnsanitizedCfiCall(const ProtectedMemory<T>& PM, Member member) {
 #if PROTECTED_MEMORY_ENABLED
-  DCHECK(&PM >= ProtectedMemoryStart && &PM < ProtectedMemoryEnd);
+  DCHECK(&PM >= ProtectedMemoryStart && &PM < ProtectedMemoryEnd)
+      << "ProtectedMemoryStart=" << ProtectedMemoryStart << ", &PM=" << &PM
+      << ", ProtectedMemoryEnd=" << ProtectedMemoryEnd;
 #endif  // PROTECTED_MEMORY_ENABLED
   return internal::UnsanitizedCfiCall<decltype(*PM.*member)>(*PM.*member);
 }
diff --git a/base/supports_user_data.cc b/base/supports_user_data.cc
index 8060543..f4a459d 100644
--- a/base/supports_user_data.cc
+++ b/base/supports_user_data.cc
@@ -66,4 +66,9 @@
   // examining a being-destroyed object.
 }
 
+void SupportsUserData::ClearAllUserData() {
+  DCHECK(sequence_checker_.CalledOnValidSequence());
+  user_data_.clear();
+}
+
 }  // namespace base
diff --git a/base/supports_user_data.h b/base/supports_user_data.h
index f8aa492c..418d4cc 100644
--- a/base/supports_user_data.h
+++ b/base/supports_user_data.h
@@ -56,6 +56,10 @@
  protected:
   virtual ~SupportsUserData();
 
+  // Clear all user data from this object. This can be used if the subclass
+  // needs to provide reset functionality.
+  void ClearAllUserData();
+
  private:
   using DataMap = std::map<const void*, std::unique_ptr<Data>>;
 
diff --git a/base/supports_user_data_unittest.cc b/base/supports_user_data_unittest.cc
index b30ede02..7bf11409 100644
--- a/base/supports_user_data_unittest.cc
+++ b/base/supports_user_data_unittest.cc
@@ -12,7 +12,10 @@
 namespace base {
 namespace {
 
-struct TestSupportsUserData : public SupportsUserData {};
+struct TestSupportsUserData : public SupportsUserData {
+  // Make ClearAllUserData public so tests can access it.
+  using SupportsUserData::ClearAllUserData;
+};
 
 struct UsesItself : public SupportsUserData::Data {
   UsesItself(SupportsUserData* supports_user_data, const void* key)
@@ -54,5 +57,21 @@
   EXPECT_EQ(nullptr, supports_user_data_2.GetUserData(&key2));
 }
 
+TEST(SupportsUserDataTest, ClearAllUserData) {
+  TestSupportsUserData supports_user_data;
+  char key1 = 0;
+  supports_user_data.SetUserData(&key1, std::make_unique<TestData>());
+  char key2 = 0;
+  supports_user_data.SetUserData(&key2, std::make_unique<TestData>());
+
+  EXPECT_TRUE(supports_user_data.GetUserData(&key1));
+  EXPECT_TRUE(supports_user_data.GetUserData(&key2));
+
+  supports_user_data.ClearAllUserData();
+
+  EXPECT_FALSE(supports_user_data.GetUserData(&key1));
+  EXPECT_FALSE(supports_user_data.GetUserData(&key2));
+}
+
 }  // namespace
 }  // namespace base
diff --git a/base/task/thread_pool/job_task_source.cc b/base/task/thread_pool/job_task_source.cc
index 9adf020..6eca51e9d 100644
--- a/base/task/thread_pool/job_task_source.cc
+++ b/base/task/thread_pool/job_task_source.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/bind_helpers.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/task/task_features.h"
@@ -39,8 +40,12 @@
       queue_time_(ThreadPoolClock::Now()) {}
 
 JobTaskSource::~JobTaskSource() {
+#if DCHECK_IS_ON()
+  auto worker_count = worker_count_.load(std::memory_order_relaxed);
   // Make sure there's no outstanding run intent left.
-  DCHECK_EQ(0U, worker_count_.load(std::memory_order_relaxed));
+  DCHECK(worker_count == 0U || worker_count == kInvalidWorkerCount)
+      << worker_count;
+#endif
 }
 
 ExecutionEnvironment JobTaskSource::GetExecutionEnvironment() {
@@ -48,25 +53,37 @@
 }
 
 TaskSource::RunIntent JobTaskSource::WillRunTask() {
+  // When this call is caused by an increase of max concurrency followed by an
+  // associated NotifyConcurrencyIncrease(), the priority queue lock guarantees
+  // an happens-after relation with NotifyConcurrencyIncrease(). The memory
+  // operations on |worker_count| below and in DidProcessTask() use
+  // std::memory_order_release and std::memory_order_acquire respectively to
+  // establish a Release-Acquire ordering. This ensures that all memory
+  // side-effects made before this point, including an increase of max
+  // concurrency followed by NotifyConcurrencyIncrease() are visible to a
+  // DidProcessTask() call which is ordered after this one.
   const size_t max_concurrency = GetMaxConcurrency();
-  const size_t worker_count_initial =
+  size_t worker_count_before_add =
       worker_count_.load(std::memory_order_relaxed);
+
+  // std::memory_order_release on success to make the newest |max_concurrency|
+  // visible to a thread that calls DidProcessTask() containing a matching
+  // std::memory_order_acquire.
+  while (worker_count_before_add < max_concurrency &&
+         !worker_count_.compare_exchange_weak(
+             worker_count_before_add, worker_count_before_add + 1,
+             std::memory_order_release, std::memory_order_relaxed)) {
+  }
   // Don't allow this worker to run the task if either:
   //   A) |worker_count_| is already at |max_concurrency|.
   //   B) |max_concurrency| was lowered below or to |worker_count_|.
-  if (worker_count_initial >= max_concurrency) {
-    // The caller receives an invalid RunIntent and should skip this TaskSource.
+  //   C) |worker_count_| was invalidated.
+  if (worker_count_before_add >= max_concurrency) {
+    // The caller receives an invalid RunIntent and should skip this
+    // TaskSource.
     return RunIntent();
   }
-  const size_t worker_count_before_add =
-      worker_count_.fetch_add(1, std::memory_order_relaxed);
-  // WillRunTask() has external synchronization to prevent concurrent calls and
-  // it is the only place where |worker_count_| is incremented. Therefore, the
-  // second reading of |worker_count_| from WillRunTask() cannot be greater than
-  // the first reading. However, since DidProcessTask() can decrement
-  // |worker_count_| concurrently with WillRunTask(), the second reading can be
-  // lower than the first reading.
-  DCHECK_LE(worker_count_before_add, worker_count_initial);
+
   DCHECK_LT(worker_count_before_add, max_concurrency);
   return MakeRunIntent(max_concurrency == worker_count_before_add + 1
                            ? Saturated::kYes
@@ -74,6 +91,8 @@
 }
 
 size_t JobTaskSource::GetRemainingConcurrency() const {
+  // std::memory_order_relaxed is sufficient because no other state is
+  // synchronized with GetRemainingConcurrency().
   const size_t worker_count = worker_count_.load(std::memory_order_relaxed);
   const size_t max_concurrency = GetMaxConcurrency();
   // Avoid underflows.
@@ -96,28 +115,57 @@
   return base::make_optional<Task>(from_here_, worker_task_, TimeDelta());
 }
 
-bool JobTaskSource::DidProcessTask(RunResult run_result) {
+bool JobTaskSource::DidProcessTask() {
   size_t worker_count_before_sub =
-      worker_count_.fetch_sub(1, std::memory_order_relaxed);
+      worker_count_.load(std::memory_order_relaxed);
+
+  // std::memory_order_acquire on |worker_count_| is necessary to establish
+  // Release-Acquire ordering (see WillRunTask()).
+  // When the task source needs to be queued, either because the current task
+  // yielded or because of NotifyConcurrencyIncrease(), one of the following is
+  // true:
+  //   A) The JobTaskSource is already in the queue (no worker picked up the
+  //      extra work yet): Incorrectly returning false is fine and the memory
+  //      barrier may be ineffective.
+  //   B) The JobTaskSource() is no longer in the queue: The Release-Acquire
+  //      ordering with WillRunTask() established by |worker_count| ensures that
+  //      the upcoming call for GetMaxConcurrency() happens-after any
+  //      NotifyConcurrencyIncrease() that happened-before WillRunTask(). If
+  //      this task completed because it yielded, this barrier guarantees that
+  //      it sees an up-to-date concurrency value and correctly re-enqueues.
+  //
+  // Note that stale values the other way around (incorrectly re-enqueuing) are
+  // not an issue because the queues support empty task sources.
+  while (worker_count_before_sub != kInvalidWorkerCount &&
+         !worker_count_.compare_exchange_weak(
+             worker_count_before_sub, worker_count_before_sub - 1,
+             std::memory_order_acquire, std::memory_order_relaxed)) {
+  }
+  if (worker_count_before_sub == kInvalidWorkerCount)
+    return false;
+
   DCHECK_GT(worker_count_before_sub, 0U);
+
   // Re-enqueue the TaskSource if the task ran and the worker count is below the
   // max concurrency.
-  const bool must_be_queued =
-      run_result == RunResult::kSkippedAtShutdown
-          ? false
-          : worker_count_before_sub <= GetMaxConcurrency();
-  return must_be_queued;
+  return worker_count_before_sub <= GetMaxConcurrency();
 }
 
 SequenceSortKey JobTaskSource::GetSortKey() const {
   return SequenceSortKey(traits_.priority(), queue_time_);
 }
 
-void JobTaskSource::Clear() {
-  // Reset callbacks to release any reference held by this task source and
-  // prevent further calls to WillRunTask().
-  worker_task_.Reset();
-  max_concurrency_callback_.Reset();
+Optional<Task> JobTaskSource::Clear() {
+  // Invalidate |worker_count_| so that further calls to WillRunTask() never
+  // succeed. std::memory_order_relaxed is sufficient because this task source
+  // never needs to be re-enqueued after Clear().
+  size_t worker_count_before_store =
+      worker_count_.exchange(kInvalidWorkerCount, std::memory_order_relaxed);
+  DCHECK_GT(worker_count_before_store, 0U);
+  // Nothing is cleared since outstanding RunIntents might still racily run
+  // tasks. For simplicity, the destructor will take care of it once all
+  // references are released.
+  return base::make_optional<Task>(from_here_, DoNothing(), TimeDelta());
 }
 
 }  // namespace internal
diff --git a/base/task/thread_pool/job_task_source.h b/base/task/thread_pool/job_task_source.h
index b0d7004fe..38d90cc45 100644
--- a/base/task/thread_pool/job_task_source.h
+++ b/base/task/thread_pool/job_task_source.h
@@ -8,6 +8,7 @@
 #include <stddef.h>
 
 #include <atomic>
+#include <limits>
 
 #include "base/base_export.h"
 #include "base/callback.h"
@@ -42,6 +43,9 @@
   size_t GetRemainingConcurrency() const override;
 
  private:
+  static constexpr size_t kInvalidWorkerCount =
+      std::numeric_limits<size_t>::max();
+
   ~JobTaskSource() override;
 
   // Returns the maximum number of tasks from this TaskSource that can run
@@ -51,13 +55,12 @@
 
   // TaskSource:
   Optional<Task> TakeTask() override;
-  bool DidProcessTask(RunResult run_result) override;
+  Optional<Task> Clear() override;
+  bool DidProcessTask() override;
   SequenceSortKey GetSortKey() const override;
-  void Clear() override;
 
   // The current number of workers concurrently running tasks from this
-  // TaskSource. "memory_order_relaxed" is sufficient to access this variable as
-  // no other state is synchronized with it.
+  // TaskSource.
   std::atomic_size_t worker_count_{0U};
 
   const Location from_here_;
diff --git a/base/task/thread_pool/job_task_source_unittest.cc b/base/task/thread_pool/job_task_source_unittest.cc
index 5af75ce..05a8f546 100644
--- a/base/task/thread_pool/job_task_source_unittest.cc
+++ b/base/task/thread_pool/job_task_source_unittest.cc
@@ -53,23 +53,60 @@
   }
 }
 
-// Verifies that a job task source doesn't get reenqueued when a task is not
-// run.
-TEST(ThreadPoolJobTaskSourceTest, SkipTask) {
+// Verifies that a job task source doesn't allow any new RunIntent after Clear()
+// is called.
+TEST(ThreadPoolJobTaskSourceTest, Clear) {
   auto job_task = base::MakeRefCounted<test::MockJobTask>(
-      DoNothing(), /* num_tasks_to_run */ 1);
+      DoNothing(), /* num_tasks_to_run */ 5);
   scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource(
       FROM_HERE, {ThreadPool(), TaskPriority::BEST_EFFORT});
 
   TaskSource::Transaction task_source_transaction(
       task_source->BeginTransaction());
+  EXPECT_EQ(5U, task_source->GetRemainingConcurrency());
 
-  auto run_intent = task_source->WillRunTask();
-  EXPECT_TRUE(run_intent);
-  EXPECT_TRUE(run_intent.IsSaturated());
-  auto task = task_source_transaction.TakeTask(&run_intent);
-  EXPECT_FALSE(task_source_transaction.DidProcessTask(
-      std::move(run_intent), TaskSource::RunResult::kSkippedAtShutdown));
+  auto run_intent_a = task_source->WillRunTask();
+  EXPECT_TRUE(run_intent_a);
+  auto task_a = task_source_transaction.TakeTask(&run_intent_a);
+
+  auto run_intent_b = task_source->WillRunTask();
+  EXPECT_TRUE(run_intent_b);
+
+  auto run_intent_c = task_source->WillRunTask();
+  EXPECT_TRUE(run_intent_c);
+
+  auto run_intent_d = task_source->WillRunTask();
+  EXPECT_TRUE(run_intent_d);
+  EXPECT_FALSE(run_intent_c.IsSaturated());
+
+  {
+    EXPECT_EQ(1U, task_source->GetRemainingConcurrency());
+    auto task = task_source_transaction.Clear(std::move(run_intent_c));
+    std::move(task->task).Run();
+    EXPECT_EQ(0U, task_source->GetRemainingConcurrency());
+  }
+  // The task source shouldn't allow any further tasks after Clear.
+  EXPECT_FALSE(task_source->WillRunTask());
+
+  // Another outstanding RunIntent can still call Clear.
+  {
+    auto task = task_source_transaction.Clear(std::move(run_intent_d));
+    std::move(task->task).Run();
+    EXPECT_EQ(0U, task_source->GetRemainingConcurrency());
+  }
+
+  // A task that was already acquired can still run.
+  std::move(task_a->task).Run();
+  task_source_transaction.DidProcessTask(std::move(run_intent_a));
+
+  // A valid outstanding RunIntent can also take & run a task.
+  {
+    auto task = task_source_transaction.TakeTask(&run_intent_b);
+    std::move(task->task).Run();
+    task_source_transaction.DidProcessTask(std::move(run_intent_b));
+  }
+  // Sanity check.
+  EXPECT_FALSE(task_source->WillRunTask());
 }
 
 // Verifies that multiple tasks can run in parallel up to |max_concurrency|.
diff --git a/base/task/thread_pool/pooled_single_thread_task_runner_manager.cc b/base/task/thread_pool/pooled_single_thread_task_runner_manager.cc
index e33235f..ed11e70 100644
--- a/base/task/thread_pool/pooled_single_thread_task_runner_manager.cc
+++ b/base/task/thread_pool/pooled_single_thread_task_runner_manager.cc
@@ -139,19 +139,22 @@
     // |task| will be pushed to |sequence|, and |sequence| will be queued
     // to |priority_queue_| iff |sequence_should_be_queued| is true.
     const bool sequence_should_be_queued = transaction.WillPushTask();
-    if (!sequence_should_be_queued) {
-      transaction.PushTask(std::move(task));
-      return true;
+    RegisteredTaskSource task_source;
+    if (sequence_should_be_queued) {
+      task_source = task_tracker_->WillQueueTaskSource(sequence);
+      // We shouldn't push |task| if we're not allowed to queue |task_source|.
+      if (!task_source)
+        return false;
     }
-    auto registered_task_source = task_tracker_->WillQueueTaskSource(sequence);
-    if (!registered_task_source)
+    if (!task_tracker_->WillPostTaskNow(task, transaction.traits().priority()))
       return false;
-    task_tracker_->WillPostTaskNow(task, transaction.traits().priority());
     transaction.PushTask(std::move(task));
-    bool should_wakeup = EnqueueTaskSource(
-        {std::move(registered_task_source), std::move(transaction)});
-    if (should_wakeup)
-      worker_->WakeUp();
+    if (task_source) {
+      bool should_wakeup =
+          EnqueueTaskSource({std::move(task_source), std::move(transaction)});
+      if (should_wakeup)
+        worker_->WakeUp();
+    }
     return true;
   }
 
diff --git a/base/task/thread_pool/priority_queue.cc b/base/task/thread_pool/priority_queue.cc
index 1670dca..7807e84 100644
--- a/base/task/thread_pool/priority_queue.cc
+++ b/base/task/thread_pool/priority_queue.cc
@@ -82,8 +82,13 @@
   if (!is_flush_task_sources_on_destroy_enabled_)
     return;
 
-  while (!container_.empty())
-    PopTaskSource().Unregister()->BeginTransaction().Clear();
+  while (!container_.empty()) {
+    auto task_source = PopTaskSource().Unregister();
+    auto task =
+        task_source->BeginTransaction().Clear(task_source->WillRunTask());
+    if (task)
+      std::move(task->task).Run();
+  }
 }
 
 PriorityQueue& PriorityQueue::operator=(PriorityQueue&& other) = default;
diff --git a/base/task/thread_pool/sequence.cc b/base/task/thread_pool/sequence.cc
index 9e70451..1e21817 100644
--- a/base/task/thread_pool/sequence.cc
+++ b/base/task/thread_pool/sequence.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "base/bind.h"
 #include "base/critical_closure.h"
 #include "base/feature_list.h"
 #include "base/logging.h"
@@ -83,7 +84,7 @@
   return std::move(next_task);
 }
 
-bool Sequence::DidProcessTask(RunResult run_result) {
+bool Sequence::DidProcessTask() {
   // There should never be a call to DidProcessTask without an associated
   // WillRunTask().
   DCHECK(has_worker_);
@@ -103,15 +104,21 @@
   return SequenceSortKey(traits_.priority(), queue_.front().queue_time);
 }
 
-void Sequence::Clear() {
-  bool queue_was_empty = queue_.empty();
-  while (!queue_.empty())
-    queue_.pop();
-  if (!queue_was_empty) {
-    // No member access after this point, ReleaseTaskRunner() might have deleted
-    // |this|.
-    ReleaseTaskRunner();
-  }
+Optional<Task> Sequence::Clear() {
+  has_worker_ = false;
+  return base::make_optional<Task>(
+      FROM_HERE,
+      base::BindOnce(
+          [](scoped_refptr<Sequence> self, base::queue<Task> queue) {
+            bool queue_was_empty = queue.empty();
+            while (!queue.empty())
+              queue.pop();
+            if (!queue_was_empty) {
+              self->ReleaseTaskRunner();
+            }
+          },
+          scoped_refptr<Sequence>(this), std::move(queue_)),
+      TimeDelta());
 }
 
 void Sequence::ReleaseTaskRunner() {
diff --git a/base/task/thread_pool/sequence.h b/base/task/thread_pool/sequence.h
index e1c3b99..58cdf02 100644
--- a/base/task/thread_pool/sequence.h
+++ b/base/task/thread_pool/sequence.h
@@ -100,9 +100,9 @@
 
   // TaskSource:
   Optional<Task> TakeTask() override WARN_UNUSED_RESULT;
-  bool DidProcessTask(RunResult run_result) override;
+  Optional<Task> Clear() override WARN_UNUSED_RESULT;
+  bool DidProcessTask() override;
   SequenceSortKey GetSortKey() const override;
-  void Clear() override;
 
   // Releases reference to TaskRunner. This might cause this object to be
   // deleted; therefore, no member access should be made after this method.
diff --git a/base/task/thread_pool/task_source.cc b/base/task/thread_pool/task_source.cc
index 6d39aeb..4a02f2d 100644
--- a/base/task/thread_pool/task_source.cc
+++ b/base/task/thread_pool/task_source.cc
@@ -63,23 +63,26 @@
   return task_source_->TakeTask();
 }
 
-bool TaskSource::Transaction::DidProcessTask(RunIntent intent,
-                                             RunResult run_result) {
+Optional<Task> TaskSource::Transaction::Clear(RunIntent intent) {
+  DCHECK_EQ(intent.task_source_, task_source());
+  DCHECK_EQ(intent.run_step_, RunIntent::State::kInitial);
+  intent.run_step_ = RunIntent::State::kCompleted;
+  intent.Release();
+  return task_source_->Clear();
+}
+
+bool TaskSource::Transaction::DidProcessTask(RunIntent intent) {
   DCHECK_EQ(intent.task_source_, task_source());
   DCHECK_EQ(intent.run_step_, RunIntent::State::kTaskAcquired);
   intent.run_step_ = RunIntent::State::kCompleted;
   intent.Release();
-  return task_source_->DidProcessTask(run_result);
+  return task_source_->DidProcessTask();
 }
 
 SequenceSortKey TaskSource::Transaction::GetSortKey() const {
   return task_source_->GetSortKey();
 }
 
-void TaskSource::Transaction::Clear() {
-  task_source_->Clear();
-}
-
 void TaskSource::Transaction::UpdatePriority(TaskPriority priority) {
   if (FeatureList::IsEnabled(kAllTasksUserBlocking))
     return;
diff --git a/base/task/thread_pool/task_source.h b/base/task/thread_pool/task_source.h
index bb9deaa..df28aea 100644
--- a/base/task/thread_pool/task_source.h
+++ b/base/task/thread_pool/task_source.h
@@ -71,14 +71,9 @@
   };
 
  public:
-  // Indicates if a task was run or skipped as a result of shutdown.
-  enum class RunResult {
-    kDidRun,
-    kSkippedAtShutdown,
-  };
-
   // Result of WillRunTask(). A single task associated with a RunIntent may be
-  // accessed with TakeTask() and run iff this evaluates to true.
+  // accessed with TakeTask() and run, or the task source may be cleared with
+  // Clear() iff this evaluates to true.
   class BASE_EXPORT RunIntent {
    public:
     RunIntent() = default;
@@ -145,11 +140,15 @@
     // https://crbug.com/783309
     Optional<Task> TakeTask(RunIntent* intent) WARN_UNUSED_RESULT;
 
-    // Must be called once the task was run or skipped. |run_result| indicates
-    // if the task executed. Cannot be called on an empty TaskSource. Returns
-    // true if the TaskSource should be queued after this operation.
-    bool DidProcessTask(RunIntent intent,
-                        RunResult run_result = RunResult::kDidRun);
+    // Returns a task that clears this TaskSource to make it empty. This should
+    // be called only with a valid |intent|, but may be called for each valid
+    // outstanding RunIntent.
+    Optional<Task> Clear(RunIntent intent) WARN_UNUSED_RESULT;
+
+    // Must be called once the task was run. Cannot be called on an empty
+    // TaskSource. Returns true if the TaskSource should be queued after this
+    // operation.
+    bool DidProcessTask(RunIntent intent);
 
     // Returns a SequenceSortKey representing the priority of the TaskSource.
     // Cannot be called on an empty TaskSource.
@@ -158,9 +157,6 @@
     // Sets TaskSource priority to |priority|.
     void UpdatePriority(TaskPriority priority);
 
-    // Deletes all tasks contained in this TaskSource.
-    void Clear();
-
     // Returns the traits of all Tasks in the TaskSource.
     TaskTraits traits() const { return task_source_->traits_; }
 
@@ -194,14 +190,12 @@
 
   // Informs this TaskSource that an additional Task could be run. Returns a
   // RunIntent that evaluates to true if this operation is allowed (TakeTask()
-  // can be called), or false otherwise. This function is not thread safe and
-  // must be externally synchronized (e.g. by the lock of the PriorityQueue
-  // holding the TaskSource).
+  // or Clear() can be called), or false otherwise.
   virtual RunIntent WillRunTask() = 0;
 
   // Thread-safe but the returned value may immediately be obsolete. As such
   // this should only be used as a best-effort guess of how many more workers
-  // are needed.
+  // are needed. This may be called on an empty task source.
   virtual size_t GetRemainingConcurrency() const = 0;
 
   // Support for IntrusiveHeap.
@@ -231,11 +225,13 @@
   // Informs this TaskSource that a task was processed. |was_run| indicates
   // whether the task executed or not. Returns true if the TaskSource
   // should be queued after this operation.
-  virtual bool DidProcessTask(RunResult run_result) = 0;
+  virtual bool DidProcessTask() = 0;
 
   virtual SequenceSortKey GetSortKey() const = 0;
 
-  virtual void Clear() = 0;
+  // This may be called for each outstanding RunIntent. If applicable, the
+  // implementation needs to support this being called multiple times.
+  virtual Optional<Task> Clear() = 0;
 
   // Sets TaskSource priority to |priority|.
   void UpdatePriority(TaskPriority priority);
diff --git a/base/task/thread_pool/task_tracker.cc b/base/task/thread_pool/task_tracker.cc
index 95a40ec2..5a55a5a 100644
--- a/base/task/thread_pool/task_tracker.cc
+++ b/base/task/thread_pool/task_tracker.cc
@@ -129,18 +129,6 @@
                         : 0];
 }
 
-// Returns shutdown behavior based on |traits|; returns SKIP_ON_SHUTDOWN if
-// shutdown behavior is BLOCK_SHUTDOWN and |is_delayed|, because delayed tasks
-// are not allowed to block shutdown.
-TaskShutdownBehavior GetEffectiveShutdownBehavior(
-    TaskShutdownBehavior shutdown_behavior,
-    bool is_delayed) {
-  if (shutdown_behavior == TaskShutdownBehavior::BLOCK_SHUTDOWN && is_delayed) {
-    return TaskShutdownBehavior::SKIP_ON_SHUTDOWN;
-  }
-  return shutdown_behavior;
-}
-
 bool HasLogBestEffortTasksSwitch() {
   // The CommandLine might not be initialized if ThreadPool is initialized in a
   // dynamic library which doesn't have access to argc/argv.
@@ -394,10 +382,9 @@
 
   if (state_->HasShutdownStarted()) {
     // A non BLOCK_SHUTDOWN task is allowed to be posted iff shutdown hasn't
-    // started.
-    if (GetEffectiveShutdownBehavior(shutdown_behavior,
-                                     !task->delayed_run_time.is_null()) !=
-        TaskShutdownBehavior::BLOCK_SHUTDOWN) {
+    // started and the task is not delayed.
+    if (shutdown_behavior != TaskShutdownBehavior::BLOCK_SHUTDOWN ||
+        !task->delayed_run_time.is_null()) {
       return false;
     }
 
@@ -414,12 +401,15 @@
   return true;
 }
 
-void TaskTracker::WillPostTaskNow(const Task& task, TaskPriority priority) {
+bool TaskTracker::WillPostTaskNow(const Task& task, TaskPriority priority) {
+  if (!task.delayed_run_time.is_null() && state_->HasShutdownStarted())
+    return false;
   if (has_log_best_effort_tasks_switch_ &&
       priority == TaskPriority::BEST_EFFORT) {
     // A TaskPriority::BEST_EFFORT task is being posted.
     LOG(INFO) << task.posted_from.ToString();
   }
+  return true;
 }
 
 RegisteredTaskSource TaskTracker::WillQueueTaskSource(
@@ -453,43 +443,35 @@
   DCHECK(run_intent_with_task_source);
   auto task_source = run_intent_with_task_source.take_task_source();
 
+  const bool can_run_worker_task =
+      BeforeRunTask(task_source->shutdown_behavior());
+
   // Run the next task in |task_source|.
   Optional<Task> task;
   TaskTraits traits{ThreadPool()};
   {
     TaskSource::Transaction task_source_transaction(
         task_source->BeginTransaction());
-    task = task_source_transaction.TakeTask(&run_intent_with_task_source);
+    task = can_run_worker_task
+               ? task_source_transaction.TakeTask(&run_intent_with_task_source)
+               : task_source_transaction.Clear(
+                     std::move(run_intent_with_task_source));
     traits = task_source_transaction.traits();
   }
 
   if (task) {
-    const TaskShutdownBehavior effective_shutdown_behavior =
-        GetEffectiveShutdownBehavior(task_source->shutdown_behavior(),
-                                     !task->delayed_run_time.is_null());
-
-    const bool can_run_task = BeforeRunTask(effective_shutdown_behavior);
-
-    RunOrSkipTask(std::move(task.value()), task_source.get(), traits,
-                  can_run_task);
-
+    // Run the |task| (whether it's a worker task or the Clear() closure).
+    RunTask(std::move(task.value()), task_source.get(), traits);
+  }
+  if (can_run_worker_task) {
+    AfterRunTask(task_source->shutdown_behavior());
     const bool task_source_must_be_queued =
         task_source->BeginTransaction().DidProcessTask(
-            std::move(run_intent_with_task_source),
-            can_run_task ? TaskSource::RunResult::kDidRun
-                         : TaskSource::RunResult::kSkippedAtShutdown);
-
-    if (can_run_task) {
-      IncrementNumTasksRun();
-      AfterRunTask(effective_shutdown_behavior);
-    }
-
+            std::move(run_intent_with_task_source));
     // |task_source| should be reenqueued iff requested by DidProcessTask().
-    if (task_source_must_be_queued) {
+    if (task_source_must_be_queued)
       return task_source;
-    }
   }
-
   return nullptr;
 }
 
@@ -543,10 +525,9 @@
   num_tasks_run_.fetch_add(1, std::memory_order_relaxed);
 }
 
-void TaskTracker::RunOrSkipTask(Task task,
-                                TaskSource* task_source,
-                                const TaskTraits& traits,
-                                bool can_run_task) {
+void TaskTracker::RunTask(Task task,
+                          TaskSource* task_source,
+                          const TaskTraits& traits) {
   DCHECK(task_source);
   RecordLatencyHistogram(LatencyHistogramType::TASK_LATENCY, traits,
                          task.queue_time);
@@ -599,21 +580,19 @@
         break;
     }
 
-    if (can_run_task) {
-      TRACE_TASK_EXECUTION("ThreadPool_RunTask", task);
+    TRACE_TASK_EXECUTION("ThreadPool_RunTask", task);
 
-      // TODO(gab): In a better world this would be tacked on as an extra arg
-      // to the trace event generated above. This is not possible however until
-      // http://crbug.com/652692 is resolved.
-      TRACE_EVENT1("thread_pool", "ThreadPool_TaskInfo", "task_info",
-                   std::make_unique<TaskTracingInfo>(
-                       traits,
-                       kExecutionModeString[static_cast<size_t>(
-                           task_source->execution_mode())],
-                       environment.token));
+    // TODO(gab): In a better world this would be tacked on as an extra arg
+    // to the trace event generated above. This is not possible however until
+    // http://crbug.com/652692 is resolved.
+    TRACE_EVENT1("thread_pool", "ThreadPool_TaskInfo", "task_info",
+                 std::make_unique<TaskTracingInfo>(
+                     traits,
+                     kExecutionModeString[static_cast<size_t>(
+                         task_source->execution_mode())],
+                     environment.token));
 
-      RunTaskWithShutdownBehavior(traits.shutdown_behavior(), &task);
-    }
+    RunTaskWithShutdownBehavior(traits.shutdown_behavior(), &task);
 
     // Make sure the arguments bound to the callback are deleted within the
     // scope in which the callback runs.
@@ -652,9 +631,8 @@
   return !state_->HasShutdownStarted();
 }
 
-bool TaskTracker::BeforeRunTask(
-    TaskShutdownBehavior effective_shutdown_behavior) {
-  switch (effective_shutdown_behavior) {
+bool TaskTracker::BeforeRunTask(TaskShutdownBehavior shutdown_behavior) {
+  switch (shutdown_behavior) {
     case TaskShutdownBehavior::BLOCK_SHUTDOWN: {
       // The number of tasks blocking shutdown has been incremented when the
       // task was posted.
@@ -693,9 +671,9 @@
   return false;
 }
 
-void TaskTracker::AfterRunTask(
-    TaskShutdownBehavior effective_shutdown_behavior) {
-  if (effective_shutdown_behavior == TaskShutdownBehavior::SKIP_ON_SHUTDOWN) {
+void TaskTracker::AfterRunTask(TaskShutdownBehavior shutdown_behavior) {
+  IncrementNumTasksRun();
+  if (shutdown_behavior == TaskShutdownBehavior::SKIP_ON_SHUTDOWN) {
     DecrementNumItemsBlockingShutdown();
   }
 }
diff --git a/base/task/thread_pool/task_tracker.h b/base/task/thread_pool/task_tracker.h
index f44c6d0..1f2e34c 100644
--- a/base/task/thread_pool/task_tracker.h
+++ b/base/task/thread_pool/task_tracker.h
@@ -100,8 +100,10 @@
   bool WillPostTask(Task* task, TaskShutdownBehavior shutdown_behavior);
 
   // Informs this TaskTracker that |task| that is about to be pushed to a task
-  // source with |priority|.
-  void WillPostTaskNow(const Task& task, TaskPriority priority);
+  // source with |priority|. Returns true if this operation is allowed (the
+  // operation should be performed if-and-only-if it is).
+  bool WillPostTaskNow(const Task& task,
+                       TaskPriority priority) WARN_UNUSED_RESULT;
 
   // Informs this TaskTracker that |task_source| is about to be queued. Returns
   // a RegisteredTaskSource that should be queued if-and-only-if it evaluates to
@@ -166,16 +168,14 @@
   bool HasIncompleteTaskSourcesForTesting() const;
 
  protected:
-  // Runs and deletes |task| if |can_run_task| is true. Otherwise, just deletes
-  // |task|. |task| is always deleted in the environment where it runs or would
-  // have run. |task_source| is the task source from which |task| was extracted.
+  // Runs and deletes |task|. |task| is deleted in the environment where it
+  // runs. |task_source| is the task source from which |task| was extracted.
   // |traits| are the traits of |task_source|. An override is expected to call
   // its parent's implementation but is free to perform extra work before and
   // after doing so.
-  virtual void RunOrSkipTask(Task task,
-                             TaskSource* task_source,
-                             const TaskTraits& traits,
-                             bool can_run_task);
+  virtual void RunTask(Task task,
+                       TaskSource* task_source,
+                       const TaskTraits& traits);
 
  private:
   friend class RegisteredTaskSource;
@@ -186,16 +186,16 @@
   // Called before WillPostTask() informs the tracing system that a task has
   // been posted. Updates |num_items_blocking_shutdown_| if necessary and
   // returns true if the current shutdown state allows the task to be posted.
-  bool BeforeQueueTaskSource(TaskShutdownBehavior effective_shutdown_behavior);
+  bool BeforeQueueTaskSource(TaskShutdownBehavior shutdown_behavior);
 
   // Called before a task with |effective_shutdown_behavior| is run by
   // RunTask(). Updates |num_items_blocking_shutdown_| if necessary and returns
   // true if the current shutdown state allows the task to be run.
-  bool BeforeRunTask(TaskShutdownBehavior effective_shutdown_behavior);
+  bool BeforeRunTask(TaskShutdownBehavior shutdown_behavior);
 
   // Called after a task with |effective_shutdown_behavior| has been run by
   // RunTask(). Updates |num_items_blocking_shutdown_| if necessary.
-  void AfterRunTask(TaskShutdownBehavior effective_shutdown_behavior);
+  void AfterRunTask(TaskShutdownBehavior shutdown_behavior);
 
   // Informs this TaskTracker that |task_source| won't be reenqueued and returns
   // the underlying TaskSource. This is called before destroying a valid
diff --git a/base/task/thread_pool/task_tracker_posix.cc b/base/task/thread_pool/task_tracker_posix.cc
index ded8ce1c..eb49a7e 100644
--- a/base/task/thread_pool/task_tracker_posix.cc
+++ b/base/task/thread_pool/task_tracker_posix.cc
@@ -15,14 +15,12 @@
 TaskTrackerPosix::TaskTrackerPosix(StringPiece name) : TaskTracker(name) {}
 TaskTrackerPosix::~TaskTrackerPosix() = default;
 
-void TaskTrackerPosix::RunOrSkipTask(Task task,
-                                     TaskSource* task_source,
-                                     const TaskTraits& traits,
-                                     bool can_run_task) {
+void TaskTrackerPosix::RunTask(Task task,
+                               TaskSource* task_source,
+                               const TaskTraits& traits) {
   DCHECK(io_thread_task_runner_);
   FileDescriptorWatcher file_descriptor_watcher(io_thread_task_runner_);
-  TaskTracker::RunOrSkipTask(std::move(task), task_source, traits,
-                             can_run_task);
+  TaskTracker::RunTask(std::move(task), task_source, traits);
 }
 
 }  // namespace internal
diff --git a/base/task/thread_pool/task_tracker_posix.h b/base/task/thread_pool/task_tracker_posix.h
index 67a0f71b..8f59d53 100644
--- a/base/task/thread_pool/task_tracker_posix.h
+++ b/base/task/thread_pool/task_tracker_posix.h
@@ -41,10 +41,9 @@
 
  protected:
   // TaskTracker:
-  void RunOrSkipTask(Task task,
-                     TaskSource* task_source,
-                     const TaskTraits& traits,
-                     bool can_run_task) override;
+  void RunTask(Task task,
+               TaskSource* task_source,
+               const TaskTraits& traits) override;
 
  private:
   scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner_;
diff --git a/base/task/thread_pool/thread_pool_impl.cc b/base/task/thread_pool/thread_pool_impl.cc
index c8b3ff9..6a58c6a 100644
--- a/base/task/thread_pool/thread_pool_impl.cc
+++ b/base/task/thread_pool/thread_pool_impl.cc
@@ -358,7 +358,8 @@
     if (!task_source)
       return false;
   }
-  task_tracker_->WillPostTaskNow(task, transaction.traits().priority());
+  if (!task_tracker_->WillPostTaskNow(task, transaction.traits().priority()))
+    return false;
   transaction.PushTask(std::move(task));
   if (task_source) {
     const TaskTraits traits = transaction.traits();
diff --git a/base/test/ios/wait_util.h b/base/test/ios/wait_util.h
index 3a08929c4..35003cb 100644
--- a/base/test/ios/wait_util.h
+++ b/base/test/ios/wait_util.h
@@ -33,6 +33,12 @@
 // complete.
 extern const NSTimeInterval kWaitForActionTimeout;
 
+// Constant for timeout in seconds while waiting for clear browsing data. It
+// seems this can take a very long time on the bots when running simulators in
+// parallel. TODO(crbug.com/993513): Investigate why this is sometimes very
+// slow.
+extern const NSTimeInterval kWaitForClearBrowsingDataTimeout;
+
 // Constant for timeout in seconds while waiting for cookies operations to
 // complete.
 extern const NSTimeInterval kWaitForCookiesTimeout;
diff --git a/base/test/ios/wait_util.mm b/base/test/ios/wait_util.mm
index 1e79343..c1538c5 100644
--- a/base/test/ios/wait_util.mm
+++ b/base/test/ios/wait_util.mm
@@ -22,6 +22,7 @@
 const NSTimeInterval kWaitForDownloadTimeout = 10.0;
 const NSTimeInterval kWaitForPageLoadTimeout = 10.0;
 const NSTimeInterval kWaitForActionTimeout = 10.0;
+const NSTimeInterval kWaitForClearBrowsingDataTimeout = 45.0;
 const NSTimeInterval kWaitForCookiesTimeout = 4.0;
 const NSTimeInterval kWaitForFileOperationTimeout = 2.0;
 
diff --git a/base/test/launcher/test_launcher_unittest.cc b/base/test/launcher/test_launcher_unittest.cc
index 0efd407..e4a9f904 100644
--- a/base/test/launcher/test_launcher_unittest.cc
+++ b/base/test/launcher/test_launcher_unittest.cc
@@ -689,6 +689,7 @@
   FilePath path = dir.GetPath().AppendASCII("SaveSummaryResult.json");
   command_line.AppendSwitchPath("test-launcher-summary-output", path);
   command_line.AppendSwitch("gtest_also_run_disabled_tests");
+  command_line.AppendSwitch("--test-launcher-retry-limit=0");
 #if defined(OS_WIN)
   // In Windows versions prior to Windows 8, nested job objects are
   // not allowed and cause this test to fail.
diff --git a/base/test/scoped_task_environment.cc b/base/test/scoped_task_environment.cc
index 198568c6..d9adc91 100644
--- a/base/test/scoped_task_environment.cc
+++ b/base/test/scoped_task_environment.cc
@@ -115,10 +115,9 @@
   friend class ScopedTaskEnvironment;
 
   // internal::ThreadPoolImpl::TaskTrackerImpl:
-  void RunOrSkipTask(internal::Task task,
-                     internal::TaskSource* sequence,
-                     const TaskTraits& traits,
-                     bool can_run_task) override;
+  void RunTask(internal::Task task,
+               internal::TaskSource* sequence,
+               const TaskTraits& traits) override;
 
   // Synchronizes accesses to members below.
   mutable Lock lock_;
@@ -739,11 +738,10 @@
   return true;
 }
 
-void ScopedTaskEnvironment::TestTaskTracker::RunOrSkipTask(
+void ScopedTaskEnvironment::TestTaskTracker::RunTask(
     internal::Task task,
     internal::TaskSource* sequence,
-    const TaskTraits& traits,
-    bool can_run_task) {
+    const TaskTraits& traits) {
   {
     AutoLock auto_lock(lock_);
 
@@ -753,8 +751,8 @@
     ++num_tasks_running_;
   }
 
-  internal::ThreadPoolImpl::TaskTrackerImpl::RunOrSkipTask(
-      std::move(task), sequence, traits, can_run_task);
+  internal::ThreadPoolImpl::TaskTrackerImpl::RunTask(std::move(task), sequence,
+                                                     traits);
 
   {
     AutoLock auto_lock(lock_);
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 26e23cdc..12ba1f1c 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8905259265255449984
\ No newline at end of file
+8905231778037491328
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 8daaa4d9..37a5393 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8905261579048864528
\ No newline at end of file
+8905235025956967056
\ No newline at end of file
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index b0ac6b0..af0f90f 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -1606,12 +1606,6 @@
 
     shared_libraries = [ ":libchrome" ]
 
-    # Android supports webp transparent resources properly since API level 18,
-    # so this can only be activated for modern ones (which target API >= 21).
-    # TODO(digit): Turn this on for all builds once JellyBean support is
-    # dropped in the future.
-    png_to_webp = _is_modern && !is_java_debug
-
     # Native libraries can be loaded directly from the APK using the
     # Chromium linker. However, we disable this for J-K due to an OEM-specific
     # platform bug, where overzealous SELinux settings prevent mapping some apk
@@ -1926,6 +1920,9 @@
       proguard_enabled = true
       proguard_configs = [ "//chrome/android/java/apk_for_test.flags" ]
     }
+    
+    # TODO(crbug.com/993340): Update test goldens with webp versions of images.
+    png_to_webp = false
   }
 }
 
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 82fb51b..cf7e11c2 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -1415,6 +1415,7 @@
   "java/src/org/chromium/chrome/browser/share/ShareParams.java",
   "java/src/org/chromium/chrome/browser/sharing/SharingNotificationUtil.java",
   "java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java",
+  "java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallUma.java",
   "java/src/org/chromium/chrome/browser/sharing/shared_clipboard/SharedClipboardMessageHandler.java",
   "java/src/org/chromium/chrome/browser/sharing/SharingJNIBridge.java",
   "java/src/org/chromium/chrome/browser/signin/AccountPickerDialogFragment.java",
@@ -1556,6 +1557,7 @@
   "java/src/org/chromium/chrome/browser/tabmodel/TabModelObserver.java",
   "java/src/org/chromium/chrome/browser/tabmodel/TabModelObserverJniBridge.java",
   "java/src/org/chromium/chrome/browser/tabmodel/TabModelOrderController.java",
+  "java/src/org/chromium/chrome/browser/tabmodel/TabModelOrderControllerImpl.java",
   "java/src/org/chromium/chrome/browser/tabmodel/TabModelSelector.java",
   "java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorBase.java",
   "java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java",
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index 7c94586..5a5960ee 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -173,6 +173,13 @@
       support_zh_hk = true
     }
 
+    # Android supports webp transparent resources properly since API level 18,
+    # so this can only be activated for modern ones (which target API >= 21).
+    if (!defined(png_to_webp)) {
+      png_to_webp = !is_java_debug
+    }
+
+    # Removes metadata needed for Resources.getIdentifier("resource_name").
     strip_resource_names = !is_java_debug
 
     # TODO(753402): enable once aapt2>=3.6.0 and bundletool>0.9.0 are rolled in.
@@ -449,7 +456,6 @@
       if (is_monochrome) {
         proguard_configs += [ "//android_webview/apk/java/proguard.flags" ]
       }
-      png_to_webp = true
     }
 
     if (!defined(deps)) {
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni
index 2011387..e6017f7 100644
--- a/chrome/android/chrome_test_java_sources.gni
+++ b/chrome/android/chrome_test_java_sources.gni
@@ -45,6 +45,7 @@
   "javatests/src/org/chromium/chrome/browser/TabsTest.java",
   "javatests/src/org/chromium/chrome/browser/UrlSchemeTest.java",
   "javatests/src/org/chromium/chrome/browser/VideoFullscreenOrientationLockChromeTest.java",
+  "javatests/src/org/chromium/chrome/browser/ViewHighlighterTestUtils.java",
   "javatests/src/org/chromium/chrome/browser/WarmupManagerTest.java",
   "javatests/src/org/chromium/chrome/browser/accessibility/FontSizePrefsTest.java",
   "javatests/src/org/chromium/chrome/browser/appmenu/AppMenuTest.java",
@@ -499,6 +500,8 @@
   "javatests/src/org/chromium/chrome/browser/webapps/ActivityAssignerTest.java",
   "javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenDialogTest.java",
   "javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenManagerTest.java",
+  "javatests/src/org/chromium/chrome/browser/webapps/WebApkActivityTest.java",
+  "javatests/src/org/chromium/chrome/browser/webapps/WebApkActivityTestRule.java",
   "javatests/src/org/chromium/chrome/browser/webapps/WebApkIntegrationTest.java",
   "javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcherTest.java",
   "javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java",
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedConfiguration.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedConfiguration.java
index e9be526..e0c52b0 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedConfiguration.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedConfiguration.java
@@ -46,6 +46,10 @@
     /** Default value for initial non cached page size. */
     public static final long INITIAL_NON_CACHED_PAGE_SIZE_DEFAULT = 10;
 
+    private static final String LIMIT_PAGE_UPDATES_IN_HEAD = "limit_page_updates_in_head";
+    /** Default value for whether to update HEAD when making a page request. */
+    public static final boolean LIMIT_PAGE_UPDATES_IN_HEAD_DEFAULT = false;
+
     private static final String LOGGING_IMMEDIATE_CONTENT_THRESHOLD_MS =
             "logging_immediate_content_threshold_ms";
     /** Default value for logging immediate content threshold. */
@@ -151,6 +155,14 @@
                 (int) INITIAL_NON_CACHED_PAGE_SIZE_DEFAULT);
     }
 
+    /** @return Whether to update HEAD when making a page request. */
+    @VisibleForTesting
+    static boolean getLimitPageUpdatesInHead() {
+        return ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean(
+                ChromeFeatureList.INTEREST_FEED_CONTENT_SUGGESTIONS, LIMIT_PAGE_UPDATES_IN_HEAD,
+                LIMIT_PAGE_UPDATES_IN_HEAD_DEFAULT);
+    }
+
     /**
      * @return How long before showing content after opening NTP is no longer considered immediate
      *         in UMA.
@@ -290,6 +302,8 @@
                 .put(ConfigKey.FEED_UI_ENABLED, FeedConfiguration.getFeedUiEnabled())
                 .put(ConfigKey.INITIAL_NON_CACHED_PAGE_SIZE,
                         FeedConfiguration.getInitialNonCachedPageSize())
+                .put(ConfigKey.LIMIT_PAGE_UPDATES_IN_HEAD,
+                        FeedConfiguration.getLimitPageUpdatesInHead())
                 .put(ConfigKey.LOGGING_IMMEDIATE_CONTENT_THRESHOLD_MS,
                         FeedConfiguration.getLoggingImmediateContentThresholdMs())
                 .put(ConfigKey.MANAGE_INTERESTS_ENABLED,
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/NtpStreamLifecycleManager.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/NtpStreamLifecycleManager.java
index 6d60a681c..48adcec2 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/NtpStreamLifecycleManager.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/NtpStreamLifecycleManager.java
@@ -5,9 +5,9 @@
 package org.chromium.chrome.browser.feed;
 
 import android.app.Activity;
+import android.support.annotation.Nullable;
 
 import com.google.android.libraries.feed.api.client.stream.Stream;
-import com.sun.istack.internal.Nullable;
 
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.ntp.NewTabPage;
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/StreamLifecycleManager.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/StreamLifecycleManager.java
index 5c453ce..550fed8 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/StreamLifecycleManager.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/StreamLifecycleManager.java
@@ -6,9 +6,9 @@
 
 import android.app.Activity;
 import android.support.annotation.IntDef;
+import android.support.annotation.Nullable;
 
 import com.google.android.libraries.feed.api.client.stream.Stream;
-import com.sun.istack.internal.Nullable;
 
 import org.chromium.base.ActivityState;
 import org.chromium.base.ApplicationStatus;
diff --git a/chrome/android/java/res/drawable/ic_error_blue_18dp.xml b/chrome/android/java/res/drawable/ic_error_blue_18dp.xml
new file mode 100644
index 0000000..75c86e6
--- /dev/null
+++ b/chrome/android/java/res/drawable/ic_error_blue_18dp.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2019 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:tools="http://schemas.android.com/tools"
+        tools:targetApi="21"
+        android:width="18dp"
+        android:height="18dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:pathData="M24 4C12.96 4 4 12.95 4 24s8.96 20 20 20 20-8.95 20-20S35.04 4 24 4zm2 30h-4v-4h4v4zm0-8h-4V14h4v12z"
+        android:fillColor="@color/default_icon_color_blue"/>
+</vector>
diff --git a/chrome/android/java/res/layout/sms_receiver_dialog.xml b/chrome/android/java/res/layout/sms_receiver_dialog.xml
index 6e9208f..aa402a4 100644
--- a/chrome/android/java/res/layout/sms_receiver_dialog.xml
+++ b/chrome/android/java/res/layout/sms_receiver_dialog.xml
@@ -38,6 +38,13 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content" >
             <ImageView
+                android:id="@+id/error_icon"
+                android:layout_height="20dp"
+                android:layout_width="20dp"
+                android:visibility="gone"
+                app:srcCompat="@drawable/ic_error_blue_18dp"
+                tools:ignore="ContentDescription" />
+            <ImageView
                 android:id="@+id/done_icon"
                 android:layout_height="20dp"
                 android:layout_width="20dp"
@@ -70,11 +77,11 @@
         app:stackedMargin="@dimen/button_bar_stacked_margin"
         app:buttonAlignment="end">
         <org.chromium.ui.widget.ButtonCompat
-            android:id="@+id/confirm_button"
+            android:id="@+id/confirm_or_try_again_button"
             android:layout_height="wrap_content"
             android:layout_width="wrap_content"
             android:layout_gravity="end"
-            android:text="@string/sms_dialog_confirm_button_text"
+            android:text="@string/confirm"
             android:enabled="false"
             style="@style/TextButton" />
         <org.chromium.ui.widget.ButtonCompat
diff --git a/chrome/android/java/res/values/colors.xml b/chrome/android/java/res/values/colors.xml
index faf144d7..be8b661 100644
--- a/chrome/android/java/res/values/colors.xml
+++ b/chrome/android/java/res/values/colors.xml
@@ -85,9 +85,9 @@
 
     <!-- Compositor Tab Colors -->
     <color name="compositor_background_tab_bg">@color/modern_grey_300</color>
-    <color name="compositor_background_tab_bg_incognito">#2A2D2F</color>
+    <color name="compositor_background_tab_bg_incognito">@color/modern_grey_900</color>
     <color name="compositor_background_tab_outline">#ACB1B6</color>
-    <color name="compositor_background_tab_outline_incognito">#0E0F10</color>
+    <color name="compositor_background_tab_outline_incognito">@android:color/black</color>
 
     <!-- Compositor Tab Title Colors -->
     <color name="compositor_tab_title_bar_text">@color/default_text_color</color>
@@ -125,11 +125,11 @@
     <color name="progress_bar_background">#3D4386F7</color>
 
     <!-- Incognito background and branding colors -->
-    <color name="incognito_modern_primary_color">@color/modern_grey_800</color>
+    <color name="incognito_modern_primary_color">@color/default_bg_color_dark_elev_3</color>
 
     <!-- Toolbar colors -->
     <color name="toolbar_background_primary">@color/default_bg_color_elev_3</color>
-    <color name="toolbar_background_primary_incognito">@color/modern_grey_800</color>
+    <color name="toolbar_background_primary_incognito">@color/default_bg_color_dark_elev_3</color>
     <color name="toolbar_text_box_background">@color/modern_grey_100</color>
     <color name="toolbar_text_box_background_incognito">@color/black_alpha_38</color>
     <color name="toolbar_shadow_color">@color/black_alpha_11</color>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/DeviceConditions.java b/chrome/android/java/src/org/chromium/chrome/browser/DeviceConditions.java
index c8dd1db..1697fc1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/DeviceConditions.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/DeviceConditions.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser;
 
 import android.annotation.TargetApi;
+import android.app.KeyguardManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -14,6 +15,7 @@
 import android.os.Build;
 import android.os.PowerManager;
 
+import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.net.ConnectionType;
 import org.chromium.net.NetworkChangeNotifier;
@@ -27,6 +29,7 @@
     private boolean mPowerConnected;
     private int mBatteryPercentage;
     private boolean mPowerSaveOn;
+    private boolean mScreenOnAndUnlocked;
 
     // Network related variables.
     private @ConnectionType int mNetConnectionType = ConnectionType.CONNECTION_UNKNOWN;
@@ -42,12 +45,13 @@
      */
     @VisibleForTesting
     public DeviceConditions(boolean powerConnected, int batteryPercentage, int netConnectionType,
-            boolean powerSaveOn, boolean activeNetworkMetered) {
+            boolean powerSaveOn, boolean activeNetworkMetered, boolean screenOnAndUnlocked) {
         mPowerConnected = powerConnected;
         mBatteryPercentage = batteryPercentage;
         mPowerSaveOn = powerSaveOn;
         mNetConnectionType = netConnectionType;
         mActiveNetworkMetered = activeNetworkMetered;
+        mScreenOnAndUnlocked = screenOnAndUnlocked;
     }
 
     @VisibleForTesting
@@ -64,7 +68,7 @@
         return new DeviceConditions(isCurrentlyPowerConnected(context, batteryStatus),
                 getCurrentBatteryPercentage(context, batteryStatus),
                 getCurrentNetConnectionType(context), isCurrentlyInPowerSaveMode(context),
-                isCurrentActiveNetworkMetered(context));
+                isCurrentActiveNetworkMetered(context), isCurrentlyScreenOnAndUnlocked(context));
     }
 
     /** @return Whether the device is connected to a power source. */
@@ -173,6 +177,16 @@
         return cm.isActiveNetworkMetered();
     }
 
+    /**
+     * @return Whether the screen is currently on and unlocked.
+     */
+    public static boolean isCurrentlyScreenOnAndUnlocked(Context context) {
+        KeyguardManager keyguardManager =
+                (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
+        return keyguardManager != null && !keyguardManager.isKeyguardLocked()
+                && ApiCompatibilityUtils.isInteractive(context);
+    }
+
     private static Intent getBatteryStatus(Context context) {
         IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
         // Note this is a sticky intent, so we aren't really registering a receiver, just getting
@@ -232,4 +246,9 @@
     public boolean isActiveNetworkMetered() {
         return mActiveNetworkMetered;
     }
+
+    /** Returns whether the screen is on and unlocked. */
+    public boolean isScreenOnAndUnlocked() {
+        return mScreenOnAndUnlocked;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/SingleTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/SingleTabActivity.java
index 845ffde..aa9378bd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/SingleTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/SingleTabActivity.java
@@ -50,12 +50,12 @@
     }
 
     @Override
-    protected Pair<TabDelegate, TabDelegate> createTabCreators() {
-        return Pair.create(createTabDelegate(false), createTabDelegate(true));
+    protected Pair<? extends TabCreator, ? extends TabCreator> createTabCreators() {
+        return Pair.create(createTabCreator(false), createTabCreator(true));
     }
 
     /** Creates TabDelegates for opening new Tabs. */
-    protected TabDelegate createTabDelegate(boolean incognito) {
+    protected TabCreator createTabCreator(boolean incognito) {
         return new TabDelegate(incognito);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTab.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTab.java
index 8681b2b..2c291d9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTab.java
@@ -274,7 +274,8 @@
         int tint = mIncognito ? R.color.compositor_background_tab_bg_incognito
                               : R.color.compositor_background_tab_bg;
         if (foreground) {
-            tint = mIncognito ? R.color.modern_grey_800 : R.color.default_bg_color_elev_3;
+            tint = mIncognito ? R.color.default_bg_color_dark_elev_3
+                              : R.color.default_bg_color_elev_3;
         }
 
         return mContext.getResources().getColor(tint);
@@ -288,7 +289,8 @@
         int tint = mIncognito ? R.color.compositor_background_tab_outline_incognito
                               : R.color.compositor_background_tab_outline;
         if (foreground) {
-            tint = mIncognito ? R.color.modern_grey_800 : R.color.default_bg_color_elev_3;
+            tint = mIncognito ? R.color.default_bg_color_dark_elev_3
+                              : R.color.default_bg_color_elev_3;
         }
 
         return mContext.getResources().getColor(tint);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java
index 65741685..3130563 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java
@@ -13,7 +13,6 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.annotations.CalledByNative;
-import org.chromium.base.metrics.CachedMetrics;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.notifications.NotificationConstants;
 import org.chromium.chrome.browser.notifications.NotificationUmaTracker;
@@ -41,9 +40,8 @@
                 dialIntent = new Intent(Intent.ACTION_DIAL);
             }
             dialIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            ContextUtils.getApplicationContext().startActivity(dialIntent);
-            new CachedMetrics.BooleanHistogramSample("Sharing.ClickToCallDialIntent")
-                    .record(TextUtils.isEmpty(phoneNumber));
+            context.startActivity(dialIntent);
+            ClickToCallUma.recordDialerShown(TextUtils.isEmpty(phoneNumber));
         }
     }
 
@@ -54,6 +52,7 @@
      */
     @CalledByNative
     private static void showNotification(String phoneNumber) {
+        ClickToCallUma.recordMessageReceived();
         Context context = ContextUtils.getApplicationContext();
         PendingIntentProvider contentIntent = PendingIntentProvider.getBroadcast(context,
                 /*requestCode=*/0,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallUma.java b/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallUma.java
new file mode 100644
index 0000000..0a0fe0b
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallUma.java
@@ -0,0 +1,122 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.sharing.click_to_call;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.support.annotation.IntDef;
+import android.support.annotation.MainThread;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
+
+import org.chromium.base.ApplicationStatus;
+import org.chromium.base.ContextUtils;
+import org.chromium.base.metrics.CachedMetrics;
+import org.chromium.chrome.browser.DeviceConditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Helper Class for Click to Call UMA Collection.
+ */
+public class ClickToCallUma {
+    // Keep in sync with the ClickToCallDeviceState enum in enums.xml.
+    @IntDef({ClickToCallDeviceState.SCREEN_OFF_BACKGROUND,
+            ClickToCallDeviceState.SCREEN_ON_BACKGROUND,
+            ClickToCallDeviceState.SCREEN_OFF_FOREGROUND,
+            ClickToCallDeviceState.SCREEN_ON_FOREGROUND})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface ClickToCallDeviceState {
+        int SCREEN_OFF_BACKGROUND = 0;
+        int SCREEN_ON_BACKGROUND = 1;
+        int SCREEN_OFF_FOREGROUND = 2;
+        int SCREEN_ON_FOREGROUND = 3;
+        int NUM_ENTRIES = 4;
+    }
+
+    private static @ClickToCallDeviceState int getDeviceState(Context context) {
+        boolean isScreenOn = DeviceConditions.isCurrentlyScreenOnAndUnlocked(context);
+        boolean isInForeground = ApplicationStatus.hasVisibleActivities();
+
+        if (isInForeground) {
+            return isScreenOn ? ClickToCallDeviceState.SCREEN_ON_FOREGROUND
+                              : ClickToCallDeviceState.SCREEN_OFF_FOREGROUND;
+        } else {
+            return isScreenOn ? ClickToCallDeviceState.SCREEN_ON_BACKGROUND
+                              : ClickToCallDeviceState.SCREEN_OFF_BACKGROUND;
+        }
+    }
+
+    /**
+     * Listens for outgoing phone calls for TIMEOUT_MS and adds metrics if there was one within that
+     * time frame. This is only used to measure successful usages of the Click to Call feature and
+     * does not contain any data other than the time it took from opening the dialer to a call being
+     * initiated.
+     */
+    private static final class CallMetricListener extends PhoneStateListener {
+        // Maximum time we wait for an outgoing call to be made.
+        private static final long TIMEOUT_MS = 30000;
+
+        // Current instance of a registered listener, or null if none running.
+        private static CallMetricListener sListener;
+
+        private final Handler mHandler = new Handler();
+        private final Runnable mTimeoutRunnable = this::stopMetric;
+        private final long mDialerOpenTime = SystemClock.uptimeMillis();
+        private final TelephonyManager mTelephonyManager;
+
+        private CallMetricListener(Context context) {
+            mTelephonyManager =
+                    (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+            mTelephonyManager.listen(this, PhoneStateListener.LISTEN_CALL_STATE);
+            mHandler.postDelayed(mTimeoutRunnable, TIMEOUT_MS);
+        }
+
+        @Override
+        public void onCallStateChanged(int state, String number) {
+            // Note: |number| will always be empty as we don't have permissions to read it.
+            if (sListener != this || state != TelephonyManager.CALL_STATE_OFFHOOK) return;
+
+            // Record successful Click to Call journey and the time it took to initiate a call.
+            recordCallMade(SystemClock.uptimeMillis() - mDialerOpenTime);
+
+            stopMetric();
+        }
+
+        @MainThread
+        public static void startMetric(Context context) {
+            if (sListener != null) sListener.stopMetric();
+            sListener = new CallMetricListener(context);
+        }
+
+        @MainThread
+        private void stopMetric() {
+            if (sListener != this) return;
+            mHandler.removeCallbacks(mTimeoutRunnable);
+            mTelephonyManager.listen(this, PhoneStateListener.LISTEN_NONE);
+            sListener = null;
+        }
+    }
+
+    private static void recordCallMade(long timeFromDialerToCallMs) {
+        new CachedMetrics.MediumTimesHistogramSample("Sharing.ClickToCallPhoneCall")
+                .record(timeFromDialerToCallMs);
+    }
+
+    public static void recordDialerShown(boolean emptyPhoneNumber) {
+        CallMetricListener.startMetric(ContextUtils.getApplicationContext());
+        new CachedMetrics.BooleanHistogramSample("Sharing.ClickToCallDialIntent")
+                .record(emptyPhoneNumber);
+    }
+
+    public static void recordMessageReceived() {
+        new CachedMetrics
+                .EnumeratedHistogramSample(
+                        "Sharing.ClickToCallReceiveDeviceState", ClickToCallDeviceState.NUM_ENTRIES)
+                .record(getDeviceState(ContextUtils.getApplicationContext()));
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sms/SmsReceiverDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/sms/SmsReceiverDialog.java
index 66c8ba7..daef54a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sms/SmsReceiverDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sms/SmsReceiverDialog.java
@@ -23,6 +23,7 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.NativeMethods;
 import org.chromium.chrome.R;
+import org.chromium.content_public.browser.sms.Event;
 import org.chromium.ui.base.WindowAndroid;
 
 /**
@@ -38,8 +39,10 @@
     private Dialog mDialog;
     private ProgressBar mProgressBar;
     private ImageView mDoneIcon;
+    private ImageView mErrorIcon;
     private TextView mStatus;
-    private Button mConfirmButton;
+    private Button mCancelButton;
+    private Button mConfirmOrTryAgainButton;
     private String mOrigin;
 
     @VisibleForTesting
@@ -67,18 +70,21 @@
 
         mDoneIcon = (ImageView) dialogContainer.findViewById(R.id.done_icon);
 
+        mErrorIcon = (ImageView) dialogContainer.findViewById(R.id.error_icon);
+
         mStatus = (TextView) dialogContainer.findViewById(R.id.status);
 
-        Button cancelButton = (Button) dialogContainer.findViewById(R.id.cancel_button);
-        cancelButton.setOnClickListener(v -> {
+        mCancelButton = (Button) dialogContainer.findViewById(R.id.cancel_button);
+        mCancelButton.setOnClickListener(v -> {
             assert mNativeSmsDialogAndroid != 0;
-            SmsReceiverDialogJni.get().onCancel(mNativeSmsDialogAndroid);
+            SmsReceiverDialogJni.get().onEvent(mNativeSmsDialogAndroid, Event.CANCEL);
         });
 
-        mConfirmButton = (Button) dialogContainer.findViewById(R.id.confirm_button);
-        mConfirmButton.setOnClickListener(v -> {
+        mConfirmOrTryAgainButton =
+                (Button) dialogContainer.findViewById(R.id.confirm_or_try_again_button);
+        mConfirmOrTryAgainButton.setOnClickListener(v -> {
             assert mNativeSmsDialogAndroid != 0;
-            SmsReceiverDialogJni.get().onConfirm(mNativeSmsDialogAndroid);
+            SmsReceiverDialogJni.get().onEvent(mNativeSmsDialogAndroid, Event.CONFIRM);
         });
 
         mDialog = new Dialog(mActivity);
@@ -131,7 +137,23 @@
         mProgressBar.setVisibility(View.GONE);
         mDoneIcon.setVisibility(View.VISIBLE);
         mStatus.setText(mActivity.getText(R.string.sms_dialog_status_sms_received));
-        mConfirmButton.setEnabled(true);
+        mConfirmOrTryAgainButton.setEnabled(true);
+    }
+
+    @CalledByNative
+    void smsTimeout() {
+        if (DEBUG) Log.d(TAG, "SmsReceiverDialog.smsTimeout()");
+
+        mProgressBar.setVisibility(View.GONE);
+        mErrorIcon.setVisibility(View.VISIBLE);
+        mStatus.setText(mActivity.getText(R.string.sms_dialog_status_timeout));
+        mCancelButton.setVisibility(View.GONE);
+        mConfirmOrTryAgainButton.setText(mActivity.getText(R.string.try_again));
+        mConfirmOrTryAgainButton.setEnabled(true);
+        mConfirmOrTryAgainButton.setOnClickListener(v -> {
+            assert mNativeSmsDialogAndroid != 0;
+            SmsReceiverDialogJni.get().onEvent(mNativeSmsDialogAndroid, Event.TIMEOUT);
+        });
     }
 
     /**
@@ -149,7 +171,6 @@
 
     @NativeMethods
     interface Natives {
-        void onCancel(long nativeSmsDialogAndroid);
-        void onConfirm(long nativeSmsDialogAndroid);
+        void onEvent(long nativeSmsDialogAndroid, int eventType);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/SingleTabModel.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/SingleTabModel.java
index b1140bd..22e08e19 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/SingleTabModel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/SingleTabModel.java
@@ -77,6 +77,7 @@
 
     @Override
     public int indexOf(Tab tab) {
+        if (tab == null) return INVALID_TAB_INDEX;
         return mTab != null && mTab.getId() == tab.getId() ? 0 : INVALID_TAB_INDEX;
     }
 
@@ -190,7 +191,9 @@
     }
 
     @Override
-    public void addTab(Tab tab, int index, @TabLaunchType int type) {}
+    public void addTab(Tab tab, int index, @TabLaunchType int type) {
+        setTab(tab);
+    }
 
     @Override
     public void removeTab(Tab tab) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelOrderController.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelOrderController.java
index 8dfec2e..5a08a019 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelOrderController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelOrderController.java
@@ -1,26 +1,15 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-
 package org.chromium.chrome.browser.tabmodel;
 
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.tab.TabAttributeKeys;
-import org.chromium.chrome.browser.tab.TabAttributes;
 
 /**
  * This class acts as a controller for determining where tabs should be inserted
- * into a tab strip model. See tab_strip_model_order_controller.cc and
- * tab_strip_model.cc
+ * into a tab strip model.
  */
-public class TabModelOrderController {
-    private static final int NO_TAB = -1;
-    private final TabModelSelector mTabModelSelector;
-
-    public TabModelOrderController(TabModelSelector modelSelector) {
-        mTabModelSelector = modelSelector;
-    }
-
+public interface TabModelOrderController {
     /**
      * Determine the insertion index of the next tab. If it's not the result of
      * a link being pressed, the provided index will be returned.
@@ -29,20 +18,7 @@
      * @param position The provided position.
      * @return Where to insert the tab.
      */
-    public int determineInsertionIndex(@TabLaunchType int type, int position, Tab newTab) {
-        if (type == TabLaunchType.FROM_BROWSER_ACTIONS) return -1;
-        if (linkClicked(type)) {
-            position = determineInsertionIndex(type, newTab);
-        }
-
-        if (willOpenInForeground(type, newTab.isIncognito())) {
-            // Forget any existing relationships, we don't want to make things
-            // too confusing by having multiple groups active at the same time.
-            forgetAllOpeners();
-        }
-
-        return position;
-    }
+    int determineInsertionIndex(@TabLaunchType int type, int position, Tab newTab);
 
     /**
      * Determine the insertion index of the next tab.
@@ -50,88 +26,7 @@
      * @param type The launch type of the new tab.
      * @return Where to insert the tab.
      */
-    public int determineInsertionIndex(@TabLaunchType int type, Tab newTab) {
-        TabModel currentModel = mTabModelSelector.getCurrentModel();
-
-        if (sameModelType(currentModel, newTab)) {
-            Tab currentTab = TabModelUtils.getCurrentTab(currentModel);
-            if (currentTab == null) {
-                assert (currentModel.getCount() == 0);
-                return 0;
-            }
-            int currentId = currentTab.getId();
-            int currentIndex = TabModelUtils.getTabIndexById(currentModel, currentId);
-
-            if (willOpenInForeground(type, newTab.isIncognito())) {
-                // If the tab was opened in the foreground, insert it adjacent to its parent tab if
-                // that exists and that tab is not the current selected tab, else insert the tab
-                // adjacent to the current tab that opened that link.
-                Tab parentTab = TabModelUtils.getTabById(currentModel, newTab.getParentId());
-                if (parentTab != null && currentTab != parentTab) {
-                    int parentTabIndex =
-                            TabModelUtils.getTabIndexById(currentModel, parentTab.getId());
-                    return parentTabIndex + 1;
-                }
-                return currentIndex + 1;
-            } else {
-                // If the tab was opened in the background, position at the end of
-                // it's 'group'.
-                int index = getIndexOfLastTabOpenedBy(currentId, currentIndex);
-                if (index != NO_TAB) {
-                    return index + 1;
-                } else {
-                    return currentIndex + 1;
-                }
-            }
-        } else {
-            // If the tab is opening in the other model type, just put it at the end.
-            return mTabModelSelector.getModel(newTab.isIncognito()).getCount();
-        }
-    }
-
-    /**
-     * Returns the index of the last tab in the model opened by the specified
-     * opener, starting at startIndex. To clarify, the tabs are traversed in the
-     * descending order of their position in the model. This means that the tab
-     * furthest in the stack with the given opener id will be returned.
-     *
-     * @param openerId The opener of interest.
-     * @param startIndex The start point of the search.
-     * @return The last tab if found, NO_TAB otherwise.
-     */
-    private int getIndexOfLastTabOpenedBy(int openerId, int startIndex) {
-        TabModel currentModel = mTabModelSelector.getCurrentModel();
-        int count = currentModel.getCount();
-        for (int i = count - 1; i >= startIndex; i--) {
-            Tab tab = currentModel.getTabAt(i);
-            if (tab.getParentId() == openerId
-                    && TabAttributes.from(tab).get(TabAttributeKeys.GROUPED_WITH_PARENT, true)) {
-                return i;
-            }
-        }
-        return NO_TAB;
-    }
-
-    /**
-     * Clear the opener attribute on all tabs in the model.
-     */
-    void forgetAllOpeners() {
-        TabModel currentModel = mTabModelSelector.getCurrentModel();
-        int count = currentModel.getCount();
-        for (int i = 0; i < count; i++) {
-            TabAttributes.from(currentModel.getTabAt(i))
-                    .set(TabAttributeKeys.GROUPED_WITH_PARENT, false);
-        }
-    }
-
-    /**
-     * Determine if a launch type is the result of linked being clicked.
-     */
-    static boolean linkClicked(@TabLaunchType int type) {
-        return type == TabLaunchType.FROM_LINK
-                || type == TabLaunchType.FROM_LONGPRESS_FOREGROUND
-                || type == TabLaunchType.FROM_LONGPRESS_BACKGROUND;
-    }
+    int determineInsertionIndex(@TabLaunchType int type, Tab newTab);
 
     /**
      * Determine if a launch type will result in the tab being opened in the
@@ -140,19 +35,5 @@
      * @param isNewTabIncognito  True if the new opened tab is incognito.
      * @return                   True if the tab will be in the foreground
      */
-    public boolean willOpenInForeground(@TabLaunchType int type, boolean isNewTabIncognito) {
-        // Restore is handling the active index by itself.
-        if (type == TabLaunchType.FROM_RESTORE || type == TabLaunchType.FROM_BROWSER_ACTIONS) {
-            return false;
-        }
-        return type != TabLaunchType.FROM_LONGPRESS_BACKGROUND
-                || (!mTabModelSelector.isIncognitoSelected() && isNewTabIncognito);
-    }
-
-    /**
-     * @return {@code true} If both tabs have the same model type, {@code false} otherwise.
-     */
-    static boolean sameModelType(TabModel model, Tab tab) {
-        return model.isIncognito() == tab.isIncognito();
-    }
+    boolean willOpenInForeground(@TabLaunchType int type, boolean isNewTabIncognito);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelOrderControllerImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelOrderControllerImpl.java
new file mode 100644
index 0000000..6d15eb6
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelOrderControllerImpl.java
@@ -0,0 +1,138 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.tabmodel;
+
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tab.TabAttributeKeys;
+import org.chromium.chrome.browser.tab.TabAttributes;
+
+/**
+ * Implementation of the TabModelOrderController based off of tab_strip_model_order_controller.cc
+ * and tab_strip_model.cc
+ */
+public class TabModelOrderControllerImpl implements TabModelOrderController {
+    private static final int NO_TAB = -1;
+    private final TabModelSelector mTabModelSelector;
+
+    public TabModelOrderControllerImpl(TabModelSelector modelSelector) {
+        mTabModelSelector = modelSelector;
+    }
+
+    @Override
+    public int determineInsertionIndex(@TabLaunchType int type, int position, Tab newTab) {
+        if (type == TabLaunchType.FROM_BROWSER_ACTIONS) return -1;
+        if (linkClicked(type)) {
+            position = determineInsertionIndex(type, newTab);
+        }
+
+        if (willOpenInForeground(type, newTab.isIncognito())) {
+            // Forget any existing relationships, we don't want to make things
+            // too confusing by having multiple groups active at the same time.
+            forgetAllOpeners();
+        }
+
+        return position;
+    }
+
+    @Override
+    public int determineInsertionIndex(@TabLaunchType int type, Tab newTab) {
+        TabModel currentModel = mTabModelSelector.getCurrentModel();
+
+        if (sameModelType(currentModel, newTab)) {
+            Tab currentTab = TabModelUtils.getCurrentTab(currentModel);
+            if (currentTab == null) {
+                assert (currentModel.getCount() == 0);
+                return 0;
+            }
+            int currentId = currentTab.getId();
+            int currentIndex = TabModelUtils.getTabIndexById(currentModel, currentId);
+
+            if (willOpenInForeground(type, newTab.isIncognito())) {
+                // If the tab was opened in the foreground, insert it adjacent to its parent tab if
+                // that exists and that tab is not the current selected tab, else insert the tab
+                // adjacent to the current tab that opened that link.
+                Tab parentTab = TabModelUtils.getTabById(currentModel, newTab.getParentId());
+                if (parentTab != null && currentTab != parentTab) {
+                    int parentTabIndex =
+                            TabModelUtils.getTabIndexById(currentModel, parentTab.getId());
+                    return parentTabIndex + 1;
+                }
+                return currentIndex + 1;
+            } else {
+                // If the tab was opened in the background, position at the end of
+                // it's 'group'.
+                int index = getIndexOfLastTabOpenedBy(currentId, currentIndex);
+                if (index != NO_TAB) {
+                    return index + 1;
+                } else {
+                    return currentIndex + 1;
+                }
+            }
+        } else {
+            // If the tab is opening in the other model type, just put it at the end.
+            return mTabModelSelector.getModel(newTab.isIncognito()).getCount();
+        }
+    }
+
+    /**
+     * Returns the index of the last tab in the model opened by the specified
+     * opener, starting at startIndex. To clarify, the tabs are traversed in the
+     * descending order of their position in the model. This means that the tab
+     * furthest in the stack with the given opener id will be returned.
+     *
+     * @param openerId The opener of interest.
+     * @param startIndex The start point of the search.
+     * @return The last tab if found, NO_TAB otherwise.
+     */
+    private int getIndexOfLastTabOpenedBy(int openerId, int startIndex) {
+        TabModel currentModel = mTabModelSelector.getCurrentModel();
+        int count = currentModel.getCount();
+        for (int i = count - 1; i >= startIndex; i--) {
+            Tab tab = currentModel.getTabAt(i);
+            if (tab.getParentId() == openerId
+                    && TabAttributes.from(tab).get(TabAttributeKeys.GROUPED_WITH_PARENT, true)) {
+                return i;
+            }
+        }
+        return NO_TAB;
+    }
+
+    /**
+     * Clear the opener attribute on all tabs in the model.
+     */
+    void forgetAllOpeners() {
+        TabModel currentModel = mTabModelSelector.getCurrentModel();
+        int count = currentModel.getCount();
+        for (int i = 0; i < count; i++) {
+            TabAttributes.from(currentModel.getTabAt(i))
+                    .set(TabAttributeKeys.GROUPED_WITH_PARENT, false);
+        }
+    }
+
+    /**
+     * Determine if a launch type is the result of linked being clicked.
+     */
+    static boolean linkClicked(@TabLaunchType int type) {
+        return type == TabLaunchType.FROM_LINK || type == TabLaunchType.FROM_LONGPRESS_FOREGROUND
+                || type == TabLaunchType.FROM_LONGPRESS_BACKGROUND;
+    }
+
+    @Override
+    public boolean willOpenInForeground(@TabLaunchType int type, boolean isNewTabIncognito) {
+        // Restore is handling the active index by itself.
+        if (type == TabLaunchType.FROM_RESTORE || type == TabLaunchType.FROM_BROWSER_ACTIONS) {
+            return false;
+        }
+        return type != TabLaunchType.FROM_LONGPRESS_BACKGROUND
+                || (!mTabModelSelector.isIncognitoSelected() && isNewTabIncognito);
+    }
+
+    /**
+     * @return {@code true} If both tabs have the same model type, {@code false} otherwise.
+     */
+    static boolean sameModelType(TabModel model, Tab tab) {
+        return model.isIncognito() == tab.isIncognito();
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java
index 4de1cce0..1d2506a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java
@@ -79,7 +79,7 @@
         mIsTabbedActivityForSync = isTabbedActivity;
         mTabSaver = new TabPersistentStore(
                 persistencePolicy, this, mTabCreatorManager, persistentStoreObserver);
-        mOrderController = new TabModelOrderController(this);
+        mOrderController = new TabModelOrderControllerImpl(this);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
index fc79a59..1ec7ed2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
@@ -49,7 +49,6 @@
 import org.chromium.chrome.browser.tab.TabObserver;
 import org.chromium.chrome.browser.tab.TabObserverRegistrar;
 import org.chromium.chrome.browser.tab.TabState;
-import org.chromium.chrome.browser.tabmodel.document.TabDelegate;
 import org.chromium.chrome.browser.toolbar.top.ToolbarControlContainer;
 import org.chromium.chrome.browser.util.ColorUtils;
 import org.chromium.chrome.browser.widget.TintedDrawable;
@@ -834,7 +833,7 @@
     }
 
     @Override
-    protected TabDelegate createTabDelegate(boolean incognito) {
+    protected TabCreator createTabCreator(boolean incognito) {
         return new WebappTabDelegate(incognito, mWebappInfo);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webauth/AuthenticatorImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/webauth/AuthenticatorImpl.java
index b39eea65..92fe4f1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webauth/AuthenticatorImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webauth/AuthenticatorImpl.java
@@ -40,8 +40,6 @@
             .Callback2<Integer, MakeCredentialAuthenticatorResponse> mMakeCredentialCallback;
     private org.chromium.mojo.bindings.Callbacks
             .Callback2<Integer, GetAssertionAuthenticatorResponse> mGetAssertionCallback;
-    private org.chromium.mojo.bindings.Callbacks
-            .Callback1<Boolean> mIsUserVerifyingPlatformAuthenticatorAvailableCallback;
 
     /**
      * Builds the Authenticator service implementation.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webauth/Fido2ApiHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/webauth/Fido2ApiHandler.java
index c7ba264..2a6670f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webauth/Fido2ApiHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webauth/Fido2ApiHandler.java
@@ -50,7 +50,4 @@
 
     protected void getAssertion(PublicKeyCredentialRequestOptions options,
             RenderFrameHost frameHost, HandlerResponseCallback callback) {}
-
-    protected void isUserVerifyingPlatformAuthenticatorAvailable(
-            RenderFrameHost frameHost, HandlerResponseCallback callback) {}
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webauth/HandlerResponseCallback.java b/chrome/android/java/src/org/chromium/chrome/browser/webauth/HandlerResponseCallback.java
index f90efbe6..fbd9bb1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webauth/HandlerResponseCallback.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webauth/HandlerResponseCallback.java
@@ -24,12 +24,6 @@
     public void onSignResponse(Integer status, GetAssertionAuthenticatorResponse response){};
 
     /**
-     * Callback for handling response from a request to call
-     * isUserVerifyingPlatformAuthenticatorAvailable.
-     */
-    public void onIsUserVerifyingPlatformAuthenticatorAvailableResponse(boolean isUVPAA){};
-
-    /**
      * Callback for handling any errors from either register or sign requests.
      */
     public void onError(Integer status){};
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/PulseDrawable.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/PulseDrawable.java
index 546be1fb..c87b5f88 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/PulseDrawable.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/PulseDrawable.java
@@ -199,8 +199,7 @@
     public void setUseLightPulseColor(Resources resources, boolean useLightPulseColor) {
         @ColorInt
         int color = ApiCompatibilityUtils.getColor(resources,
-                useLightPulseColor ? R.color.modern_secondary_color
-                                   : R.color.default_icon_color_blue);
+                useLightPulseColor ? R.color.modern_blue_300 : R.color.default_icon_color_blue);
         if (mState.color == color) return;
 
         int alpha = getAlpha();
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 2a6cc23..bba9ee9b 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -3966,8 +3966,8 @@
       <message name="IDS_SMS_DIALOG_STATUS_SMS_RECEIVED" desc="Message shown when Chrome has received an SMS on the user's behalf">
         Text message received
       </message>
-      <message name="IDS_SMS_DIALOG_CONFIRM_BUTTON_TEXT" desc="Label on the button that users can click to confirm SMS verification by passing the incoming SMS to the site.">
-        Confirm
+      <message name="IDS_SMS_DIALOG_STATUS_TIMEOUT" desc="Message shown when SMS verification timed out.">
+        Something went wrong
       </message>
 
       <message name="IDS_TEST_DUMMY_MODULE_TITLE"
diff --git a/chrome/android/java/strings/android_chrome_strings_grd/IDS_SMS_DIALOG_CONFIRM_BUTTON_TEXT.png.sha1 b/chrome/android/java/strings/android_chrome_strings_grd/IDS_SMS_DIALOG_CONFIRM_BUTTON_TEXT.png.sha1
deleted file mode 100644
index 4196c98..0000000
--- a/chrome/android/java/strings/android_chrome_strings_grd/IDS_SMS_DIALOG_CONFIRM_BUTTON_TEXT.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-3851b10baa9e6cd314477667cdac69e549ba2e52
\ No newline at end of file
diff --git a/chrome/android/java/strings/android_chrome_strings_grd/IDS_SMS_DIALOG_STATUS_SMS_RECEIVED.png.sha1 b/chrome/android/java/strings/android_chrome_strings_grd/IDS_SMS_DIALOG_STATUS_SMS_RECEIVED.png.sha1
index 4196c98..b9364de 100644
--- a/chrome/android/java/strings/android_chrome_strings_grd/IDS_SMS_DIALOG_STATUS_SMS_RECEIVED.png.sha1
+++ b/chrome/android/java/strings/android_chrome_strings_grd/IDS_SMS_DIALOG_STATUS_SMS_RECEIVED.png.sha1
@@ -1 +1 @@
-3851b10baa9e6cd314477667cdac69e549ba2e52
\ No newline at end of file
+3851b10baa9e6cd314477667cdac69e549ba2e52
diff --git a/chrome/android/java/strings/android_chrome_strings_grd/IDS_SMS_DIALOG_STATUS_TIMEOUT.png.sha1 b/chrome/android/java/strings/android_chrome_strings_grd/IDS_SMS_DIALOG_STATUS_TIMEOUT.png.sha1
new file mode 100644
index 0000000..930e31f
--- /dev/null
+++ b/chrome/android/java/strings/android_chrome_strings_grd/IDS_SMS_DIALOG_STATUS_TIMEOUT.png.sha1
@@ -0,0 +1 @@
+06b38a1c7e0379eb1a4407829baf8b8300c74744
\ No newline at end of file
diff --git a/chrome/android/java/strings/android_chrome_strings_grd/IDS_SMS_DIALOG_STATUS_WAITING.png.sha1 b/chrome/android/java/strings/android_chrome_strings_grd/IDS_SMS_DIALOG_STATUS_WAITING.png.sha1
index eb85055..c97e8c0 100644
--- a/chrome/android/java/strings/android_chrome_strings_grd/IDS_SMS_DIALOG_STATUS_WAITING.png.sha1
+++ b/chrome/android/java/strings/android_chrome_strings_grd/IDS_SMS_DIALOG_STATUS_WAITING.png.sha1
@@ -1 +1 @@
-9a38cd3599c74c36b46f3bf4edf565fa8280eb9d
\ No newline at end of file
+9a38cd3599c74c36b46f3bf4edf565fa8280eb9d
diff --git a/chrome/android/java/strings/android_chrome_strings_grd/IDS_SMS_DIALOG_TITLE.png.sha1 b/chrome/android/java/strings/android_chrome_strings_grd/IDS_SMS_DIALOG_TITLE.png.sha1
index 5776234..c97e8c0 100644
--- a/chrome/android/java/strings/android_chrome_strings_grd/IDS_SMS_DIALOG_TITLE.png.sha1
+++ b/chrome/android/java/strings/android_chrome_strings_grd/IDS_SMS_DIALOG_TITLE.png.sha1
@@ -1 +1 @@
-ef2666b60a9adfb774b327ecec89f1ef090a78a4
\ No newline at end of file
+9a38cd3599c74c36b46f3bf4edf565fa8280eb9d
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ServicificationBackgroundServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ServicificationBackgroundServiceTest.java
index 44da274..80b96eb 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ServicificationBackgroundServiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ServicificationBackgroundServiceTest.java
@@ -19,6 +19,7 @@
 import org.chromium.base.Log;
 import org.chromium.base.StrictModeContext;
 import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.RetryOnFailure;
 import org.chromium.chrome.browser.init.ServiceManagerStartupUtils;
@@ -118,6 +119,7 @@
     @Test
     @LargeTest
     @Feature({"ServicificationStartup"})
+    @CommandLineFlags.Add("force-fieldtrials=*Foo/Bar")
     public void testHistogramsPersistedWithServiceManagerOnlyStart() {
         createBrowserMetricsSpareFile();
         Assert.assertTrue(mSpareFile.exists());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ViewHighlighterTestUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ViewHighlighterTestUtils.java
new file mode 100644
index 0000000..bc27f18
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ViewHighlighterTestUtils.java
@@ -0,0 +1,43 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser;
+
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.view.View;
+
+import org.chromium.chrome.browser.widget.PulseDrawable;
+
+/**
+ * Allows for testing of views which are highlightable via ViewHighlighter.
+ */
+public class ViewHighlighterTestUtils {
+    /**
+     * Returns true if the provided view is currently being highlighted.
+     * Please note that this function may not be the same as !checkHighlightOff.
+     *
+     * @param view The view which you'd like to check for highlighting.
+     * @return True if the view is currently being highlighted.
+     */
+    public static boolean checkHighlightOn(View view) {
+        if (!(view.getBackground() instanceof LayerDrawable)) return false;
+        LayerDrawable layerDrawable = (LayerDrawable) view.getBackground();
+        Drawable drawable = layerDrawable.getDrawable(layerDrawable.getNumberOfLayers() - 1);
+        if (!(drawable instanceof PulseDrawable)) return false;
+        PulseDrawable pulse = (PulseDrawable) drawable;
+        return pulse.isRunning() && pulse.isVisible();
+    }
+
+    /**
+     * Returns true if the provided view is not currently being highlighted.
+     * Please note that this function may not be the same as !checkHighlightOn.
+     *
+     * @param view The view which you'd like to check for highlighting.
+     * @return True if view is not currently being highlighted.
+     */
+    public static boolean checkHighlightOff(View view) {
+        return !(view.getBackground() instanceof LayerDrawable);
+    }
+}
\ No newline at end of file
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkReorderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkReorderTest.java
index eb54238..ec4ea21 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkReorderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkReorderTest.java
@@ -9,6 +9,9 @@
 import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
 import static android.support.test.espresso.matcher.ViewMatchers.withText;
 
+import static org.chromium.chrome.browser.ViewHighlighterTestUtils.checkHighlightOff;
+import static org.chromium.chrome.browser.ViewHighlighterTestUtils.checkHighlightOn;
+
 import android.support.test.filters.MediumTest;
 import android.support.v7.widget.RecyclerView.ViewHolder;
 import android.view.View;
@@ -604,6 +607,144 @@
                 "Expected \"Other Bookmarks\" folder to appear!", 2, adapter.getItemCount());
     }
 
+    @Test
+    @MediumTest
+    public void testShowInFolder_NoScroll() throws Exception {
+        addFolder(TEST_FOLDER_TITLE);
+        forceSyncHeaderState();
+        openBookmarkManager();
+
+        // Enter search mode.
+        View searchButton = mManager.getToolbarForTests().findViewById(R.id.search_menu_id);
+        TestThreadUtils.runOnUiThreadBlocking(searchButton::performClick);
+        CriteriaHelper.pollUiThread(
+                () -> mManager.getToolbarForTests().isSearching(), "Expected to enter search mode");
+
+        // Click "Show in folder".
+        View testFolder = mItemsContainer.findViewHolderForAdapterPosition(0).itemView;
+        View more = testFolder.findViewById(R.id.more);
+        Assert.assertEquals("Wrong bookmark item selected.", TEST_FOLDER_TITLE,
+                ((BookmarkFolderRow) testFolder).getTitle());
+        TestThreadUtils.runOnUiThreadBlocking(more::performClick);
+        onView(withText("Show in folder")).perform(click());
+
+        Assert.assertTrue(
+                "Expected bookmark row to be highlighted after clicking \"show in folder\"",
+                checkHighlightOn(testFolder));
+
+        // Enter search mode again.
+        searchButton = mManager.getToolbarForTests().findViewById(R.id.search_menu_id);
+        TestThreadUtils.runOnUiThreadBlocking(searchButton::performClick);
+        CriteriaHelper.pollUiThread(
+                () -> mManager.getToolbarForTests().isSearching(), "Expected to enter search mode");
+
+        Assert.assertTrue("Expected bookmark row to not be highlighted "
+                        + "after entering search mode",
+                checkHighlightOff(testFolder));
+
+        // Click "Show in folder" again.
+        TestThreadUtils.runOnUiThreadBlocking(more::performClick);
+        onView(withText("Show in folder")).perform(click());
+
+        // Check that the highlight is on.
+        Assert.assertTrue("Expected highlight to successfully come back on"
+                        + " after clicking \"show in folder\" a 2nd time",
+                checkHighlightOn(testFolder));
+    }
+
+    @Test
+    @MediumTest
+    public void testShowInFolder_Scroll() throws Exception {
+        addFolder(TEST_FOLDER_TITLE); // Index 8
+        addBookmark(TEST_TITLE_A, TEST_URL_A);
+        addBookmark(TEST_PAGE_TITLE_FOO, "http://foo.com");
+        addFolder(TEST_PAGE_TITLE_GOOGLE2);
+        addFolder("B");
+        addFolder("C");
+        addFolder("D");
+        addFolder("E"); // Index 1
+        forceSyncHeaderState();
+        openBookmarkManager();
+
+        // Enter search mode.
+        View searchButton = mManager.getToolbarForTests().findViewById(R.id.search_menu_id);
+        TestThreadUtils.runOnUiThreadBlocking(searchButton::performClick);
+        CriteriaHelper.pollUiThread(
+                () -> mManager.getToolbarForTests().isSearching(), "Expected to enter search mode");
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> mManager.onSearchTextChanged(TEST_FOLDER_TITLE));
+        RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer);
+
+        // This should be the only (& therefore 0-indexed) item.
+        View testFolderInSearch = mItemsContainer.findViewHolderForAdapterPosition(0).itemView;
+        View more = testFolderInSearch.findViewById(R.id.more);
+        Assert.assertEquals("Wrong bookmark item selected.", TEST_FOLDER_TITLE,
+                ((BookmarkFolderRow) testFolderInSearch).getTitle());
+
+        // Show in folder.
+        TestThreadUtils.runOnUiThreadBlocking(more::performClick);
+        onView(withText("Show in folder")).perform(click());
+
+        // This should be in the 8th position now.
+        ViewHolder testFolderInList = mItemsContainer.findViewHolderForAdapterPosition(8);
+        Assert.assertFalse(
+                "Expected list to scroll bookmark item into view", testFolderInList == null);
+        Assert.assertEquals("Wrong bookmark item selected.", TEST_FOLDER_TITLE,
+                ((BookmarkFolderRow) testFolderInList.itemView).getTitle());
+        Assert.assertTrue("Expected bookmark item to be highlighted after scrolling to it.",
+                checkHighlightOn(testFolderInList.itemView));
+    }
+
+    @Test
+    @MediumTest
+    public void testShowInFolder_OpenOtherFolder() throws Exception {
+        BookmarkId testId = addFolder(TEST_FOLDER_TITLE);
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> mBookmarkModel.addBookmark(testId, 0, TEST_TITLE_A, TEST_URL_A));
+        forceSyncHeaderState();
+        openBookmarkManager();
+
+        // Enter search mode.
+        View searchButton = mManager.getToolbarForTests().findViewById(R.id.search_menu_id);
+        TestThreadUtils.runOnUiThreadBlocking(searchButton::performClick);
+        CriteriaHelper.pollUiThread(
+                () -> mManager.getToolbarForTests().isSearching(), "Expected to enter search mode");
+        TestThreadUtils.runOnUiThreadBlocking(() -> mManager.onSearchTextChanged(TEST_URL_A));
+        RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer);
+
+        // This should be the only (& therefore 0-indexed) item.
+        View itemAInSearch = mItemsContainer.findViewHolderForAdapterPosition(0).itemView;
+        View more = itemAInSearch.findViewById(R.id.more);
+        Assert.assertEquals("Wrong bookmark item selected.", TEST_TITLE_A,
+                ((BookmarkItemRow) itemAInSearch).getTitle());
+
+        // Show in folder.
+        TestThreadUtils.runOnUiThreadBlocking(more::performClick);
+        onView(withText("Show in folder")).perform(click());
+
+        // Make sure that we're in the right folder (index 1 because of promo).
+        View itemA = mItemsContainer.findViewHolderForAdapterPosition(1).itemView;
+        Assert.assertEquals("Wrong bookmark item selected.", TEST_TITLE_A,
+                ((BookmarkItemRow) itemA).getTitle());
+        Assert.assertTrue(
+                "Expected bookmark item to be highlighted after opening it in new folder.",
+                checkHighlightOn(itemA));
+
+        // Open mobile bookmarks folder, then go back to the subfolder.
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mManager.openFolder(mBookmarkModel.getMobileFolderId());
+            mManager.openFolder(testId);
+        });
+        RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer);
+
+        itemA = mItemsContainer.findViewHolderForAdapterPosition(1).itemView;
+        Assert.assertEquals("Wrong bookmark item selected.", TEST_TITLE_A,
+                ((BookmarkItemRow) itemA).getTitle());
+        Assert.assertTrue("Expected bookmark item to not be highlighted after "
+                        + "exiting and re-entering folder.",
+                checkHighlightOff(itemA));
+    }
+
     @Override
     protected void openBookmarkManager() throws InterruptedException {
         super.openBookmarkManager();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/feed/FeedConfigurationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/feed/FeedConfigurationTest.java
index 0e25918..4161ee5f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/feed/FeedConfigurationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/feed/FeedConfigurationTest.java
@@ -46,6 +46,8 @@
                 FeedConfiguration.FEED_UI_ENABLED_DEFAULT, FeedConfiguration.getFeedUiEnabled());
         Assert.assertEquals(FeedConfiguration.INITIAL_NON_CACHED_PAGE_SIZE_DEFAULT,
                 FeedConfiguration.getInitialNonCachedPageSize());
+        Assert.assertEquals(FeedConfiguration.LIMIT_PAGE_UPDATES_IN_HEAD_DEFAULT,
+                FeedConfiguration.getLimitPageUpdatesInHead());
         Assert.assertEquals(FeedConfiguration.LOGGING_IMMEDIATE_CONTENT_THRESHOLD_MS_DEFAULT,
                 FeedConfiguration.getLoggingImmediateContentThresholdMs());
         Assert.assertEquals(FeedConfiguration.MANAGE_INTERESTS_ENABLED_DEFAULT,
@@ -142,6 +144,16 @@
     @Feature({"Feed"})
     @CommandLineFlags.
     Add({"enable-features=InterestFeedContentSuggestions<Trial", "force-fieldtrials=Trial/Group",
+            "force-fieldtrial-params=Trial.Group:limit_page_updates_in_head/true"})
+    public void
+    testLimitPageUpdatesInHead() {
+        Assert.assertTrue(FeedConfiguration.getLimitPageUpdatesInHead());
+    }
+
+    @Test
+    @Feature({"Feed"})
+    @CommandLineFlags.
+    Add({"enable-features=InterestFeedContentSuggestions<Trial", "force-fieldtrials=Trial/Group",
             "force-fieldtrial-params=Trial.Group:logging_immediate_content_threshold_ms/5000"})
     public void
     testLoggingImmediateContentThresholdMs() {
@@ -294,6 +306,8 @@
         Assert.assertFalse(configuration.getValueOrDefault(ConfigKey.FEED_UI_ENABLED, true));
         Assert.assertEquals((long) FeedConfiguration.INITIAL_NON_CACHED_PAGE_SIZE_DEFAULT,
                 configuration.getValueOrDefault(ConfigKey.INITIAL_NON_CACHED_PAGE_SIZE, 0));
+        Assert.assertFalse(
+                configuration.getValueOrDefault(ConfigKey.LIMIT_PAGE_UPDATES_IN_HEAD, true));
         Assert.assertEquals((long) FeedConfiguration.LOGGING_IMMEDIATE_CONTENT_THRESHOLD_MS_DEFAULT,
                 configuration.getValueOrDefault(
                         ConfigKey.LOGGING_IMMEDIATE_CONTENT_THRESHOLD_MS, 0l));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sms/SmsReceiverDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sms/SmsReceiverDialogTest.java
index dcf7d5e..9233568 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sms/SmsReceiverDialogTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sms/SmsReceiverDialogTest.java
@@ -27,6 +27,7 @@
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.content_public.browser.sms.Event;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.content_public.browser.test.util.TestTouchUtils;
 import org.chromium.ui.base.ActivityWindowAndroid;
@@ -49,16 +50,24 @@
 
     final private CallbackHelper mCancelButtonClickedCallback = new CallbackHelper();
     final private CallbackHelper mConfirmButtonClickedCallback = new CallbackHelper();
+    final private CallbackHelper mTryAgainButtonClickedCallback = new CallbackHelper();
 
     private class TestSmsReceiverDialogJni implements SmsReceiverDialog.Natives {
         @Override
-        public void onCancel(long nativeSmsDialogAndroid) {
-            mCancelButtonClickedCallback.notifyCalled();
-        }
-
-        @Override
-        public void onConfirm(long nativeSmsDialogAndroid) {
-            mConfirmButtonClickedCallback.notifyCalled();
+        public void onEvent(long nativeSmsDialogAndroid, int eventType) {
+            switch (eventType) {
+                case Event.CANCEL:
+                    mCancelButtonClickedCallback.notifyCalled();
+                    return;
+                case Event.CONFIRM:
+                    mConfirmButtonClickedCallback.notifyCalled();
+                    return;
+                case Event.TIMEOUT:
+                    mTryAgainButtonClickedCallback.notifyCalled();
+                    return;
+                default:
+                    assert false : "|eventType| is invalid";
+            }
         }
     }
 
@@ -81,45 +90,109 @@
 
     @Test
     @LargeTest
-    public void testCancelButtonAndConfirmButton() {
+    public void testSmsCancel() throws Throwable {
         Dialog dialog = mSmsDialog.getDialogForTesting();
 
         Button cancelButton = (Button) dialog.findViewById(R.id.cancel_button);
         Assert.assertTrue(cancelButton.isEnabled());
 
-        Button confirmButton = (Button) dialog.findViewById(R.id.confirm_button);
-        Assert.assertFalse(confirmButton.isEnabled());
-
-        TestThreadUtils.runOnUiThreadBlocking(mSmsDialog::smsReceived);
-        Assert.assertTrue(confirmButton.isEnabled());
-    }
-
-    @Test
-    @LargeTest
-    public void testClickCancelButton() throws Throwable {
-        Dialog dialog = mSmsDialog.getDialogForTesting();
-        Button cancelButton = (Button) dialog.findViewById(R.id.cancel_button);
-
+        // Simulates the user clicking the "Cancel" button.
         TestTouchUtils.performClickOnMainSync(
                 InstrumentationRegistry.getInstrumentation(), cancelButton);
-
         mCancelButtonClickedCallback.waitForCallback(0, 1);
     }
 
     @Test
     @LargeTest
-    public void testClickConfirmButton() throws Throwable {
+    public void testSmsReceivedUserClickingCancelButton() throws Throwable {
         Dialog dialog = mSmsDialog.getDialogForTesting();
-        Button confirmButton = (Button) dialog.findViewById(R.id.confirm_button);
 
+        ProgressBar progressBar = (ProgressBar) dialog.findViewById(R.id.progress);
+        ImageView doneIcon = (ImageView) dialog.findViewById(R.id.done_icon);
+        ImageView errorIcon = (ImageView) dialog.findViewById(R.id.error_icon);
+        TextView status = (TextView) dialog.findViewById(R.id.status);
+        Button cancelButton = (Button) dialog.findViewById(R.id.cancel_button);
+        Button confirmButton = (Button) dialog.findViewById(R.id.confirm_or_try_again_button);
+
+        Assert.assertEquals(View.VISIBLE, progressBar.getVisibility());
+        Assert.assertEquals(View.GONE, doneIcon.getVisibility());
+        Assert.assertEquals(View.GONE, errorIcon.getVisibility());
+        Assert.assertEquals(
+                mActivityTestRule.getActivity().getString(R.string.sms_dialog_status_waiting),
+                status.getText().toString());
+        Assert.assertTrue(cancelButton.isEnabled());
+        Assert.assertEquals(mActivityTestRule.getActivity().getString(R.string.confirm),
+                confirmButton.getText().toString());
+        Assert.assertFalse(confirmButton.isEnabled());
+
+        // Simulates the SMS being received.
+        TestThreadUtils.runOnUiThreadBlocking(mSmsDialog::smsReceived);
+
+        Assert.assertEquals(View.GONE, progressBar.getVisibility());
+        Assert.assertEquals(View.VISIBLE, doneIcon.getVisibility());
+        Assert.assertEquals(View.GONE, errorIcon.getVisibility());
+        Assert.assertEquals(
+                mActivityTestRule.getActivity().getString(R.string.sms_dialog_status_sms_received),
+                status.getText().toString());
+        Assert.assertTrue(cancelButton.isEnabled());
+        Assert.assertTrue(confirmButton.isEnabled());
+
+        // Simulates the user clicking the "Cancel" button.
+        TestTouchUtils.performClickOnMainSync(
+                InstrumentationRegistry.getInstrumentation(), cancelButton);
+        mCancelButtonClickedCallback.waitForCallback(0, 1);
+    }
+
+    @Test
+    @LargeTest
+    public void testSmsReceivedUserClickingConfirmButton() throws Throwable {
+        Dialog dialog = mSmsDialog.getDialogForTesting();
+
+        Button confirmButton = (Button) dialog.findViewById(R.id.confirm_or_try_again_button);
+
+        // Simulates the SMS being received.
+        TestThreadUtils.runOnUiThreadBlocking(mSmsDialog::smsReceived);
+
+        // Simulates the user clicking the "Confirm" button.
         TestTouchUtils.performClickOnMainSync(
                 InstrumentationRegistry.getInstrumentation(), confirmButton);
-
         mConfirmButtonClickedCallback.waitForCallback(0, 1);
     }
 
     @Test
     @LargeTest
+    public void testSmsTimeout() throws Throwable {
+        Dialog dialog = mSmsDialog.getDialogForTesting();
+
+        ProgressBar progressBar = (ProgressBar) dialog.findViewById(R.id.progress);
+        ImageView doneIcon = (ImageView) dialog.findViewById(R.id.done_icon);
+        ImageView errorIcon = (ImageView) dialog.findViewById(R.id.error_icon);
+        TextView status = (TextView) dialog.findViewById(R.id.status);
+        Button cancelButton = (Button) dialog.findViewById(R.id.cancel_button);
+        Button tryAgainButton = (Button) dialog.findViewById(R.id.confirm_or_try_again_button);
+
+        // Simulates receiving the SMS having timed out.
+        TestThreadUtils.runOnUiThreadBlocking(mSmsDialog::smsTimeout);
+
+        Assert.assertEquals(View.GONE, progressBar.getVisibility());
+        Assert.assertEquals(View.GONE, doneIcon.getVisibility());
+        Assert.assertEquals(View.VISIBLE, errorIcon.getVisibility());
+        Assert.assertEquals(
+                mActivityTestRule.getActivity().getString(R.string.sms_dialog_status_timeout),
+                status.getText().toString());
+        Assert.assertEquals(View.GONE, cancelButton.getVisibility());
+        Assert.assertEquals(mActivityTestRule.getActivity().getString(R.string.try_again),
+                tryAgainButton.getText().toString());
+        Assert.assertTrue(tryAgainButton.isEnabled());
+
+        // Simulates the user clicking the "Try again" button.
+        TestTouchUtils.performClickOnMainSync(
+                InstrumentationRegistry.getInstrumentation(), tryAgainButton);
+        mTryAgainButtonClickedCallback.waitForCallback(0, 1);
+    }
+
+    @Test
+    @LargeTest
     public void testStatusRowChangesWhenMessageReceived() {
         Dialog dialog = mSmsDialog.getDialogForTesting();
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorObserverTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorObserverTestRule.java
index 0166839..93123279 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorObserverTestRule.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorObserverTestRule.java
@@ -75,7 +75,7 @@
             }
         };
 
-        TabModelOrderController orderController = new TabModelOrderController(mSelector);
+        TabModelOrderController orderController = new TabModelOrderControllerImpl(mSelector);
         TabContentManager tabContentManager =
                 new TabContentManager(InstrumentationRegistry.getTargetContext(), null, false);
         TabPersistencePolicy persistencePolicy = new TabbedModeTabPersistencePolicy(0, false);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java
index bc35eb8..9ebf3a24 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java
@@ -179,7 +179,7 @@
                                     mTabCreatorManager, mTabPersistentStoreObserver);
                         }
                     });
-            mTabModelOrderController = new TabModelOrderController(this);
+            mTabModelOrderController = new TabModelOrderControllerImpl(this);
 
             Callable<TabModelImpl> callable = new Callable<TabModelImpl>() {
                 @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkActivityTest.java
new file mode 100644
index 0000000..51b00d80
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkActivityTest.java
@@ -0,0 +1,257 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.webapps;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Build;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.base.ContextUtils;
+import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.Feature;
+import org.chromium.blink_public.platform.WebDisplayMode;
+import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.browser.ChromeTabbedActivity;
+import org.chromium.chrome.browser.DeferredStartupHandler;
+import org.chromium.chrome.browser.ShortcutHelper;
+import org.chromium.chrome.browser.ShortcutSource;
+import org.chromium.chrome.browser.customtabs.CustomTabActivity;
+import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider;
+import org.chromium.chrome.browser.tab.TabWebContentsDelegateAndroid;
+import org.chromium.chrome.browser.touchless.TouchlessDelegate;
+import org.chromium.chrome.browser.util.FeatureUtilities;
+import org.chromium.chrome.browser.util.IntentUtils;
+import org.chromium.chrome.test.ChromeActivityTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.util.ChromeTabUtils;
+import org.chromium.content_public.browser.test.NativeLibraryTestRule;
+import org.chromium.content_public.browser.test.util.Criteria;
+import org.chromium.content_public.browser.test.util.CriteriaHelper;
+import org.chromium.content_public.browser.test.util.JavaScriptUtils;
+import org.chromium.content_public.common.ScreenOrientationValues;
+import org.chromium.webapk.lib.common.WebApkConstants;
+
+/** Tests for WebApkActivity. */
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+public final class WebApkActivityTest {
+    private static final String TEST_WEBAPK_PACKAGE_NAME = "org.chromium.webapk.for.testing";
+    private static final String TEST_WEBAPK_ID =
+            WebApkConstants.WEBAPK_ID_PREFIX + TEST_WEBAPK_PACKAGE_NAME;
+
+    public final WebApkActivityTestRule mActivityTestRule = new WebApkActivityTestRule();
+    public final NativeLibraryTestRule mNativeLibraryTestRule = new NativeLibraryTestRule();
+
+    @Before
+    public void setUp() {
+        WebApkUpdateManager.setUpdatesEnabledForTesting(false);
+        mActivityTestRule.getEmbeddedTestServerRule().setServerUsesHttps(true);
+
+        // WebAPK is not installed. Ensure that WebappRegistry#unregisterOldWebapps() does not
+        // delete the WebAPK's shared preferences.
+        SharedPreferences sharedPrefs = ContextUtils.getApplicationContext().getSharedPreferences(
+                WebappRegistry.REGISTRY_FILE_NAME, Context.MODE_PRIVATE);
+        sharedPrefs.edit()
+                .putLong(WebappRegistry.KEY_LAST_CLEANUP, System.currentTimeMillis())
+                .apply();
+    }
+
+    /**
+     * Test that navigating a WebAPK to a URL which is outside of the WebAPK's scope shows the
+     * toolbar.
+     */
+    @Test
+    @LargeTest
+    @Feature({"WebApk"})
+    public void testLaunchAndNavigateOutsideScope() throws Exception {
+        WebApkActivity webApkActivity = mActivityTestRule.startWebApkActivity(createWebApkInfo(
+                getTestServerUrl("scope_a/page_1.html"), getTestServerUrl("scope_a/")));
+        WebappActivityTestRule.assertToolbarShowState(webApkActivity, false);
+
+        // We navigate outside scope and expect CCT toolbar to show on top of WebApkActivity.
+        String outOfScopeUrl = getTestServerUrl("manifest_test_page.html");
+        mActivityTestRule.runJavaScriptCodeInCurrentTab(
+                "window.top.location = '" + outOfScopeUrl + "'");
+
+        ChromeTabUtils.waitForTabPageLoaded(webApkActivity.getActivityTab(), outOfScopeUrl);
+        WebappActivityTestRule.assertToolbarShowState(webApkActivity, true);
+    }
+
+    /**
+     * Test launching a WebAPK. Test that opening a url within scope through window.open() will open
+     * a CCT.
+     */
+    @Test
+    @LargeTest
+    @Feature({"WebApk"})
+    public void testLaunchAndOpenNewWindowInScope() throws Exception {
+        String scopeUrl = getTestServerUrl("scope_a/");
+        String inScopeUrl = getTestServerUrl("scope_a/page_1.html");
+        WebApkActivity webApkActivity =
+                mActivityTestRule.startWebApkActivity(createWebApkInfo(inScopeUrl, scopeUrl));
+
+        WebappActivityTestRule.jsWindowOpen(mActivityTestRule.getActivity(), inScopeUrl);
+
+        CustomTabActivity customTabActivity =
+                ChromeActivityTestRule.waitFor(CustomTabActivity.class);
+        ChromeTabUtils.waitForTabPageLoaded(customTabActivity.getActivityTab(), inScopeUrl);
+        Assert.assertTrue(
+                "Sending to external handlers needs to be enabled for redirect back (e.g. OAuth).",
+                IntentUtils.safeGetBooleanExtra(customTabActivity.getIntent(),
+                        CustomTabIntentDataProvider.EXTRA_SEND_TO_EXTERNAL_DEFAULT_HANDLER, false));
+    }
+
+    /**
+     * Test launching a WebAPK. Test that opening a url off scope through window.open() will open a
+     * CCT, and in scope urls will stay in the CCT.
+     */
+    @Test
+    @LargeTest
+    @Feature({"WebApk"})
+    public void testLaunchAndNavigationInNewWindowOffandInScope() throws Exception {
+        String scopeUrl = getTestServerUrl("scope_a/");
+        String inScopeUrl = getTestServerUrl("scope_a/page_1.html");
+        String offScopeUrl = getTestServerUrl("scope_b/scope_b.html");
+        WebApkActivity webApkActivity =
+                mActivityTestRule.startWebApkActivity(createWebApkInfo(inScopeUrl, scopeUrl));
+
+        WebappActivityTestRule.jsWindowOpen(mActivityTestRule.getActivity(), offScopeUrl);
+        CustomTabActivity customTabActivity =
+                ChromeActivityTestRule.waitFor(CustomTabActivity.class);
+        ChromeTabUtils.waitForTabPageLoaded(customTabActivity.getActivityTab(), offScopeUrl);
+
+        JavaScriptUtils.executeJavaScriptAndWaitForResult(
+                customTabActivity.getActivityTab().getWebContents(),
+                String.format("window.location.href='%s'", inScopeUrl));
+        ChromeTabUtils.waitForTabPageLoaded(customTabActivity.getActivityTab(), inScopeUrl);
+    }
+
+    /**
+     * Test that on first launch:
+     * - the "WebApk.LaunchInterval" histogram is not recorded (because there is no previous launch
+     *   to compute the interval from).
+     * - the "last used" time is updated (to compute future "launch intervals").
+     */
+    @Test
+    @LargeTest
+    @Feature({"WebApk"})
+    public void testLaunchIntervalHistogramNotRecordedOnFirstLaunch() throws Exception {
+        android.util.Log.e("ABCD", "Start");
+        final String histogramName = "WebApk.LaunchInterval";
+        WebApkActivity webApkActivity = mActivityTestRule.startWebApkActivity(createWebApkInfo(
+                getTestServerUrl("manifest_test_page.html"), getTestServerUrl("/")));
+
+        CriteriaHelper.pollUiThread(new Criteria("Deferred startup never completed") {
+            @Override
+            public boolean isSatisfied() {
+                return DeferredStartupHandler.getInstance().isDeferredStartupCompleteForApp()
+                        && WebappRegistry.getInstance().getWebappDataStorage(TEST_WEBAPK_ID)
+                        != null;
+            }
+        });
+        Assert.assertEquals(0, RecordHistogram.getHistogramTotalCountForTesting(histogramName));
+        WebappDataStorage storage =
+                WebappRegistry.getInstance().getWebappDataStorage(TEST_WEBAPK_ID);
+        Assert.assertNotEquals(WebappDataStorage.TIMESTAMP_INVALID, storage.getLastUsedTimeMs());
+        android.util.Log.e("ABCD", "Start2");
+    }
+
+    /** Test that the "WebApk.LaunchInterval" histogram is recorded on susbequent launches. */
+    @Test
+    @LargeTest
+    @Feature({"WebApk"})
+    public void testLaunchIntervalHistogramRecordedOnSecondLaunch() throws Exception {
+        mNativeLibraryTestRule.loadNativeLibraryNoBrowserProcess();
+
+        final String histogramName = "WebApk.LaunchInterval2";
+        final String packageName = "org.chromium.webapk.test";
+
+        WebappDataStorage storage = registerWithStorage(TEST_WEBAPK_ID);
+        storage.setHasBeenLaunched();
+        storage.updateLastUsedTime();
+        Assert.assertEquals(0, RecordHistogram.getHistogramTotalCountForTesting(histogramName));
+
+        WebApkActivity webApkActivity = mActivityTestRule.startWebApkActivity(createWebApkInfo(
+                getTestServerUrl("manifest_test_page.html"), getTestServerUrl("/")));
+
+        CriteriaHelper.pollUiThread(new Criteria("Deferred startup never completed") {
+            @Override
+            public boolean isSatisfied() {
+                return DeferredStartupHandler.getInstance().isDeferredStartupCompleteForApp();
+            }
+        });
+
+        Assert.assertEquals(1, RecordHistogram.getHistogramTotalCountForTesting(histogramName));
+    }
+
+    /**
+     * Test the L+ logic in {@link TabWebContentsDelegateAndroid#activateContents} for bringing
+     * WebAPK to the foreground.
+     */
+    @LargeTest
+    @Test
+    public void testActivateWebApkLPlus() throws Exception {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return;
+
+        // Launch WebAPK.
+        WebApkActivity webApkActivity = mActivityTestRule.startWebApkActivity(createWebApkInfo(
+                getTestServerUrl("manifest_test_page.html"), getTestServerUrl("/")));
+
+        Class<? extends ChromeActivity> mainClass = FeatureUtilities.isNoTouchModeEnabled()
+                ? TouchlessDelegate.getNoTouchActivityClass()
+                : ChromeTabbedActivity.class;
+
+        // Move WebAPK to the background by launching Chrome.
+        Intent intent = new Intent(InstrumentationRegistry.getTargetContext(), mainClass);
+        intent.setFlags(
+                Intent.FLAG_ACTIVITY_NEW_TASK | ApiCompatibilityUtils.getActivityNewDocumentFlag());
+        InstrumentationRegistry.getTargetContext().startActivity(intent);
+        ChromeActivityTestRule.waitFor(mainClass);
+
+        TabWebContentsDelegateAndroid tabDelegate =
+                webApkActivity.getActivityTab().getTabWebContentsDelegateAndroid();
+        tabDelegate.activateContents();
+
+        // WebApkActivity should have been brought back to the foreground.
+        ChromeActivityTestRule.waitFor(WebApkActivity.class);
+    }
+
+    private WebApkInfo createWebApkInfo(String startUrl, String scopeUrl) {
+        return WebApkInfo.create(TEST_WEBAPK_ID, startUrl, scopeUrl, null /* primaryIcon */,
+                null /* badgeIcon */, null /* splashIcon */, "" /* name */, "" /* short_name */,
+                WebDisplayMode.STANDALONE, ScreenOrientationValues.DEFAULT, ShortcutSource.UNKNOWN,
+                ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING /* themeColor */,
+                ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING /* backgroundColor */,
+                0 /* defaultBackgroundColor */, false /* isPrimaryIconMaskable */,
+                TEST_WEBAPK_PACKAGE_NAME, 10 /* packageVersion */, "" /* manifestURL */,
+                "" /* manifestStartURL */, WebApkInfo.WebApkDistributor.BROWSER, null, null,
+                null /*shareTargetActivityName*/, false /* forceNavigation */,
+                false /* isSplashProvidedByWebApk */, null /* shareData */, 1 /* apkVersionCode */);
+    }
+
+    private String getTestServerUrl(String relativeUrl) {
+        return mActivityTestRule.getEmbeddedTestServerRule().getServer().getURL(
+                "/chrome/test/data/banners/" + relativeUrl);
+    }
+
+    /** Register WebAPK with WebappDataStorage */
+    private WebappDataStorage registerWithStorage(final String webappId) throws Exception {
+        TestFetchStorageCallback callback = new TestFetchStorageCallback();
+        WebappRegistry.getInstance().register(webappId, callback);
+        callback.waitForCallback(0);
+        return WebappRegistry.getInstance().getWebappDataStorage(webappId);
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkActivityTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkActivityTestRule.java
new file mode 100644
index 0000000..77703d1
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkActivityTestRule.java
@@ -0,0 +1,71 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.webapps;
+
+import android.content.Intent;
+import android.support.test.InstrumentationRegistry;
+
+import org.junit.Assert;
+
+import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.base.test.util.ScalableTimeout;
+import org.chromium.chrome.browser.ShortcutHelper;
+import org.chromium.chrome.test.ChromeActivityTestRule;
+import org.chromium.chrome.test.util.ChromeTabUtils;
+import org.chromium.content_public.browser.test.util.Criteria;
+import org.chromium.content_public.browser.test.util.CriteriaHelper;
+import org.chromium.webapk.lib.common.WebApkConstants;
+
+/** Custom {@link ChromeActivityTestRule} for tests using {@link WebApkActivity}. */
+public class WebApkActivityTestRule extends ChromeActivityTestRule<WebApkActivity> {
+    /** Time in milliseconds to wait for page to be loaded. */
+    private static final long STARTUP_TIMEOUT = ScalableTimeout.scaleTimeout(10000);
+
+    public WebApkActivityTestRule() {
+        super(WebApkActivity.class);
+    }
+
+    /**
+     * Launches WebApkActivity and waits for the page to have finished loading and for the splash
+     * screen to be hidden.
+     */
+    public WebApkActivity startWebApkActivity(WebApkInfo webApkInfo) throws InterruptedException {
+        Intent intent = createIntent(webApkInfo);
+
+        WebappActivity.addWebappInfo(webApkInfo.id(), webApkInfo);
+        final WebApkActivity webApkActivity =
+                (WebApkActivity) InstrumentationRegistry.getInstrumentation().startActivitySync(
+                        intent);
+        setActivity(webApkActivity);
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        CriteriaHelper.pollInstrumentationThread(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                return webApkActivity.getActivityTab() != null;
+            }
+        }, STARTUP_TIMEOUT, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
+
+        ChromeTabUtils.waitForTabPageLoaded(
+                webApkActivity.getActivityTab(), webApkInfo.uri().toString());
+        WebappActivityTestRule.waitUntilSplashHides(webApkActivity);
+
+        // Launching the WebAPK should have popped the WebApkInfo.
+        Assert.assertNull(WebappActivity.popWebappInfo(webApkInfo.id()));
+
+        return webApkActivity;
+    }
+
+    private Intent createIntent(WebApkInfo webApkInfo) {
+        Intent intent =
+                new Intent(InstrumentationRegistry.getTargetContext(), WebApkActivity0.class);
+        intent.putExtra(WebApkConstants.EXTRA_WEBAPK_PACKAGE_NAME, webApkInfo.webApkPackageName());
+        intent.putExtra(ShortcutHelper.EXTRA_ID, webApkInfo.id());
+        intent.putExtra(ShortcutHelper.EXTRA_URL, webApkInfo.uri().toString());
+        intent.addFlags(
+                Intent.FLAG_ACTIVITY_NEW_TASK | ApiCompatibilityUtils.getActivityNewDocumentFlag());
+        return intent;
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkIntegrationTest.java
index b757859..cbc1dec 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkIntegrationTest.java
@@ -16,31 +16,14 @@
 import org.junit.rules.RuleChain;
 import org.junit.runner.RunWith;
 
-import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.CommandLine;
-import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.ScalableTimeout;
-import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.ChromeSwitches;
-import org.chromium.chrome.browser.ChromeTabbedActivity;
-import org.chromium.chrome.browser.DeferredStartupHandler;
-import org.chromium.chrome.browser.ShortcutHelper;
-import org.chromium.chrome.browser.customtabs.CustomTabActivity;
-import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider;
-import org.chromium.chrome.browser.tab.TabWebContentsDelegateAndroid;
 import org.chromium.chrome.browser.test.MockCertVerifierRuleAndroid;
-import org.chromium.chrome.browser.touchless.TouchlessDelegate;
-import org.chromium.chrome.browser.util.FeatureUtilities;
-import org.chromium.chrome.browser.util.IntentUtils;
 import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.chrome.test.util.ChromeTabUtils;
 import org.chromium.content_public.browser.test.NativeLibraryTestRule;
-import org.chromium.content_public.browser.test.util.Criteria;
-import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.JavaScriptUtils;
 import org.chromium.content_public.common.ContentSwitches;
 import org.chromium.webapk.lib.client.WebApkValidator;
 import org.chromium.webapk.lib.common.WebApkConstants;
@@ -63,54 +46,6 @@
                                           .around(mNativeLibraryTestRule)
                                           .around(mCertVerifierRule);
 
-    private static final long STARTUP_TIMEOUT = ScalableTimeout.scaleTimeout(10000);
-
-    public void startWebApkActivity(String webApkPackageName, final String startUrl)
-            throws InterruptedException {
-        Intent intent =
-                new Intent(InstrumentationRegistry.getTargetContext(), WebApkActivity0.class);
-        intent.putExtra(WebApkConstants.EXTRA_WEBAPK_PACKAGE_NAME, webApkPackageName);
-        intent.putExtra(ShortcutHelper.EXTRA_URL, startUrl);
-        intent.addFlags(
-                Intent.FLAG_ACTIVITY_NEW_TASK | ApiCompatibilityUtils.getActivityNewDocumentFlag());
-
-        WebApkActivity webApkActivity =
-                (WebApkActivity) InstrumentationRegistry.getInstrumentation().startActivitySync(
-                        intent);
-        mActivityTestRule.setActivity(webApkActivity);
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return mActivityTestRule.getActivity().getActivityTab() != null;
-            }
-        }, STARTUP_TIMEOUT, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
-
-        ChromeTabUtils.waitForTabPageLoaded(
-                mActivityTestRule.getActivity().getActivityTab(), startUrl);
-    }
-
-    /** Waits for the splash screen to be hidden. */
-    public void waitUntilSplashscreenHides() {
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return mActivityTestRule.getActivity()
-                        .getSplashControllerForTests()
-                        .wasSplashScreenHiddenForTests();
-            }
-        });
-    }
-
-    /** Register WebAPK with WebappDataStorage */
-    private WebappDataStorage registerWithStorage(final String webappId) throws Exception {
-        TestFetchStorageCallback callback = new TestFetchStorageCallback();
-        WebappRegistry.getInstance().register(webappId, callback);
-        callback.waitForCallback(0);
-        return WebappRegistry.getInstance().getWebappDataStorage(webappId);
-    }
-
     /** Returns URL for the passed-in host which maps to a page on the EmbeddedTestServer. */
     private String getUrlForHost(String host) {
         return "https://" + host + "/defaultresponse";
@@ -148,158 +83,4 @@
         WebApkActivity lastActivity = mActivityTestRule.getActivity();
         Assert.assertEquals(pwaRocksUrl, lastActivity.getWebappInfo().uri().toString());
     }
-
-    /**
-     * Test launching a WebAPK. Test that loading the start page works and that the splashscreen
-     * eventually hides.
-     */
-    @Test
-    @LargeTest
-    @Feature({"WebApk"})
-    public void testLaunchAndNavigateOffOrigin() throws Exception {
-        startWebApkActivity("org.chromium.webapk.test", getUrlForHost("pwa.rocks"));
-        waitUntilSplashscreenHides();
-        WebApkActivity webApkActivity = mActivityTestRule.getActivity();
-        WebappActivityTestRule.assertToolbarShowState(webApkActivity, false);
-
-        // We navigate outside origin and expect CCT toolbar to show on top of WebApkActivity.
-        String googleUrl = getUrlForHost("www.google.com");
-        mActivityTestRule.runJavaScriptCodeInCurrentTab(
-                "window.top.location = '" + googleUrl + "'");
-
-        ChromeTabUtils.waitForTabPageLoaded(webApkActivity.getActivityTab(), googleUrl);
-        WebappActivityTestRule.assertToolbarShowState(webApkActivity, true);
-    }
-
-    /**
-     * Test launching a WebAPK. Test that open a url within scope through window.open() will open a
-     * CCT.
-     */
-    @Test
-    @LargeTest
-    @Feature({"WebApk"})
-    public void testLaunchAndOpenNewWindowInOrigin() throws Exception {
-        String pwaRocksUrl = getUrlForHost("pwa.rocks");
-        startWebApkActivity("org.chromium.webapk.test", pwaRocksUrl);
-        waitUntilSplashscreenHides();
-
-        WebappActivityTestRule.jsWindowOpen(mActivityTestRule.getActivity(), pwaRocksUrl);
-
-        CustomTabActivity customTabActivity =
-                ChromeActivityTestRule.waitFor(CustomTabActivity.class);
-        ChromeTabUtils.waitForTabPageLoaded(customTabActivity.getActivityTab(), pwaRocksUrl);
-        Assert.assertTrue(
-                "Sending to external handlers needs to be enabled for redirect back (e.g. OAuth).",
-                IntentUtils.safeGetBooleanExtra(customTabActivity.getIntent(),
-                        CustomTabIntentDataProvider.EXTRA_SEND_TO_EXTERNAL_DEFAULT_HANDLER, false));
-    }
-
-    /**
-     * Test launching a WebAPK. Test that open a url off scope through window.open() will open a
-     * CCT, and in scope urls will stay in the CCT.
-     */
-    @Test
-    @LargeTest
-    @Feature({"WebApk"})
-    public void testLaunchAndNavigationInNewWindowOffandInOrigin() throws Exception {
-        String pwaRocksUrl = getUrlForHost("pwa.rocks");
-        String googleUrl = getUrlForHost("www.google.com");
-        startWebApkActivity("org.chromium.webapk.test", pwaRocksUrl);
-        waitUntilSplashscreenHides();
-
-        WebappActivityTestRule.jsWindowOpen(mActivityTestRule.getActivity(), googleUrl);
-        CustomTabActivity customTabActivity =
-                ChromeActivityTestRule.waitFor(CustomTabActivity.class);
-        ChromeTabUtils.waitForTabPageLoaded(customTabActivity.getActivityTab(), googleUrl);
-
-        JavaScriptUtils.executeJavaScriptAndWaitForResult(
-                customTabActivity.getActivityTab().getWebContents(),
-                String.format("window.location.href='%s'", pwaRocksUrl));
-        ChromeTabUtils.waitForTabPageLoaded(customTabActivity.getActivityTab(), pwaRocksUrl);
-    }
-
-    /**
-     * Test that on first launch:
-     * - the "WebApk.LaunchInterval" histogram is not recorded (because there is no prevous launch
-     *   to compute the interval from).
-     * - the "last used" time is updated (to compute future "launch intervals").
-     */
-    @Test
-    @LargeTest
-    @Feature({"WebApk"})
-    public void testLaunchIntervalHistogramNotRecordedOnFirstLaunch() throws Exception {
-        final String histogramName = "WebApk.LaunchInterval";
-        final String packageName = "org.chromium.webapk.test";
-        startWebApkActivity(packageName, getUrlForHost("pwa.rocks"));
-
-        CriteriaHelper.pollUiThread(new Criteria("Deferred startup never completed") {
-            @Override
-            public boolean isSatisfied() {
-                return DeferredStartupHandler.getInstance().isDeferredStartupCompleteForApp();
-            }
-        });
-        Assert.assertEquals(0, RecordHistogram.getHistogramTotalCountForTesting(histogramName));
-        WebappDataStorage storage = WebappRegistry.getInstance().getWebappDataStorage(
-                WebApkConstants.WEBAPK_ID_PREFIX + packageName);
-        Assert.assertNotEquals(WebappDataStorage.TIMESTAMP_INVALID, storage.getLastUsedTimeMs());
-    }
-
-    /** Test that the "WebApk.LaunchInterval" histogram is recorded on susbequent launches. */
-    @Test
-    @LargeTest
-    @Feature({"WebApk"})
-    public void testLaunchIntervalHistogramRecordedOnSecondLaunch() throws Exception {
-        mNativeLibraryTestRule.loadNativeLibraryNoBrowserProcess();
-
-        final String histogramName = "WebApk.LaunchInterval2";
-        final String packageName = "org.chromium.webapk.test";
-
-        WebappDataStorage storage =
-                registerWithStorage(WebApkConstants.WEBAPK_ID_PREFIX + packageName);
-        storage.setHasBeenLaunched();
-        storage.updateLastUsedTime();
-        Assert.assertEquals(0, RecordHistogram.getHistogramTotalCountForTesting(histogramName));
-
-        startWebApkActivity(packageName, getUrlForHost("pwa.rocks"));
-
-        CriteriaHelper.pollUiThread(new Criteria("Deferred startup never completed") {
-            @Override
-            public boolean isSatisfied() {
-                return DeferredStartupHandler.getInstance().isDeferredStartupCompleteForApp();
-            }
-        });
-
-        Assert.assertEquals(1, RecordHistogram.getHistogramTotalCountForTesting(histogramName));
-    }
-
-    /**
-     * Test that {@link TabWebContentsDelegateAndroid#activateContents} brings a WebAPK to the
-     * foreground.
-     */
-    @LargeTest
-    @Test
-    public void testActivateWebApk() throws Exception {
-        // Launch WebAPK.
-        startWebApkActivity("org.chromium.webapk.test", getUrlForHost("pwa.rocks"));
-        waitUntilSplashscreenHides();
-
-        Class<? extends ChromeActivity> mainClass = FeatureUtilities.isNoTouchModeEnabled()
-                ? TouchlessDelegate.getNoTouchActivityClass()
-                : ChromeTabbedActivity.class;
-
-        // Move WebAPK to the background by launching Chrome.
-        Intent intent = new Intent(InstrumentationRegistry.getTargetContext(), mainClass);
-        intent.setFlags(
-                Intent.FLAG_ACTIVITY_NEW_TASK | ApiCompatibilityUtils.getActivityNewDocumentFlag());
-        InstrumentationRegistry.getTargetContext().startActivity(intent);
-        ChromeActivityTestRule.waitFor(mainClass);
-
-        WebApkActivity webApkActivity = mActivityTestRule.getActivity();
-        TabWebContentsDelegateAndroid tabDelegate =
-                webApkActivity.getActivityTab().getTabWebContentsDelegateAndroid();
-        tabDelegate.activateContents();
-
-        // WebApkActivity should have been brought back to the foreground.
-        ChromeActivityTestRule.waitFor(WebApkActivity.class);
-    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActivityTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActivityTestRule.java
index 250f22b..a64b7a0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActivityTestRule.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActivityTestRule.java
@@ -247,10 +247,14 @@
      * Waits for the splash screen to be hidden.
      */
     public void waitUntilSplashscreenHides() {
+        waitUntilSplashHides(getActivity());
+    }
+
+    public static void waitUntilSplashHides(WebappActivity activity) {
         CriteriaHelper.pollInstrumentationThread(new Criteria() {
             @Override
             public boolean isSatisfied() {
-                return !isSplashScreenVisible();
+                return activity.getSplashControllerForTests().wasSplashScreenHiddenForTests();
             }
         }, STARTUP_TIMEOUT, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/ViewHighlighterTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/ViewHighlighterTest.java
index 8c9c44c..c0d02ff 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/ViewHighlighterTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/ViewHighlighterTest.java
@@ -7,8 +7,6 @@
 import android.content.Context;
 import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
 import android.support.test.rule.UiThreadTestRule;
@@ -22,6 +20,7 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ViewHighlighterTestUtils;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 
 /**
@@ -83,17 +82,21 @@
         checkHighlightOn(tintedImageButton);
     }
 
-    private void checkHighlightOn(View view) {
-        Assert.assertTrue(view.getBackground() instanceof LayerDrawable);
-        LayerDrawable layerDrawable = (LayerDrawable) view.getBackground();
-        Drawable drawable = layerDrawable.getDrawable(layerDrawable.getNumberOfLayers() - 1);
-        Assert.assertTrue(drawable instanceof PulseDrawable);
-        PulseDrawable pulse = (PulseDrawable) drawable;
-        Assert.assertTrue(pulse.isRunning());
-        Assert.assertTrue(pulse.isVisible());
+    /**
+     * Assert that the provided view is highlighted.
+     *
+     * @param view The view of interest.
+     */
+    private static void checkHighlightOn(View view) {
+        Assert.assertTrue(ViewHighlighterTestUtils.checkHighlightOn(view));
     }
 
-    private void checkHighlightOff(View view) {
-        Assert.assertFalse(view.getBackground() instanceof LayerDrawable);
+    /**
+     * Assert that the provided view is not highlighted.
+     *
+     * @param view The view of interest.
+     */
+    private static void checkHighlightOff(View view) {
+        Assert.assertTrue(ViewHighlighterTestUtils.checkHighlightOff(view));
     }
-}
+}
\ No newline at end of file
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ShadowDeviceConditions.java b/chrome/android/junit/src/org/chromium/chrome/browser/ShadowDeviceConditions.java
index 5ec6a380..c8ad496 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/ShadowDeviceConditions.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/ShadowDeviceConditions.java
@@ -59,4 +59,9 @@
     public static boolean isCurrentActiveNetworkMetered(Context context) {
         return sDeviceConditions.isActiveNetworkMetered();
     }
+
+    @Implementation
+    public static boolean isCurrentlyScreenOnAndUnlocked(Context context) {
+        return sDeviceConditions.isScreenOnAndUnlocked();
+    }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBackgroundTaskUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBackgroundTaskUnitTest.java
index 504878b..038e68fe 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBackgroundTaskUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBackgroundTaskUnitTest.java
@@ -114,9 +114,10 @@
         boolean powerSaveModeOn = true;
         int highBatteryLevel = 75;
         boolean metered = true;
+        boolean screenOnAndUnlocked = true;
 
-        DeviceConditions deviceConditions = new DeviceConditions(
-                !powerConnected, highBatteryLevel, connectionType, !powerSaveModeOn, !metered);
+        DeviceConditions deviceConditions = new DeviceConditions(!powerConnected, highBatteryLevel,
+                connectionType, !powerSaveModeOn, !metered, screenOnAndUnlocked);
         ShadowDeviceConditions.setCurrentConditions(deviceConditions);
     }
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflineBackgroundTaskTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflineBackgroundTaskTest.java
index 539a5f07..4aabd85 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflineBackgroundTaskTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflineBackgroundTaskTest.java
@@ -62,6 +62,7 @@
     private static final boolean POWER_CONNECTED = true;
     private static final boolean POWER_SAVE_MODE_ON = true;
     private static final boolean METERED = true;
+    private static final boolean SCREEN_ON_AND_UNLOCKED = true;
     private static final int MINIMUM_BATTERY_LEVEL = 33;
     private static final String IS_LOW_END_DEVICE_SWITCH =
             "--" + BaseSwitches.ENABLE_LOW_END_DEVICE_MODE;
@@ -74,7 +75,8 @@
     private TriggerConditions mTriggerConditions =
             new TriggerConditions(!REQUIRE_POWER, MINIMUM_BATTERY_LEVEL, REQUIRE_UNMETERED);
     private DeviceConditions mDeviceConditions = new DeviceConditions(!POWER_CONNECTED,
-            MINIMUM_BATTERY_LEVEL + 5, ConnectionType.CONNECTION_3G, !POWER_SAVE_MODE_ON, !METERED);
+            MINIMUM_BATTERY_LEVEL + 5, ConnectionType.CONNECTION_3G, !POWER_SAVE_MODE_ON, !METERED,
+            SCREEN_ON_AND_UNLOCKED);
     private Activity mTestActivity;
 
     @Mock
@@ -134,9 +136,9 @@
     @Feature({"OfflinePages"})
     public void testCheckConditions_BatteryConditions_LowBattery_NoPower() {
         // Setup low battery conditions with no power connected.
-        DeviceConditions deviceConditionsLowBattery =
-                new DeviceConditions(!POWER_CONNECTED, MINIMUM_BATTERY_LEVEL - 1,
-                        ConnectionType.CONNECTION_WIFI, !POWER_SAVE_MODE_ON, !METERED);
+        DeviceConditions deviceConditionsLowBattery = new DeviceConditions(!POWER_CONNECTED,
+                MINIMUM_BATTERY_LEVEL - 1, ConnectionType.CONNECTION_WIFI, !POWER_SAVE_MODE_ON,
+                !METERED, SCREEN_ON_AND_UNLOCKED);
         ShadowDeviceConditions.setCurrentConditions(deviceConditionsLowBattery);
 
         // Verify that conditions for processing are not met.
@@ -159,9 +161,9 @@
     @Feature({"OfflinePages"})
     public void testCheckConditions_BatteryConditions_LowBattery_WithPower() {
         // Set battery percentage below minimum level, but connect power.
-        DeviceConditions deviceConditionsPowerConnected =
-                new DeviceConditions(POWER_CONNECTED, MINIMUM_BATTERY_LEVEL - 1,
-                        ConnectionType.CONNECTION_WIFI, !POWER_SAVE_MODE_ON, !METERED);
+        DeviceConditions deviceConditionsPowerConnected = new DeviceConditions(POWER_CONNECTED,
+                MINIMUM_BATTERY_LEVEL - 1, ConnectionType.CONNECTION_WIFI, !POWER_SAVE_MODE_ON,
+                !METERED, SCREEN_ON_AND_UNLOCKED);
         ShadowDeviceConditions.setCurrentConditions(deviceConditionsPowerConnected);
 
         // Now verify that same battery level, with power connected, will pass the conditions.
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/prefetch/OfflineNotificationBackgroundTaskUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/prefetch/OfflineNotificationBackgroundTaskUnitTest.java
index a19e6bb..1200d27e 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/prefetch/OfflineNotificationBackgroundTaskUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/prefetch/OfflineNotificationBackgroundTaskUnitTest.java
@@ -195,10 +195,10 @@
     }
 
     private void setupDeviceOnlineStatus(boolean online) {
-        DeviceConditions deviceConditions =
-                new DeviceConditions(false /* POWER_CONNECTED */, 75 /* BATTERY_LEVEL */,
-                        online ? ConnectionType.CONNECTION_WIFI : ConnectionType.CONNECTION_NONE,
-                        false /* POWER_SAVE */, false /* metered */);
+        DeviceConditions deviceConditions = new DeviceConditions(false /* POWER_CONNECTED */,
+                75 /* BATTERY_LEVEL */,
+                online ? ConnectionType.CONNECTION_WIFI : ConnectionType.CONNECTION_NONE,
+                false /* POWER_SAVE */, false /* metered */, true /* screenOnAndUnlocked */);
         ShadowDeviceConditions.setCurrentConditions(deviceConditions);
     }
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTaskUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTaskUnitTest.java
index 71f40f66..d61ec381 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTaskUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTaskUnitTest.java
@@ -90,6 +90,7 @@
     public static final int HIGH_BATTERY_LEVEL = 75;
     public static final int LOW_BATTERY_LEVEL = 25;
     public static final boolean METERED = true;
+    public static final boolean SCREEN_ON_AND_UNLOCKED = true;
 
     @Spy
     private PrefetchBackgroundTask mPrefetchBackgroundTask = new PrefetchBackgroundTask();
@@ -193,9 +194,9 @@
                 TaskParameters.create(TaskIds.OFFLINE_PAGES_PREFETCH_JOB_ID).build();
 
         // Setup battery conditions with no power connected.
-        DeviceConditions deviceConditions =
-                new DeviceConditions(!POWER_CONNECTED, HIGH_BATTERY_LEVEL - 1,
-                        ConnectionType.CONNECTION_WIFI, !POWER_SAVE_MODE_ON, !METERED);
+        DeviceConditions deviceConditions = new DeviceConditions(!POWER_CONNECTED,
+                HIGH_BATTERY_LEVEL - 1, ConnectionType.CONNECTION_WIFI, !POWER_SAVE_MODE_ON,
+                !METERED, SCREEN_ON_AND_UNLOCKED);
         ShadowDeviceConditions.setCurrentConditions(deviceConditions);
 
         mPrefetchBackgroundTask.onStartTask(null, params, new TaskFinishedCallback() {
@@ -225,7 +226,8 @@
 
         // Setup battery conditions with no power connected.
         DeviceConditions deviceConditions = new DeviceConditions(!POWER_CONNECTED,
-                0 /* battery level */, ConnectionType.CONNECTION_2G, !POWER_SAVE_MODE_ON, METERED);
+                0 /* battery level */, ConnectionType.CONNECTION_2G, !POWER_SAVE_MODE_ON, METERED,
+                SCREEN_ON_AND_UNLOCKED);
         ShadowDeviceConditions.setCurrentConditions(deviceConditions);
 
         mPrefetchBackgroundTask.onStartTask(null, params, new TaskFinishedCallback() {
@@ -244,7 +246,8 @@
     public void testBatteryLow() throws Exception {
         // Setup low battery conditions with no power connected.
         DeviceConditions deviceConditionsLowBattery = new DeviceConditions(!POWER_CONNECTED,
-                LOW_BATTERY_LEVEL, ConnectionType.CONNECTION_WIFI, !POWER_SAVE_MODE_ON, METERED);
+                LOW_BATTERY_LEVEL, ConnectionType.CONNECTION_WIFI, !POWER_SAVE_MODE_ON, METERED,
+                SCREEN_ON_AND_UNLOCKED);
         ShadowDeviceConditions.setCurrentConditions(deviceConditionsLowBattery);
 
         // Check impact on starting before native loaded.
@@ -265,7 +268,8 @@
     public void testBatteryHigh() throws Exception {
         // Setup high battery conditions with no power connected.
         DeviceConditions deviceConditionsHighBattery = new DeviceConditions(!POWER_CONNECTED,
-                HIGH_BATTERY_LEVEL, ConnectionType.CONNECTION_WIFI, !POWER_SAVE_MODE_ON, !METERED);
+                HIGH_BATTERY_LEVEL, ConnectionType.CONNECTION_WIFI, !POWER_SAVE_MODE_ON, !METERED,
+                SCREEN_ON_AND_UNLOCKED);
         ShadowDeviceConditions.setCurrentConditions(deviceConditionsHighBattery);
 
         // Check impact on starting before native loaded.
@@ -286,7 +290,8 @@
     public void testNoNetwork() throws Exception {
         // Setup no network conditions.
         DeviceConditions deviceConditionsNoNetwork = new DeviceConditions(!POWER_CONNECTED,
-                HIGH_BATTERY_LEVEL, ConnectionType.CONNECTION_NONE, !POWER_SAVE_MODE_ON, !METERED);
+                HIGH_BATTERY_LEVEL, ConnectionType.CONNECTION_NONE, !POWER_SAVE_MODE_ON, !METERED,
+                SCREEN_ON_AND_UNLOCKED);
         ShadowDeviceConditions.setCurrentConditions(deviceConditionsNoNetwork);
 
         // Check impact on starting before native loaded.
@@ -310,9 +315,9 @@
     @Test
     public void testNoNetworkLimitless() throws Exception {
         // Setup no network conditions.
-        DeviceConditions deviceConditionsNoNetwork =
-                new DeviceConditions(!POWER_CONNECTED, 0 /* battery level */,
-                        ConnectionType.CONNECTION_NONE, !POWER_SAVE_MODE_ON, !METERED);
+        DeviceConditions deviceConditionsNoNetwork = new DeviceConditions(!POWER_CONNECTED,
+                0 /* battery level */, ConnectionType.CONNECTION_NONE, !POWER_SAVE_MODE_ON,
+                !METERED, SCREEN_ON_AND_UNLOCKED);
         ShadowDeviceConditions.setCurrentConditions(deviceConditionsNoNetwork);
 
         // Check impact on starting before native loaded.
@@ -336,7 +341,8 @@
     public void testUnmeteredWifiNetwork() throws Exception {
         // Setup unmetered wifi conditions.
         DeviceConditions deviceConditionsUnmeteredWifi = new DeviceConditions(!POWER_CONNECTED,
-                HIGH_BATTERY_LEVEL, ConnectionType.CONNECTION_WIFI, !POWER_SAVE_MODE_ON, !METERED);
+                HIGH_BATTERY_LEVEL, ConnectionType.CONNECTION_WIFI, !POWER_SAVE_MODE_ON, !METERED,
+                SCREEN_ON_AND_UNLOCKED);
         ShadowDeviceConditions.setCurrentConditions(deviceConditionsUnmeteredWifi);
 
         // Check impact on starting before native loaded.
@@ -357,7 +363,8 @@
     public void testMeteredWifiNetwork() throws Exception {
         // Setup metered wifi conditions.
         DeviceConditions deviceConditionsMeteredWifi = new DeviceConditions(!POWER_CONNECTED,
-                HIGH_BATTERY_LEVEL, ConnectionType.CONNECTION_WIFI, !POWER_SAVE_MODE_ON, METERED);
+                HIGH_BATTERY_LEVEL, ConnectionType.CONNECTION_WIFI, !POWER_SAVE_MODE_ON, METERED,
+                SCREEN_ON_AND_UNLOCKED);
         ShadowDeviceConditions.setCurrentConditions(deviceConditionsMeteredWifi);
 
         // Check impact on starting before native loaded.
@@ -378,7 +385,8 @@
     public void test2GNetwork() throws Exception {
         // Setup metered 2g connection conditions.
         DeviceConditions deviceConditions2G = new DeviceConditions(!POWER_CONNECTED,
-                HIGH_BATTERY_LEVEL, ConnectionType.CONNECTION_2G, !POWER_SAVE_MODE_ON, METERED);
+                HIGH_BATTERY_LEVEL, ConnectionType.CONNECTION_2G, !POWER_SAVE_MODE_ON, METERED,
+                SCREEN_ON_AND_UNLOCKED);
         // TODO(petewil): this test name and the condition below do not match.
         ShadowDeviceConditions.setCurrentConditions(deviceConditions2G);
 
@@ -399,9 +407,9 @@
     @Test
     public void testBluetoothNetwork() throws Exception {
         // Setup bluetooth connection conditions.
-        DeviceConditions deviceConditionsBluetooth =
-                new DeviceConditions(!POWER_CONNECTED, HIGH_BATTERY_LEVEL,
-                        ConnectionType.CONNECTION_BLUETOOTH, !POWER_SAVE_MODE_ON, !METERED);
+        DeviceConditions deviceConditionsBluetooth = new DeviceConditions(!POWER_CONNECTED,
+                HIGH_BATTERY_LEVEL, ConnectionType.CONNECTION_BLUETOOTH, !POWER_SAVE_MODE_ON,
+                !METERED, SCREEN_ON_AND_UNLOCKED);
         ShadowDeviceConditions.setCurrentConditions(deviceConditionsBluetooth);
 
         // Check impact on starting before native loaded.
@@ -425,9 +433,9 @@
                 TaskParameters.create(TaskIds.OFFLINE_PAGES_PREFETCH_JOB_ID).build();
 
         // Conditions should be appropriate for running the task.
-        DeviceConditions deviceConditions =
-                new DeviceConditions(POWER_CONNECTED, HIGH_BATTERY_LEVEL - 1,
-                        ConnectionType.CONNECTION_WIFI, !POWER_SAVE_MODE_ON, !METERED);
+        DeviceConditions deviceConditions = new DeviceConditions(POWER_CONNECTED,
+                HIGH_BATTERY_LEVEL - 1, ConnectionType.CONNECTION_WIFI, !POWER_SAVE_MODE_ON,
+                !METERED, SCREEN_ON_AND_UNLOCKED);
         ShadowDeviceConditions.setCurrentConditions(deviceConditions);
 
         mPrefetchBackgroundTask.onStartTask(null, params, new TaskFinishedCallback() {
@@ -447,7 +455,8 @@
     public void testPowerSaverOn() throws Exception {
         // Setup power save mode, battery is high, wifi, not plugged in.
         DeviceConditions deviceConditionsPowerSave = new DeviceConditions(!POWER_CONNECTED,
-                HIGH_BATTERY_LEVEL, ConnectionType.CONNECTION_WIFI, POWER_SAVE_MODE_ON, !METERED);
+                HIGH_BATTERY_LEVEL, ConnectionType.CONNECTION_WIFI, POWER_SAVE_MODE_ON, !METERED,
+                SCREEN_ON_AND_UNLOCKED);
         ShadowDeviceConditions.setCurrentConditions(deviceConditionsPowerSave);
 
         // Check impact on starting before native loaded.
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchActivity.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchActivity.java
index 7edbdb21..09a75c7 100644
--- a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchActivity.java
+++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchActivity.java
@@ -30,7 +30,6 @@
 import org.chromium.chrome.browser.tab.TabDelegateFactory;
 import org.chromium.chrome.browser.tab.TabRedirectHandler;
 import org.chromium.chrome.browser.tab.TabState;
-import org.chromium.chrome.browser.tabmodel.document.TabDelegate;
 import org.chromium.chrome.browser.util.UrlConstants;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.common.Referrer;
@@ -145,6 +144,12 @@
         // we need to clear it due to inactivity, we should do it before calling
         // super#initializeState.
         if (launchNtpDueToInactivity) resetSavedInstanceState();
+
+        ((TouchlessTabCreator) getTabCreator(false))
+                .setTabModel(getTabModelSelector().getModel(false));
+        ((TouchlessTabCreator) getTabCreator(true))
+                .setTabModel(getTabModelSelector().getModel(true));
+
         super.initializeState();
 
         // By this point if we were going to restore a URL from savedInstanceState we would already
@@ -284,7 +289,7 @@
     }
 
     @Override
-    protected TabDelegate createTabDelegate(boolean incognito) {
-        return new TouchlessTabDelegate(incognito);
+    protected TabCreator createTabCreator(boolean incognito) {
+        return new TouchlessTabCreator(this, getWindowAndroid(), incognito);
     }
 }
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessTabCreator.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessTabCreator.java
new file mode 100644
index 0000000..3e9fff8
--- /dev/null
+++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessTabCreator.java
@@ -0,0 +1,119 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+package org.chromium.chrome.browser.touchless;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.provider.Browser;
+
+import androidx.browser.customtabs.CustomTabsIntent;
+
+import org.chromium.base.ContextUtils;
+import org.chromium.chrome.browser.IntentHandler;
+import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider;
+import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider.LaunchSourceType;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tab.TabIdManager;
+import org.chromium.chrome.browser.tabmodel.AsyncTabParamsManager;
+import org.chromium.chrome.browser.tabmodel.ChromeTabCreator;
+import org.chromium.chrome.browser.tabmodel.TabLaunchType;
+import org.chromium.chrome.browser.tabmodel.TabModel;
+import org.chromium.chrome.browser.tabmodel.TabModelOrderController;
+import org.chromium.chrome.browser.tabmodel.document.AsyncTabCreationParams;
+import org.chromium.chrome.browser.tabmodel.document.TabDelegate;
+import org.chromium.chrome.browser.util.UrlUtilities;
+import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.content_public.browser.WebContents;
+import org.chromium.ui.base.WindowAndroid;
+
+/**
+ * Creates Tabs for navigation originating from {@link NoTouchActivity}.
+ *
+ * This is the same as the parent class with exception of opening a Custom Tab instead of creating a
+ * new tab in Chrome for links that open in new tabs.
+ */
+public class TouchlessTabCreator extends ChromeTabCreator {
+    private final TabDelegate mAsyncTabDelegate;
+    private final TabModelOrderController mOrderController;
+
+    public TouchlessTabCreator(NoTouchActivity activity, WindowAndroid window, boolean incognito) {
+        super(activity, window, incognito);
+        mAsyncTabDelegate = new TabDelegate(incognito) {
+            @Override
+            public void createNewTab(
+                    AsyncTabCreationParams asyncParams, @TabLaunchType int type, int parentId) {
+                String url = asyncParams.getLoadUrlParams().getUrl();
+
+                int assignedTabId = TabIdManager.getInstance().generateValidId(Tab.INVALID_TAB_ID);
+                AsyncTabParamsManager.add(assignedTabId, asyncParams);
+
+                Intent intent = new CustomTabsIntent.Builder().setShowTitle(true).build().intent;
+                intent.setData(Uri.parse(url));
+                intent.putExtra(
+                        CustomTabIntentDataProvider.EXTRA_SEND_TO_EXTERNAL_DEFAULT_HANDLER, true);
+                intent.putExtra(CustomTabIntentDataProvider.EXTRA_IS_OPENED_BY_CHROME, true);
+                intent.putExtra(CustomTabIntentDataProvider.EXTRA_IS_OPENED_BY_WEBAPK, false);
+                intent.putExtra(CustomTabIntentDataProvider.EXTRA_BROWSER_LAUNCH_SOURCE,
+                        LaunchSourceType.OTHER);
+                intent.putExtra(Browser.EXTRA_APPLICATION_ID,
+                        ContextUtils.getApplicationContext().getPackageName());
+                addAsyncTabExtras(
+                        asyncParams, parentId, false /* isChromeUI */, assignedTabId, intent);
+
+                IntentHandler.startActivityForTrustedIntent(intent);
+            }
+        };
+
+        mOrderController = new TabModelOrderController() {
+            @Override
+            public int determineInsertionIndex(int type, int position, Tab newTab) {
+                return 0;
+            }
+
+            @Override
+            public int determineInsertionIndex(int type, Tab newTab) {
+                return 0;
+            }
+
+            @Override
+            public boolean willOpenInForeground(int type, boolean isNewTabIncognito) {
+                return true;
+            }
+        };
+    }
+
+    @Override
+    public boolean createTabWithWebContents(
+            Tab parent, WebContents webContents, @TabLaunchType int type, String url) {
+        if (shouldRedirectToCCT(type, url)) {
+            return mAsyncTabDelegate.createTabWithWebContents(parent, webContents, type, url);
+        }
+        return super.createTabWithWebContents(parent, webContents, type, url);
+    }
+
+    @Override
+    public Tab createNewTab(
+            LoadUrlParams loadUrlParams, @TabLaunchType int type, Tab parent, Intent intent) {
+        if (shouldRedirectToCCT(type, loadUrlParams.getUrl())) {
+            return mAsyncTabDelegate.createNewTab(loadUrlParams, type, parent);
+        }
+        return super.createNewTab(loadUrlParams, type, parent, intent);
+    }
+
+    private boolean shouldRedirectToCCT(@TabLaunchType int type, String url) {
+        // Only link clicks should open in CCT, if the browser opens a tab for, say, intent
+        // handling, we should continue to open in NoTouchActivity.
+        // However, we should also handle intent URLs as normal, even if they open in a new window.
+        return isLinkClickLaunchType(type) && !UrlUtilities.validateIntentUrl(url);
+    }
+
+    private boolean isLinkClickLaunchType(@TabLaunchType int type) {
+        return type == TabLaunchType.FROM_LINK || type == TabLaunchType.FROM_LONGPRESS_FOREGROUND
+                || type == TabLaunchType.FROM_LONGPRESS_BACKGROUND;
+    }
+
+    /* package */ void setTabModel(TabModel model) {
+        setTabModel(model, mOrderController);
+    }
+}
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessTabDelegate.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessTabDelegate.java
deleted file mode 100644
index 92a7084..0000000
--- a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessTabDelegate.java
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-package org.chromium.chrome.browser.touchless;
-
-import android.content.Intent;
-import android.net.Uri;
-import android.provider.Browser;
-
-import org.chromium.base.ContextUtils;
-import org.chromium.chrome.browser.IntentHandler;
-import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider;
-import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider.LaunchSourceType;
-import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.tab.TabIdManager;
-import org.chromium.chrome.browser.tabmodel.AsyncTabParamsManager;
-import org.chromium.chrome.browser.tabmodel.TabLaunchType;
-import org.chromium.chrome.browser.tabmodel.document.AsyncTabCreationParams;
-import org.chromium.chrome.browser.tabmodel.document.TabDelegate;
-import org.chromium.chrome.browser.util.UrlUtilities;
-
-import androidx.browser.customtabs.CustomTabsIntent;
-
-/**
- * Asynchronously creates Tabs for navigation originating from {@link NoTouchActivity}.
- *
- * This is the same as the parent class with exception of opening a Custom Tab instead of creating a
- * new tab in Chrome.
- */
-public class TouchlessTabDelegate extends TabDelegate {
-    public TouchlessTabDelegate(boolean incognito) {
-        super(incognito);
-    }
-
-    @Override
-    public void createNewTab(
-            AsyncTabCreationParams asyncParams, @TabLaunchType int type, int parentId) {
-        if (!isLinkClickLaunchType(type)) {
-            // Only link clicks should open in CCT, if the browser opens a tab for, say, intent
-            // handling, we should continue to open in NoTouchActivity.
-            super.createNewTab(asyncParams, type, parentId);
-            return;
-        }
-        if (UrlUtilities.validateIntentUrl(asyncParams.getLoadUrlParams().getUrl())) {
-            // Handle intent URLs as normal.
-            super.createNewTab(asyncParams, type, parentId);
-            return;
-        }
-
-        String url = asyncParams.getLoadUrlParams().getUrl();
-
-        int assignedTabId = TabIdManager.getInstance().generateValidId(Tab.INVALID_TAB_ID);
-        AsyncTabParamsManager.add(assignedTabId, asyncParams);
-
-        Intent intent = new CustomTabsIntent.Builder().setShowTitle(true).build().intent;
-        intent.setData(Uri.parse(url));
-        intent.putExtra(CustomTabIntentDataProvider.EXTRA_SEND_TO_EXTERNAL_DEFAULT_HANDLER, true);
-        intent.putExtra(CustomTabIntentDataProvider.EXTRA_IS_OPENED_BY_CHROME, true);
-        intent.putExtra(CustomTabIntentDataProvider.EXTRA_IS_OPENED_BY_WEBAPK, false);
-        intent.putExtra(
-                CustomTabIntentDataProvider.EXTRA_BROWSER_LAUNCH_SOURCE, LaunchSourceType.OTHER);
-        intent.putExtra(Browser.EXTRA_APPLICATION_ID,
-                ContextUtils.getApplicationContext().getPackageName());
-        addAsyncTabExtras(asyncParams, parentId, false /* isChromeUI */, assignedTabId, intent);
-
-        IntentHandler.startActivityForTrustedIntent(intent);
-    }
-
-    private boolean isLinkClickLaunchType(@TabLaunchType int type) {
-        return type == TabLaunchType.FROM_LINK || type == TabLaunchType.FROM_LONGPRESS_FOREGROUND
-                || type == TabLaunchType.FROM_LONGPRESS_BACKGROUND;
-    }
-}
diff --git a/chrome/android/touchless/javatests/src/org/chromium/chrome/browser/touchless/TouchlessNavigationRecorderTest.java b/chrome/android/touchless/javatests/src/org/chromium/chrome/browser/touchless/TouchlessNavigationRecorderTest.java
index 087f132..6ec505ff 100644
--- a/chrome/android/touchless/javatests/src/org/chromium/chrome/browser/touchless/TouchlessNavigationRecorderTest.java
+++ b/chrome/android/touchless/javatests/src/org/chromium/chrome/browser/touchless/TouchlessNavigationRecorderTest.java
@@ -85,8 +85,10 @@
 
         ChromeTabUtils.waitForTabPageLoaded(mInitialTab, (String) null);
 
-        // This will trigger an intent and use PageTransition.FROM_API.
-        mActivityTestRule.getActivity().getTabCreator(false).launchNTP();
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            // This will trigger an intent and use PageTransition.FROM_API.
+            mActivityTestRule.getActivity().getTabCreator(false).launchNTP();
+        });
         callback.waitForCallback(0);
     }
 
diff --git a/chrome/android/touchless/touchless_java_sources.gni b/chrome/android/touchless/touchless_java_sources.gni
index defeeea..05cd5780 100644
--- a/chrome/android/touchless/touchless_java_sources.gni
+++ b/chrome/android/touchless/touchless_java_sources.gni
@@ -44,7 +44,7 @@
   "touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessPreferences.java",
   "touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessRecyclerView.java",
   "touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessSuggestionsBinder.java",
-  "touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessTabDelegate.java",
+  "touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessTabCreator.java",
   "touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessTabObserver.java",
   "touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessUiCoordinator.java",
   "touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessUiCoordinatorImpl.java",
diff --git a/chrome/android/webapk/shell_apk/BUILD.gn b/chrome/android/webapk/shell_apk/BUILD.gn
index b70ca4a..e21dd83 100644
--- a/chrome/android/webapk/shell_apk/BUILD.gn
+++ b/chrome/android/webapk/shell_apk/BUILD.gn
@@ -187,9 +187,6 @@
     native_lib_placeholders = [ "libfoo.so" ]
 
     if (!is_java_debug) {
-      if (defined(webapk_proguard_jar_path)) {
-        proguard_jar_path = webapk_proguard_jar_path
-      }
       proguard_enabled = true
       proguard_configs = [
         "//chrome/android/webapk/shell_apk/proguard.flags",
diff --git a/chrome/app/chrome_command_ids.h b/chrome/app/chrome_command_ids.h
index f91d2a2..715865c6 100644
--- a/chrome/app/chrome_command_ids.h
+++ b/chrome/app/chrome_command_ids.h
@@ -333,6 +333,8 @@
 // Context menu items for Sharing
 #define IDC_CONTENT_CONTEXT_SHARING_CLICK_TO_CALL_SINGLE_DEVICE 51030
 #define IDC_CONTENT_CONTEXT_SHARING_CLICK_TO_CALL_MULTIPLE_DEVICES 51031
+#define IDC_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_SINGLE_DEVICE 51032
+#define IDC_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_MULTIPLE_DEVICES 51033
 
 // Context menu items in the status tray
 #define IDC_STATUS_TRAY_KEEP_CHROME_RUNNING_IN_BACKGROUND 51100
diff --git a/chrome/app/helper-gpu-entitlements.plist b/chrome/app/helper-gpu-entitlements.plist
index a1c430a..d35e43a 100644
--- a/chrome/app/helper-gpu-entitlements.plist
+++ b/chrome/app/helper-gpu-entitlements.plist
@@ -2,7 +2,7 @@
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
-	<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
+	<key>com.apple.security.cs.allow-jit</key>
 	<true/>
 </dict>
 </plist>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 48fecf1..75c6d6a 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -3367,6 +3367,8 @@
       "sharing/click_to_call/click_to_call_ui_controller.h",
       "sharing/click_to_call/click_to_call_utils.cc",
       "sharing/click_to_call/click_to_call_utils.h",
+      "sharing/shared_clipboard/shared_clipboard_context_menu_observer.cc",
+      "sharing/shared_clipboard/shared_clipboard_context_menu_observer.h",
       "sharing/shared_clipboard/shared_clipboard_ui_controller.cc",
       "sharing/shared_clipboard/shared_clipboard_ui_controller.h",
       "sharing/sharing_dialog.h",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 7c61660e..b2e6be39 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1096,11 +1096,16 @@
 
 const FeatureEntry::FeatureParam kFilteringPredictionEmptyFilterEnabled[] = {
     {"filter", ui::input_prediction::kFilterNameEmpty}};
+const FeatureEntry::FeatureParam kFilteringPredictionOneEuroFilterEnabled[] = {
+    {"filter", ui::input_prediction::kFilterNameOneEuro}};
 
 const FeatureEntry::FeatureVariation kFilteringPredictionFeatureVariations[] = {
     {ui::input_prediction::kFilterNameEmpty,
      kFilteringPredictionEmptyFilterEnabled,
-     base::size(kFilteringPredictionEmptyFilterEnabled), nullptr}};
+     base::size(kFilteringPredictionEmptyFilterEnabled), nullptr},
+    {ui::input_prediction::kFilterNameOneEuro,
+     kFilteringPredictionOneEuroFilterEnabled,
+     base::size(kFilteringPredictionOneEuroFilterEnabled), nullptr}};
 
 #if defined(OS_ANDROID)
 const FeatureEntry::FeatureParam kBottomOfflineIndicatorEnabled[] = {
diff --git a/chrome/browser/android/servicification_background_service_jni.cc b/chrome/browser/android/servicification_background_service_jni.cc
index eacdc3a..6461df9 100644
--- a/chrome/browser/android/servicification_background_service_jni.cc
+++ b/chrome/browser/android/servicification_background_service_jni.cc
@@ -52,36 +52,58 @@
           std::move(mapped), 0, 0, base::StringPiece(), /* read_only */ true);
   if (memory_allocator->GetMemoryState() ==
       base::PersistentMemoryAllocator::MEMORY_DELETED) {
+    LOG(ERROR) << "The memory allocator state shouldn't be MEMORY_DELETED!";
     return false;
   }
-  if (memory_allocator->IsCorrupt())
-    return false;
 
-  if (!metrics::PersistentSystemProfile::HasSystemProfile(*memory_allocator))
+  if (memory_allocator->IsCorrupt()) {
+    LOG(ERROR) << "The memory allocator is corrupt!";
     return false;
+  }
+
+  if (!metrics::PersistentSystemProfile::HasSystemProfile(*memory_allocator)) {
+    LOG(ERROR) << "There isn't a System Profile!";
+    return false;
+  }
 
   metrics::SystemProfileProto system_profile_proto;
   if (!metrics::PersistentSystemProfile::GetSystemProfile(
-          *memory_allocator, &system_profile_proto))
+          *memory_allocator, &system_profile_proto)) {
+    LOG(ERROR) << "Failed to get the System Profile!";
     return false;
+  }
 
-  if (!system_profile_proto.has_os())
+  if (!system_profile_proto.has_os()) {
+    LOG(ERROR) << "The os info isn't set!";
     return false;
+  }
 
   const metrics::SystemProfileProto_OS& os = system_profile_proto.os();
-  if (!os.has_version())
+  if (!os.has_version()) {
+    LOG(ERROR) << "The os version isn't set!";
     return false;
+  }
 
-  if (base::SysInfo::OperatingSystemVersion().compare(os.version()) != 0)
+  if (base::SysInfo::OperatingSystemVersion().compare(os.version()) != 0) {
+    LOG(ERROR) << "The os version doesn't match!";
     return false;
+  }
 
   std::vector<variations::ActiveGroupId> field_trial_ids;
   variations::GetFieldTrialActiveGroupIds("", &field_trial_ids);
+  int expected_size = static_cast<int>(field_trial_ids.size());
 
-  int expeceted_size = static_cast<int>(field_trial_ids.size());
-  // The active field trial "PersistentHistograms" is guaranteed in the list.
-  if (expeceted_size <= 0)
+  // The active field trial "Foo" is guaranteed in the list.
+  if (expected_size <= 0) {
+    LOG(ERROR) << "Expect at least one active field trial!";
     return false;
+  }
 
-  return system_profile_proto.field_trial_size() == expeceted_size;
+  if (system_profile_proto.field_trial_size() != expected_size) {
+    LOG(ERROR) << "The size of field trials recorded in the System Profile"
+               << " doesn't match the size of active field trials!";
+    return false;
+  }
+
+  return true;
 }
diff --git a/chrome/browser/autofill/automated_tests/cache_replayer.cc b/chrome/browser/autofill/automated_tests/cache_replayer.cc
index 421361a2..ba42c0c 100644
--- a/chrome/browser/autofill/automated_tests/cache_replayer.cc
+++ b/chrome/browser/autofill/automated_tests/cache_replayer.cc
@@ -526,6 +526,7 @@
     VLOG(1) << "Did not match any response for " << key;
     return false;
   }
+  VLOG(1) << "Retrieving response for " << key;
   std::string decompressed_http_response;
   // Safe to use at() here since we looked for key's presence and there is no
   // mutation done when there is concurrency.
diff --git a/chrome/browser/autofill/captured_sites_test_utils.cc b/chrome/browser/autofill/captured_sites_test_utils.cc
index 896627e..89eb1e0 100644
--- a/chrome/browser/autofill/captured_sites_test_utils.cc
+++ b/chrome/browser/autofill/captured_sites_test_utils.cc
@@ -449,6 +449,10 @@
   args.push_back(base::StringPrintf("--http_port=%d", kHostHttpPort));
   args.push_back(base::StringPrintf("--https_port=%d", kHostHttpsPort));
   args.push_back("--serve_response_in_chronological_sequence");
+  // Start WPR in quiet mode, removing the extra verbose ServeHTTP interactions
+  // that are for the the overwhelming majority unhelpful, but for extra
+  // debugging of a test case, this might make sense to comment out.
+  args.push_back("--quiet_mode");
   args.push_back(base::StringPrintf(
       "--inject_scripts=%s,%s",
       FilePathToUTF8(src_dir.AppendASCII("third_party")
diff --git a/chrome/browser/certificate_manager_model.cc b/chrome/browser/certificate_manager_model.cc
index b140b5d..c175586 100644
--- a/chrome/browser/certificate_manager_model.cc
+++ b/chrome/browser/certificate_manager_model.cc
@@ -36,6 +36,7 @@
 #include "chrome/browser/chromeos/certificate_provider/certificate_provider_service_factory.h"
 #include "chrome/browser/chromeos/policy/user_network_configuration_updater.h"
 #include "chrome/browser/chromeos/policy/user_network_configuration_updater_factory.h"
+#include "chromeos/network/onc/certificate_scope.h"
 #include "chromeos/network/policy_certificate_provider.h"
 #endif
 
@@ -308,11 +309,13 @@
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     switch (mode_) {
       case Mode::kPolicyCertsWithoutWebTrust:
-        RefreshImpl(policy_certs_provider_->GetCertificatesWithoutWebTrust(),
+        RefreshImpl(policy_certs_provider_->GetCertificatesWithoutWebTrust(
+                        chromeos::onc::CertificateScope::Default()),
                     false /* policy_web_trusted */);
         break;
       case Mode::kPolicyCertsWithWebTrust:
-        RefreshImpl(policy_certs_provider_->GetWebTrustedCertificates(),
+        RefreshImpl(policy_certs_provider_->GetWebTrustedCertificates(
+                        chromeos::onc::CertificateScope::Default()),
                     true /* policy_web_trusted */);
         break;
       default:
diff --git a/chrome/browser/certificate_manager_model_unittest.cc b/chrome/browser/certificate_manager_model_unittest.cc
index 5551587..d071c00 100644
--- a/chrome/browser/certificate_manager_model_unittest.cc
+++ b/chrome/browser/certificate_manager_model_unittest.cc
@@ -18,6 +18,7 @@
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/certificate_provider/certificate_provider.h"
+#include "chromeos/network/onc/certificate_scope.h"
 #include "chromeos/network/policy_certificate_provider.h"
 #endif
 
@@ -202,7 +203,11 @@
     observer_list_.RemoveObserver(observer);
   }
 
-  net::CertificateList GetAllServerAndAuthorityCertificates() const override {
+  net::CertificateList GetAllServerAndAuthorityCertificates(
+      const chromeos::onc::CertificateScope& scope) const override {
+    // The CertificateManagerModel only retrieves profile-wide certificates.
+    EXPECT_EQ(chromeos::onc::CertificateScope::Default(), scope);
+
     net::CertificateList merged;
     merged.insert(merged.end(), web_trusted_certs_.begin(),
                   web_trusted_certs_.end());
@@ -211,20 +216,36 @@
     return merged;
   }
 
-  net::CertificateList GetAllAuthorityCertificates() const override {
+  net::CertificateList GetAllAuthorityCertificates(
+      const chromeos::onc::CertificateScope& scope) const override {
     // This function is not called by CertificateManagerModel.
     NOTREACHED();
     return net::CertificateList();
   }
 
-  net::CertificateList GetWebTrustedCertificates() const override {
+  net::CertificateList GetWebTrustedCertificates(
+      const chromeos::onc::CertificateScope& scope) const override {
+    // The CertificateManagerModel only retrieves profile-wide certificates.
+    EXPECT_EQ(chromeos::onc::CertificateScope::Default(), scope);
+
     return web_trusted_certs_;
   }
 
-  net::CertificateList GetCertificatesWithoutWebTrust() const override {
+  net::CertificateList GetCertificatesWithoutWebTrust(
+      const chromeos::onc::CertificateScope& scope) const override {
+    // The CertificateManagerModel only retrieves profile-wide certificates.
+    EXPECT_EQ(chromeos::onc::CertificateScope::Default(), scope);
+
     return not_web_trusted_certs_;
   }
 
+  const std::set<std::string>& GetExtensionIdsWithPolicyCertificates()
+      const override {
+    // This function is not called by CertificateManagerModel.
+    NOTREACHED();
+    return kNoExtensions;
+  }
+
   void SetPolicyProvidedCertificates(
       const net::CertificateList& web_trusted_certs,
       const net::CertificateList& not_web_trusted_certs) {
@@ -242,6 +263,7 @@
                      true /* check_empty */>::Unchecked observer_list_;
   net::CertificateList web_trusted_certs_;
   net::CertificateList not_web_trusted_certs_;
+  const std::set<std::string> kNoExtensions = {};
 };
 
 class FakeExtensionCertificateProvider : public chromeos::CertificateProvider {
diff --git a/chrome/browser/chromeos/crostini/crostini_export_import.cc b/chrome/browser/chromeos/crostini/crostini_export_import.cc
index 3f7363a..4f87d72 100644
--- a/chrome/browser/chromeos/crostini/crostini_export_import.cc
+++ b/chrome/browser/chromeos/crostini/crostini_export_import.cc
@@ -8,7 +8,6 @@
 
 #include "base/bind.h"
 #include "base/files/file_util.h"
-#include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/stringprintf.h"
 #include "base/task/post_task.h"
@@ -240,8 +239,7 @@
     const base::Time& start,
     const ContainerId& container_id,
     CrostiniManager::CrostiniResultCallback callback,
-    CrostiniResult result,
-    uint64_t container_size) {
+    CrostiniResult result) {
   auto it = notifications_.find(container_id);
   DCHECK(it != notifications_.end())
       << ContainerIdToString(container_id) << " has no notification to update";
@@ -264,43 +262,6 @@
       case CrostiniExportImportNotification::Status::RUNNING:
         UMA_HISTOGRAM_LONG_TIMES("Crostini.BackupTimeSuccess",
                                  base::Time::Now() - start);
-        // Log backup size statistics.
-        // TODO(juwa): Send compressed bytes written in progress message from
-        // tremplin, to remove the need to read the file's size.
-        base::PostTask(
-            FROM_HERE,
-            {base::ThreadPool(), base::MayBlock(),
-             base::TaskPriority::BEST_EFFORT},
-            base::BindOnce(
-                [](const base::FilePath& path, uint64_t size) {
-                  if (size == 0) {
-                    LOG(ERROR) << "Uncompressed container size from export "
-                                  "progress is zero.";
-                    NOTREACHED();
-                    return;
-                  }
-                  uint64_t compressed_size{};
-                  {
-                    int64_t file_size;
-                    if (!base::GetFileSize(path, &file_size) || file_size < 0) {
-                      LOG(ERROR) << "Couldn't get exported file size for "
-                                    "histogram";
-                      return;
-                    }
-                    compressed_size = static_cast<uint64_t>(file_size);
-                  }
-
-                  base::UmaHistogramCustomCounts(
-                      "Crostini.BackupUncompressedSizeLog2",
-                      std::round(std::log2(size)), 0, 50, 50);
-                  base::UmaHistogramCustomCounts(
-                      "Crostini.BackupCompressedSizeLog2",
-                      std::round(std::log2(compressed_size)), 0, 50, 50);
-                  base::UmaHistogramPercentage(
-                      "Crostini.BackupCompressionRatio",
-                      std::round(compressed_size * 100.0 / size));
-                },
-                it->second->path(), container_size));
         RemoveNotification(it).SetStatusDone();
         break;
       default:
diff --git a/chrome/browser/chromeos/crostini/crostini_export_import.h b/chrome/browser/chromeos/crostini/crostini_export_import.h
index 2d37bb2f..7284cdc7 100644
--- a/chrome/browser/chromeos/crostini/crostini_export_import.h
+++ b/chrome/browser/chromeos/crostini/crostini_export_import.h
@@ -164,8 +164,7 @@
   void OnExportComplete(const base::Time& start,
                         const ContainerId& container_id,
                         CrostiniManager::CrostiniResultCallback callback,
-                        CrostiniResult result,
-                        uint64_t container_size);
+                        CrostiniResult result);
 
   void ImportAfterSharing(const ContainerId& container_id,
                           CrostiniManager::CrostiniResultCallback callback,
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.cc b/chrome/browser/chromeos/crostini/crostini_manager.cc
index 7dd2892f..9ec4e99 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager.cc
@@ -82,16 +82,16 @@
   GetCiceroneClient()->WaitForServiceToBeAvailable(std::move(callback));
 }
 
-// Find any callbacks for the specified |vm_name|, invoke them with
-// |arguments|... and erase them from the map.
-template <typename... Arguments>
+// Find any callbacks for the specified |vm_name|, invoke them with |result|
+// and erase them from the map.
 void InvokeAndErasePendingCallbacks(
-    std::map<ContainerId, base::OnceCallback<void(Arguments...)>>* vm_keyed_map,
+    std::map<ContainerId, CrostiniManager::CrostiniResultCallback>*
+        vm_keyed_map,
     const std::string& vm_name,
-    Arguments&&... arguments) {
+    CrostiniResult result) {
   for (auto it = vm_keyed_map->begin(); it != vm_keyed_map->end();) {
     if (it->first.first == vm_name) {
-      std::move(it->second).Run(arguments...);
+      std::move(it->second).Run(result);
       vm_keyed_map->erase(it++);
     } else {
       ++it;
@@ -1096,25 +1096,23 @@
                      request.container_name(), std::move(callback)));
 }
 
-void CrostiniManager::ExportLxdContainer(
-    std::string vm_name,
-    std::string container_name,
-    base::FilePath export_path,
-    base::OnceCallback<void(CrostiniResult success, uint64_t container_size)>
-        callback) {
+void CrostiniManager::ExportLxdContainer(std::string vm_name,
+                                         std::string container_name,
+                                         base::FilePath export_path,
+                                         CrostiniResultCallback callback) {
   if (vm_name.empty()) {
     LOG(ERROR) << "vm_name is required";
-    std::move(callback).Run(CrostiniResult::CLIENT_ERROR, 0);
+    std::move(callback).Run(CrostiniResult::CLIENT_ERROR);
     return;
   }
   if (container_name.empty()) {
     LOG(ERROR) << "container_name is required";
-    std::move(callback).Run(CrostiniResult::CLIENT_ERROR, 0);
+    std::move(callback).Run(CrostiniResult::CLIENT_ERROR);
     return;
   }
   if (export_path.empty()) {
     LOG(ERROR) << "export_path is required";
-    std::move(callback).Run(CrostiniResult::CLIENT_ERROR, 0);
+    std::move(callback).Run(CrostiniResult::CLIENT_ERROR);
     return;
   }
 
@@ -1123,7 +1121,7 @@
       export_lxd_container_callbacks_.end()) {
     LOG(ERROR) << "Export currently in progress for " << vm_name << ", "
                << container_name;
-    std::move(callback).Run(CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED, 0);
+    std::move(callback).Run(CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED);
     return;
   }
   export_lxd_container_callbacks_.emplace(key, std::move(callback));
@@ -1779,7 +1777,7 @@
   // be marked as failed.
   InvokeAndErasePendingCallbacks(
       &export_lxd_container_callbacks_, vm_name,
-      CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_VM_STARTED, uint64_t{0});
+      CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_VM_STARTED);
   InvokeAndErasePendingCallbacks(
       &import_lxd_container_callbacks_, vm_name,
       CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_VM_STARTED);
@@ -1859,7 +1857,7 @@
   running_containers_.erase(vm_name);
   InvokeAndErasePendingCallbacks(
       &export_lxd_container_callbacks_, vm_name,
-      CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_VM_STOPPED, uint64_t{0});
+      CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_VM_STOPPED);
   InvokeAndErasePendingCallbacks(
       &import_lxd_container_callbacks_, vm_name,
       CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_VM_STOPPED);
@@ -2445,8 +2443,7 @@
 
   if (!response) {
     LOG(ERROR) << "Failed to export lxd container. Empty response.";
-    std::move(it->second)
-        .Run(CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED, 0);
+    std::move(it->second).Run(CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED);
     export_lxd_container_callbacks_.erase(it);
     return;
   }
@@ -2458,8 +2455,7 @@
       vm_tools::cicerone::ExportLxdContainerResponse::EXPORTING) {
     LOG(ERROR) << "Failed to export container: status=" << response->status()
                << ", failure_reason=" << response->failure_reason();
-    std::move(it->second)
-        .Run(CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED, 0);
+    std::move(it->second).Run(CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED);
     export_lxd_container_callbacks_.erase(it);
   }
 }
@@ -2520,7 +2516,7 @@
                << signal.container_name();
     return;
   }
-  std::move(it->second).Run(result, signal.input_bytes_streamed());
+  std::move(it->second).Run(result);
   export_lxd_container_callbacks_.erase(it);
 }
 
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.h b/chrome/browser/chromeos/crostini/crostini_manager.h
index cd651e4..48ca586b 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.h
+++ b/chrome/browser/chromeos/crostini/crostini_manager.h
@@ -255,12 +255,10 @@
   // Checks the arguments for exporting an Lxd container via
   // CiceroneClient::ExportLxdContainer. |callback| is called immediately if the
   // arguments are bad, or after the method call finishes.
-  void ExportLxdContainer(
-      std::string vm_name,
-      std::string container_name,
-      base::FilePath export_path,
-      base::OnceCallback<void(CrostiniResult result, uint64_t container_size)>
-          callback);
+  void ExportLxdContainer(std::string vm_name,
+                          std::string container_name,
+                          base::FilePath export_path,
+                          CrostiniResultCallback callback);
 
   // Checks the arguments for importing an Lxd container via
   // CiceroneClient::ImportLxdContainer. |callback| is called immediately if the
@@ -718,10 +716,7 @@
   std::multimap<ContainerId, CrostiniResultCallback>
       create_lxd_container_callbacks_;
   std::multimap<ContainerId, BoolCallback> delete_lxd_container_callbacks_;
-  std::map<
-      ContainerId,
-      base::OnceCallback<void(CrostiniResult result, uint64_t container_size)>>
-      export_lxd_container_callbacks_;
+  std::map<ContainerId, CrostiniResultCallback> export_lxd_container_callbacks_;
   std::map<ContainerId, CrostiniResultCallback> import_lxd_container_callbacks_;
 
   // Callbacks to run after Tremplin is started, keyed by vm_name. These are
diff --git a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
index 2e0746a3..fb8a6a86 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
@@ -55,16 +55,6 @@
   std::move(closure).Run();
 }
 
-void ExpectCrostiniExportResult(base::OnceClosure closure,
-                                CrostiniResult expected_result,
-                                uint64_t expected_container_size,
-                                CrostiniResult result,
-                                uint64_t container_size) {
-  EXPECT_EQ(expected_result, result);
-  EXPECT_EQ(expected_container_size, container_size);
-  std::move(closure).Run();
-}
-
 }  // namespace
 
 class CrostiniManagerTest : public testing::Test {
@@ -1113,8 +1103,8 @@
 TEST_F(CrostiniManagerTest, ExportContainerSuccess) {
   crostini_manager()->ExportLxdContainer(
       kVmName, kContainerName, base::FilePath("export_path"),
-      base::BindOnce(&ExpectCrostiniExportResult, run_loop()->QuitClosure(),
-                     CrostiniResult::SUCCESS, 123));
+      base::BindOnce(&ExpectCrostiniResult, run_loop()->QuitClosure(),
+                     CrostiniResult::SUCCESS));
 
   // Send signals, PACK, DOWNLOAD, DONE.
   vm_tools::cicerone::ExportLxdContainerProgressSignal signal;
@@ -1132,7 +1122,6 @@
 
   signal.set_status(
       vm_tools::cicerone::ExportLxdContainerProgressSignal_Status_DONE);
-  signal.set_input_bytes_streamed(123);
   fake_cicerone_client_->NotifyExportLxdContainerProgress(signal);
 
   run_loop()->Run();
@@ -1142,14 +1131,14 @@
   // 1st call succeeds.
   crostini_manager()->ExportLxdContainer(
       kVmName, kContainerName, base::FilePath("export_path"),
-      base::BindOnce(&ExpectCrostiniExportResult, run_loop()->QuitClosure(),
-                     CrostiniResult::SUCCESS, 123));
+      base::BindOnce(&ExpectCrostiniResult, run_loop()->QuitClosure(),
+                     CrostiniResult::SUCCESS));
 
   // 2nd call fails since 1st call is in progress.
   crostini_manager()->ExportLxdContainer(
       kVmName, kContainerName, base::FilePath("export_path"),
-      base::BindOnce(&ExpectCrostiniExportResult, base::DoNothing::Once(),
-                     CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED, 0));
+      base::BindOnce(&ExpectCrostiniResult, base::DoNothing::Once(),
+                     CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED));
 
   // Send signal to indicate 1st call is done.
   vm_tools::cicerone::ExportLxdContainerProgressSignal signal;
@@ -1158,7 +1147,6 @@
   signal.set_container_name(kContainerName);
   signal.set_status(
       vm_tools::cicerone::ExportLxdContainerProgressSignal_Status_DONE);
-  signal.set_input_bytes_streamed(123);
   fake_cicerone_client_->NotifyExportLxdContainerProgress(signal);
 
   run_loop()->Run();
@@ -1167,8 +1155,8 @@
 TEST_F(CrostiniManagerTest, ExportContainerFailFromSignal) {
   crostini_manager()->ExportLxdContainer(
       kVmName, kContainerName, base::FilePath("export_path"),
-      base::BindOnce(&ExpectCrostiniExportResult, run_loop()->QuitClosure(),
-                     CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED, 123));
+      base::BindOnce(&ExpectCrostiniResult, run_loop()->QuitClosure(),
+                     CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED));
 
   // Send signal with FAILED.
   vm_tools::cicerone::ExportLxdContainerProgressSignal signal;
@@ -1177,7 +1165,6 @@
   signal.set_container_name(kContainerName);
   signal.set_status(
       vm_tools::cicerone::ExportLxdContainerProgressSignal_Status_FAILED);
-  signal.set_input_bytes_streamed(123);
   fake_cicerone_client_->NotifyExportLxdContainerProgress(signal);
 
   run_loop()->Run();
@@ -1187,9 +1174,9 @@
   crostini_manager()->AddRunningVmForTesting(kVmName);
   crostini_manager()->ExportLxdContainer(
       kVmName, kContainerName, base::FilePath("export_path"),
-      base::BindOnce(&ExpectCrostiniExportResult, run_loop()->QuitClosure(),
-                     CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_VM_STOPPED,
-                     0));
+      base::BindOnce(
+          &ExpectCrostiniResult, run_loop()->QuitClosure(),
+          CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_VM_STOPPED));
   crostini_manager()->StopVm(kVmName, base::DoNothing());
   run_loop()->Run();
 }
diff --git a/chrome/browser/chromeos/dbus/cryptohome_key_delegate_service_provider_browsertest.cc b/chrome/browser/chromeos/dbus/cryptohome_key_delegate_service_provider_browsertest.cc
index 9a7e2d9..5f6725e 100644
--- a/chrome/browser/chromeos/dbus/cryptohome_key_delegate_service_provider_browsertest.cc
+++ b/chrome/browser/chromeos/dbus/cryptohome_key_delegate_service_provider_browsertest.cc
@@ -31,11 +31,7 @@
 #include "content/public/browser/browser_context.h"
 #include "dbus/message.h"
 #include "dbus/object_path.h"
-#include "extensions/browser/deferred_start_render_host.h"
-#include "extensions/browser/deferred_start_render_host_observer.h"
-#include "extensions/browser/extension_host.h"
-#include "extensions/browser/process_manager.h"
-#include "extensions/browser/process_manager_observer.h"
+#include "extensions/test/test_background_page_first_load_observer.h"
 #include "net/cert/asn1_util.h"
 #include "net/cert/x509_certificate.h"
 #include "net/cert/x509_util.h"
@@ -56,68 +52,6 @@
   return spki_bytes.as_string();
 }
 
-// Observer that allows to wait until the extension's background page was first
-// loaded.
-// TODO(crbug.com/826417): Extract into a generic helper to be usable in other
-// tests.
-class ExtensionBackgroundPageFirstLoadObserver final
-    : public extensions::ProcessManagerObserver,
-      public extensions::DeferredStartRenderHostObserver {
- public:
-  ExtensionBackgroundPageFirstLoadObserver(
-      content::BrowserContext* browser_context,
-      const std::string& extension_id)
-      : extension_id_(extension_id),
-        process_manager_(extensions::ProcessManager::Get(browser_context)) {
-    process_manager_->AddObserver(this);
-    extension_host_ =
-        process_manager_->GetBackgroundHostForExtension(extension_id_);
-    if (extension_host_)
-      OnObtainedExtensionHost();
-  }
-
-  ~ExtensionBackgroundPageFirstLoadObserver() override {
-    if (extension_host_) {
-      static_cast<extensions::DeferredStartRenderHost*>(extension_host_)
-          ->RemoveDeferredStartRenderHostObserver(this);
-    }
-    process_manager_->RemoveObserver(this);
-  }
-
-  void Wait() {
-    if (!extension_host_ || !extension_host_->has_loaded_once())
-      run_loop_.Run();
-  }
-
- private:
-  // extensions::ProcessManagerObserver:
-  void OnBackgroundHostCreated(extensions::ExtensionHost* host) override {
-    if (host->extension_id() == extension_id_) {
-      DCHECK(!extension_host_);
-      extension_host_ = host;
-      OnObtainedExtensionHost();
-    }
-  }
-
-  // extensions::DeferredStartRenderHostObserver:
-  void OnDeferredStartRenderHostDidStopFirstLoad(
-      const extensions::DeferredStartRenderHost* /* host */) override {
-    run_loop_.Quit();
-  }
-
-  void OnObtainedExtensionHost() {
-    static_cast<extensions::DeferredStartRenderHost*>(extension_host_)
-        ->AddDeferredStartRenderHostObserver(this);
-  }
-
-  const std::string extension_id_;
-  extensions::ProcessManager* const process_manager_;
-  extensions::ExtensionHost* extension_host_ = nullptr;
-  base::RunLoop run_loop_;
-
-  DISALLOW_COPY_AND_ASSIGN(ExtensionBackgroundPageFirstLoadObserver);
-};
-
 }  // namespace
 
 // Tests for the CryptohomeKeyDelegateServiceProvider class.
@@ -251,7 +185,7 @@
     cert_provider_extension_ =
         std::make_unique<TestCertificateProviderExtension>(profile,
                                                            kExtensionId);
-    ExtensionBackgroundPageFirstLoadObserver bg_page_first_load_observer(
+    extensions::TestBackgroundPageFirstLoadObserver bg_page_first_load_observer(
         profile, kExtensionId);
     AddExtensionForForceInstallation(kExtensionId,
                                      kExtensionUpdateManifestPath);
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
index 578a46df..31fd0ad 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
@@ -80,6 +80,7 @@
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/upstart/upstart_client.h"
 #include "chromeos/login/login_state/login_state.h"
+#include "chromeos/network/onc/certificate_scope.h"
 #include "chromeos/network/proxy/proxy_config_service_impl.h"
 #include "chromeos/settings/cros_settings_names.h"
 #include "chromeos/timezone/timezone_resolver.h"
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater.cc b/chrome/browser/chromeos/policy/network_configuration_updater.cc
index b3f5f15..888bcc0 100644
--- a/chrome/browser/chromeos/policy/network_configuration_updater.cc
+++ b/chrome/browser/chromeos/policy/network_configuration_updater.cc
@@ -14,6 +14,7 @@
 #include "net/cert/x509_certificate.h"
 #include "net/cert/x509_util_nss.h"
 
+using chromeos::onc::CertificateScope;
 using chromeos::onc::OncParsedCertificates;
 
 namespace policy {
@@ -24,19 +25,37 @@
 using ServerOrAuthorityCertPredicate = base::RepeatingCallback<bool(
     const OncParsedCertificates::ServerOrAuthorityCertificate& cert)>;
 
+// Returns a filtered copy of |sever_or_authority_certificates|. The filtered
+// copy will contain  a certificate from the input iff it matches |scope| and
+// executing |predicate| on it returned true.
 net::CertificateList GetFilteredCertificateListFromOnc(
     const std::vector<OncParsedCertificates::ServerOrAuthorityCertificate>&
         server_or_authority_certificates,
+    const CertificateScope& scope,
     ServerOrAuthorityCertPredicate predicate) {
   net::CertificateList certificates;
   for (const auto& server_or_authority_cert :
        server_or_authority_certificates) {
-    if (predicate.Run(server_or_authority_cert))
+    if (server_or_authority_cert.scope() == scope &&
+        predicate.Run(server_or_authority_cert))
       certificates.push_back(server_or_authority_cert.certificate());
   }
   return certificates;
 }
 
+// Returns all extension IDs that were used in a Scope of a one of the
+// |server_or_authority_certificates|.
+std::set<std::string> CollectExtensionIds(
+    const std::vector<OncParsedCertificates::ServerOrAuthorityCertificate>&
+        server_or_authority_certificates) {
+  std::set<std::string> extension_ids;
+  for (const auto& cert : server_or_authority_certificates) {
+    if (cert.scope().is_extension_scoped())
+      extension_ids.insert(cert.scope().extension_id());
+  }
+  return extension_ids;
+}
+
 }  // namespace
 
 NetworkConfigurationUpdater::~NetworkConfigurationUpdater() {
@@ -72,21 +91,22 @@
 }
 
 net::CertificateList
-NetworkConfigurationUpdater::GetAllServerAndAuthorityCertificates() const {
+NetworkConfigurationUpdater::GetAllServerAndAuthorityCertificates(
+    const CertificateScope& scope) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return GetFilteredCertificateListFromOnc(
-      certs_->server_or_authority_certificates(),
+      certs_->server_or_authority_certificates(), scope,
       base::BindRepeating(
           [](const OncParsedCertificates::ServerOrAuthorityCertificate& cert) {
             return true;
           }));
 }
 
-net::CertificateList NetworkConfigurationUpdater::GetAllAuthorityCertificates()
-    const {
+net::CertificateList NetworkConfigurationUpdater::GetAllAuthorityCertificates(
+    const CertificateScope& scope) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return GetFilteredCertificateListFromOnc(
-      certs_->server_or_authority_certificates(),
+      certs_->server_or_authority_certificates(), scope,
       base::BindRepeating(
           [](const OncParsedCertificates::ServerOrAuthorityCertificate& cert) {
             return cert.type() ==
@@ -95,11 +115,11 @@
           }));
 }
 
-net::CertificateList NetworkConfigurationUpdater::GetWebTrustedCertificates()
-    const {
+net::CertificateList NetworkConfigurationUpdater::GetWebTrustedCertificates(
+    const CertificateScope& scope) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return GetFilteredCertificateListFromOnc(
-      certs_->server_or_authority_certificates(),
+      certs_->server_or_authority_certificates(), scope,
       base::BindRepeating(
           [](const OncParsedCertificates::ServerOrAuthorityCertificate& cert) {
             return cert.web_trust_requested();
@@ -107,16 +127,22 @@
 }
 
 net::CertificateList
-NetworkConfigurationUpdater::GetCertificatesWithoutWebTrust() const {
+NetworkConfigurationUpdater::GetCertificatesWithoutWebTrust(
+    const CertificateScope& scope) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return GetFilteredCertificateListFromOnc(
-      certs_->server_or_authority_certificates(),
+      certs_->server_or_authority_certificates(), scope,
       base::BindRepeating(
           [](const OncParsedCertificates::ServerOrAuthorityCertificate& cert) {
             return !cert.web_trust_requested();
           }));
 }
 
+const std::set<std::string>&
+NetworkConfigurationUpdater::GetExtensionIdsWithPolicyCertificates() const {
+  return extension_ids_with_policy_certificates_;
+}
+
 NetworkConfigurationUpdater::NetworkConfigurationUpdater(
     onc::ONCSource onc_source,
     std::string policy_key,
@@ -288,6 +314,8 @@
     return;
 
   certs_ = std::move(incoming_certs);
+  extension_ids_with_policy_certificates_ =
+      CollectExtensionIds(certs_->server_or_authority_certificates());
 
   if (client_certs_changed)
     ImportClientCertificates();
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater.h b/chrome/browser/chromeos/policy/network_configuration_updater.h
index 2b5b1cb..27b25ac 100644
--- a/chrome/browser/chromeos/policy/network_configuration_updater.h
+++ b/chrome/browser/chromeos/policy/network_configuration_updater.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_CHROMEOS_POLICY_NETWORK_CONFIGURATION_UPDATER_H_
 
 #include <memory>
+#include <set>
 #include <string>
 #include <vector>
 
@@ -13,6 +14,7 @@
 #include "base/macros.h"
 #include "base/observer_list.h"
 #include "base/sequence_checker.h"
+#include "chromeos/network/onc/certificate_scope.h"
 #include "chromeos/network/onc/onc_parsed_certificates.h"
 #include "chromeos/network/policy_certificate_provider.h"
 #include "components/onc/onc_constants.h"
@@ -54,10 +56,17 @@
       chromeos::PolicyCertificateProvider::Observer* observer) override;
   void RemovePolicyProvidedCertsObserver(
       chromeos::PolicyCertificateProvider::Observer* observer) override;
-  net::CertificateList GetAllServerAndAuthorityCertificates() const override;
-  net::CertificateList GetAllAuthorityCertificates() const override;
-  net::CertificateList GetWebTrustedCertificates() const override;
-  net::CertificateList GetCertificatesWithoutWebTrust() const override;
+  net::CertificateList GetAllServerAndAuthorityCertificates(
+      const chromeos::onc::CertificateScope& scope) const override;
+  net::CertificateList GetAllAuthorityCertificates(
+      const chromeos::onc::CertificateScope& scope) const override;
+  net::CertificateList GetWebTrustedCertificates(
+      const chromeos::onc::CertificateScope& scope) const override;
+  net::CertificateList GetCertificatesWithoutWebTrust(
+      const chromeos::onc::CertificateScope& scope) const override;
+
+  const std::set<std::string>& GetExtensionIdsWithPolicyCertificates()
+      const override;
 
  protected:
   NetworkConfigurationUpdater(
@@ -149,6 +158,7 @@
 
   // Holds certificates from the last parsed ONC policy.
   std::unique_ptr<chromeos::onc::OncParsedCertificates> certs_;
+  std::set<std::string> extension_ids_with_policy_certificates_;
 
   // Observer list for notifying about ONC-provided server and CA certificate
   // changes.
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc b/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc
index efa54d9..a189f68d 100644
--- a/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc
+++ b/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc
@@ -23,6 +23,7 @@
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/network/fake_network_device_handler.h"
 #include "chromeos/network/mock_managed_network_configuration_handler.h"
+#include "chromeos/network/onc/certificate_scope.h"
 #include "chromeos/network/onc/onc_certificate_importer.h"
 #include "chromeos/network/onc/onc_parsed_certificates.h"
 #include "chromeos/network/onc/onc_test_utils.h"
@@ -249,6 +250,41 @@
       "Type": "UnencryptedConfiguration"
     })";
 
+const char kFakeONCWithExtensionScopedCert[] = R"(
+    { "Certificates": [
+        { "GUID": "{extension-scoped-certificate}",
+          "TrustBits": [
+             "Web"
+          ],
+          "Scope": {
+            "Type": "Extension",
+            "Id": "ngjobkbdodapjbbncmagbccommkggmnj"
+          },
+          "Type": "Authority",
+          "X509": "-----BEGIN CERTIFICATE-----\n
+    MIIC8zCCAdugAwIBAgIJALF9qhLor0+aMA0GCSqGSIb3DQEBBQUAMBcxFTATBgNV\n
+    BAMMDFRlc3QgUm9vdCBDQTAeFw0xNDA4MTQwMzA1MjlaFw0yNDA4MTEwMzA1Mjla\n
+    MBcxFTATBgNVBAMMDFRlc3QgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP\n
+    ADCCAQoCggEBALZJQeNCAVGofzx6cdP7zZE1F4QajvY2x9FwHfqG8267dm/oMi43\n
+    /TiSPWjkin1CMxRGG9wE9pFuVEDECgn97C1i4l7huiycwbFgTNrH+CJcgiBlQh5W\n
+    d3VP65AsSupXDiKNbJWsEerM1+72cA0J3aY1YV3Jdm2w8h6/MIbYd1I2lZcO0UbF\n
+    7YE9G7DyYZU8wUA4719dumGf7yucn4WJdHBj1XboNX7OAeHzERGQHA31/Y3OEGyt\n
+    fFUaIW/XLfR4FeovOL2RnjwdB0b1Q8GCi68SU2UZimlpZgay2gv6KgChKhWESfEB\n
+    v5swBtAVoB+dUZFH4VNf717swmF5whSfxOMCAwEAAaNCMEAwDwYDVR0TAQH/BAUw\n
+    AwEB/zAdBgNVHQ4EFgQUvPcw0TzA8nn675/JbFyT84poq4MwDgYDVR0PAQH/BAQD\n
+    AgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBXByn7f+j/sObYWGrDkKE4HLTzaLHs6Ikj\n
+    JNeo8iHDYOSkSVwAv9/HgniAKxj3rd3QYl6nsMzwqrTOcBJZZWd2BQAYmv/EKhfj\n
+    8VXYvlxe68rLU4cQ1QkyNqdeQfRT2n5WYNJ+TpqlCF9ddennMMsi6e8ZSYOlI6H4\n
+    YEzlNtU5eBjxXr/OqgtTgSx4qQpr2xMQIRR/G3A9iRpAigYsXVAZYvnHRYnyPWYF\n
+    PX11W1UegEJyoZp8bQp09u6mIWw6mPt3gl/ya1bm3ZuOUPDGrv3qpgUHqSYGVrOy\n
+    2bI3oCE+eQYfuVG+9LFJTZC1M+UOx15bQMVqBNFDepRqpE9h/ILg\n
+    -----END CERTIFICATE-----" },
+      ],
+      "Type": "UnencryptedConfiguration"
+    })";
+
+const char kExtensionIdWithScopedCert[] = "ngjobkbdodapjbbncmagbccommkggmnj";
+
 std::string ValueToString(const base::Value& value) {
   std::stringstream str;
   str << value;
@@ -391,7 +427,8 @@
     return updater;
   }
 
-  void CreateNetworkConfigurationUpdaterForDevicePolicy() {
+  NetworkConfigurationUpdater*
+  CreateNetworkConfigurationUpdaterForDevicePolicy() {
     auto testing_device_asset_id_getter =
         base::BindRepeating([] { return std::string(kFakeAssetId); });
     network_configuration_updater_ =
@@ -399,6 +436,7 @@
             policy_service_.get(), &network_config_handler_,
             &network_device_handler_, chromeos::CrosSettings::Get(),
             testing_device_asset_id_getter);
+    return network_configuration_updater_.get();
   }
 
   content::TestBrowserThreadBundle thread_bundle_;
@@ -534,9 +572,16 @@
   base::RunLoop().RunUntilIdle();
 
   // Certificates with the "Web" trust flag set will be returned.
-  EXPECT_EQ(1u, updater->GetWebTrustedCertificates().size());
-  EXPECT_EQ(1u, updater->GetCertificatesWithoutWebTrust().size());
-  EXPECT_EQ(2u, updater->GetAllServerAndAuthorityCertificates().size());
+  const auto kDefaultScope = chromeos::onc::CertificateScope::Default();
+  EXPECT_EQ(1u, updater->GetWebTrustedCertificates(kDefaultScope).size());
+  EXPECT_EQ(1u, updater->GetCertificatesWithoutWebTrust(kDefaultScope).size());
+  EXPECT_EQ(
+      2u, updater->GetAllServerAndAuthorityCertificates(kDefaultScope).size());
+  EXPECT_EQ(0u, updater
+                    ->GetAllServerAndAuthorityCertificates(
+                        chromeos::onc::CertificateScope::ForExtension(
+                            kExtensionIdWithScopedCert))
+                    .size());
 
   updater->RemovePolicyProvidedCertsObserver(&observer);
 }
@@ -559,9 +604,11 @@
   base::RunLoop().RunUntilIdle();
 
   // Verify that the returned certificate list is empty.
-  EXPECT_TRUE(updater->GetWebTrustedCertificates().empty());
-  EXPECT_TRUE(updater->GetCertificatesWithoutWebTrust().empty());
-  EXPECT_TRUE(updater->GetAllServerAndAuthorityCertificates().empty());
+  const auto kDefaultScope = chromeos::onc::CertificateScope::Default();
+  EXPECT_TRUE(updater->GetWebTrustedCertificates(kDefaultScope).empty());
+  EXPECT_TRUE(updater->GetCertificatesWithoutWebTrust(kDefaultScope).empty());
+  EXPECT_TRUE(
+      updater->GetAllServerAndAuthorityCertificates(kDefaultScope).empty());
 
   // No call has been made to the policy-provided certificates observer.
   Mock::VerifyAndClearExpectations(&observer);
@@ -575,9 +622,58 @@
   UpdateProviderPolicy(policy);
   base::RunLoop().RunUntilIdle();
 
-  EXPECT_EQ(1u, updater->GetWebTrustedCertificates().size());
-  EXPECT_EQ(1u, updater->GetCertificatesWithoutWebTrust().size());
-  EXPECT_EQ(2u, updater->GetAllServerAndAuthorityCertificates().size());
+  // Certificates with the "Web" trust flag set will be returned and forwarded
+  // to observers.
+  EXPECT_EQ(1u, updater->GetWebTrustedCertificates(kDefaultScope).size());
+  EXPECT_EQ(1u, updater->GetCertificatesWithoutWebTrust(kDefaultScope).size());
+  EXPECT_EQ(
+      2u, updater->GetAllServerAndAuthorityCertificates(kDefaultScope).size());
+  EXPECT_EQ(0u, updater
+                    ->GetAllServerAndAuthorityCertificates(
+                        chromeos::onc::CertificateScope::ForExtension(
+                            kExtensionIdWithScopedCert))
+                    .size());
+
+  updater->RemovePolicyProvidedCertsObserver(&observer);
+}
+
+TEST_F(NetworkConfigurationUpdaterTest, ExtensionScopedWebTrustedCertificate) {
+  // Ignore network configuration changes.
+  EXPECT_CALL(network_config_handler_, SetPolicy(_, _, _, _))
+      .Times(AnyNumber());
+
+  NetworkConfigurationUpdater* updater =
+      CreateNetworkConfigurationUpdaterForDevicePolicy();
+
+  MockPolicyProvidedCertsObserver observer;
+  EXPECT_CALL(observer, OnPolicyProvidedCertsChanged());
+  updater->AddPolicyProvidedCertsObserver(&observer);
+
+  PolicyMap policy;
+  policy.Set(key::kDeviceOpenNetworkConfiguration, POLICY_LEVEL_MANDATORY,
+             POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
+             std::make_unique<base::Value>(kFakeONCWithExtensionScopedCert),
+             nullptr);
+  UpdateProviderPolicy(policy);
+  MarkPolicyProviderInitialized();
+  base::RunLoop().RunUntilIdle();
+
+  // Certificates with the "Web" trust flag set will be returned.
+  const auto kDefaultScope = chromeos::onc::CertificateScope::Default();
+  EXPECT_EQ(0u, updater->GetWebTrustedCertificates(kDefaultScope).size());
+  EXPECT_EQ(0u, updater->GetCertificatesWithoutWebTrust(kDefaultScope).size());
+  EXPECT_EQ(
+      0u, updater->GetAllServerAndAuthorityCertificates(kDefaultScope).size());
+  EXPECT_EQ(1u, updater
+                    ->GetAllServerAndAuthorityCertificates(
+                        chromeos::onc::CertificateScope::ForExtension(
+                            kExtensionIdWithScopedCert))
+                    .size());
+  EXPECT_EQ(1u, updater
+                    ->GetWebTrustedCertificates(
+                        chromeos::onc::CertificateScope::ForExtension(
+                            kExtensionIdWithScopedCert))
+                    .size());
 
   updater->RemovePolicyProvidedCertsObserver(&observer);
 }
diff --git a/chrome/browser/chromeos/policy/policy_cert_service.cc b/chrome/browser/chromeos/policy/policy_cert_service.cc
index e59df62..50fe87f 100644
--- a/chrome/browser/chromeos/policy/policy_cert_service.cc
+++ b/chrome/browser/chromeos/policy/policy_cert_service.cc
@@ -17,6 +17,8 @@
 #include "chrome/browser/net/profile_network_context_service.h"
 #include "chrome/browser/net/profile_network_context_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chromeos/network/onc/certificate_scope.h"
+#include "chromeos/network/policy_certificate_provider.h"
 #include "components/user_manager/user_manager.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
@@ -51,7 +53,8 @@
 
   policy_certificate_provider_->AddPolicyProvidedCertsObserver(this);
   profile_wide_all_server_and_authority_certs_ =
-      policy_certificate_provider_->GetAllServerAndAuthorityCertificates();
+      policy_certificate_provider_->GetAllServerAndAuthorityCertificates(
+          chromeos::onc::CertificateScope::Default());
   profile_wide_trust_anchors_ = GetAllowedProfileWideTrustAnchors();
 }
 
@@ -65,7 +68,8 @@
 
 void PolicyCertService::OnPolicyProvidedCertsChanged() {
   profile_wide_all_server_and_authority_certs_ =
-      policy_certificate_provider_->GetAllServerAndAuthorityCertificates();
+      policy_certificate_provider_->GetAllServerAndAuthorityCertificates(
+          chromeos::onc::CertificateScope::Default());
   profile_wide_trust_anchors_ = GetAllowedProfileWideTrustAnchors();
 
   // Make all policy-provided server and authority certificates available to NSS
@@ -109,7 +113,8 @@
     return {};
 
   net::CertificateList trust_anchors =
-      policy_certificate_provider_->GetWebTrustedCertificates();
+      policy_certificate_provider_->GetWebTrustedCertificates(
+          chromeos::onc::CertificateScope::Default());
 
   // Do not use certificates installed via ONC policy if the current session has
   // multiple profiles. This is important to make sure that any possibly tainted
diff --git a/chrome/browser/download/download_target_determiner.cc b/chrome/browser/download/download_target_determiner.cc
index 717be62..1ebb1303 100644
--- a/chrome/browser/download/download_target_determiner.cc
+++ b/chrome/browser/download/download_target_determiner.cc
@@ -373,10 +373,14 @@
     // Downloads/music/music/music/bar.mp3.
     base::FilePath new_path(download_prefs_->DownloadPath().Append(
         suggested_path).NormalizePathSeparators());
-    // Do not pass a mime type to GenerateSafeFileName so that it does not force
-    // the filename to have an extension if the (Chrome) extension does not
-    // suggest it.
-    net::GenerateSafeFileName(std::string(), false, &new_path);
+    // If the (Chrome) extension does not suggest an file extension, do not pass
+    // a mime type to GenerateSafeFileName so that it does not force the
+    // filename to have an extension. Otherwise, correct the file extension in
+    // case it is wrongly given.
+    if (new_path.Extension().empty())
+      net::GenerateSafeFileName(std::string(), false, &new_path);
+    else
+      net::GenerateSafeFileName(download_->GetMimeType(), true, &new_path);
     virtual_path_ = new_path;
     create_target_directory_ = true;
   }
diff --git a/chrome/browser/extensions/api/chrome_extensions_api_client.cc b/chrome/browser/extensions/api/chrome_extensions_api_client.cc
index 9a0afb65f..82adf99 100644
--- a/chrome/browser/extensions/api/chrome_extensions_api_client.cc
+++ b/chrome/browser/extensions/api/chrome_extensions_api_client.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/extensions/api/chrome_device_permissions_prompt.h"
 #include "chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry.h"
 #include "chrome/browser/extensions/api/declarative_content/default_content_predicate_evaluators.h"
+#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
 #include "chrome/browser/extensions/api/feedback_private/chrome_feedback_private_delegate.h"
 #include "chrome/browser/extensions/api/file_system/chrome_file_system_delegate.h"
 #include "chrome/browser/extensions/api/management/chrome_management_api_delegate.h"
@@ -25,7 +26,10 @@
 #include "chrome/browser/extensions/api/storage/managed_value_store_cache.h"
 #include "chrome/browser/extensions/api/storage/sync_value_store_cache.h"
 #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
+#include "chrome/browser/extensions/extension_action.h"
+#include "chrome/browser/extensions/extension_action_manager.h"
 #include "chrome/browser/extensions/extension_action_runner.h"
+#include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/extensions/system_display/display_info_provider.h"
 #include "chrome/browser/favicon/favicon_utils.h"
 #include "chrome/browser/guest_view/app_view/chrome_app_view_guest_delegate.h"
@@ -213,6 +217,30 @@
   runner->OnWebRequestBlocked(extension);
 }
 
+void ChromeExtensionsAPIClient::UpdateActionCount(
+    content::BrowserContext* context,
+    const ExtensionId& extension_id,
+    int tab_id,
+    int action_count) {
+  const Extension* extension =
+      ExtensionRegistry::Get(context)->enabled_extensions().GetByID(
+          extension_id);
+  DCHECK(extension);
+
+  ExtensionAction* action =
+      ExtensionActionManager::Get(context)->GetExtensionAction(*extension);
+  DCHECK(action);
+
+  action->SetDNRActionCount(tab_id, action_count);
+  content::WebContents* tab_contents = nullptr;
+  if (ExtensionTabUtil::GetTabById(
+          tab_id, context, true /* include_incognito */, &tab_contents) &&
+      tab_contents) {
+    ExtensionActionAPI::Get(context)->NotifyChange(action, tab_contents,
+                                                   context);
+  }
+}
+
 AppViewGuestDelegate* ChromeExtensionsAPIClient::CreateAppViewGuestDelegate()
     const {
   return new ChromeAppViewGuestDelegate();
@@ -241,9 +269,9 @@
   return new ChromeWebViewGuestDelegate(web_view_guest);
 }
 
-WebViewPermissionHelperDelegate* ChromeExtensionsAPIClient::
-    CreateWebViewPermissionHelperDelegate(
-        WebViewPermissionHelper* web_view_permission_helper) const {
+WebViewPermissionHelperDelegate*
+ChromeExtensionsAPIClient::CreateWebViewPermissionHelperDelegate(
+    WebViewPermissionHelper* web_view_permission_helper) const {
   return new ChromeWebViewPermissionHelperDelegate(web_view_permission_helper);
 }
 
@@ -251,12 +279,10 @@
 ChromeExtensionsAPIClient::CreateContentRulesRegistry(
     content::BrowserContext* browser_context,
     RulesCacheDelegate* cache_delegate) const {
-  return scoped_refptr<ContentRulesRegistry>(
-      new ChromeContentRulesRegistry(
-          browser_context,
-          cache_delegate,
-          base::Bind(&CreateDefaultContentPredicateEvaluators,
-                     base::Unretained(browser_context))));
+  return scoped_refptr<ContentRulesRegistry>(new ChromeContentRulesRegistry(
+      browser_context, cache_delegate,
+      base::Bind(&CreateDefaultContentPredicateEvaluators,
+                 base::Unretained(browser_context))));
 }
 
 std::unique_ptr<DevicePermissionsPrompt>
diff --git a/chrome/browser/extensions/api/chrome_extensions_api_client.h b/chrome/browser/extensions/api/chrome_extensions_api_client.h
index a4837bf2..f1b8197f 100644
--- a/chrome/browser/extensions/api/chrome_extensions_api_client.h
+++ b/chrome/browser/extensions/api/chrome_extensions_api_client.h
@@ -39,6 +39,10 @@
   void NotifyWebRequestWithheld(int render_process_id,
                                 int render_frame_id,
                                 const ExtensionId& extension_id) override;
+  void UpdateActionCount(content::BrowserContext* context,
+                         const ExtensionId& extension_id,
+                         int tab_id,
+                         int action_count) override;
   AppViewGuestDelegate* CreateAppViewGuestDelegate() const override;
   ExtensionOptionsGuestDelegate* CreateExtensionOptionsGuestDelegate(
       ExtensionOptionsGuest* guest) const override;
diff --git a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
index 2c6777cd..bddbf354d 100644
--- a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
+++ b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
@@ -29,16 +29,21 @@
 #include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "chrome/browser/extensions/extension_action.h"
+#include "chrome/browser/extensions/extension_action_manager.h"
 #include "chrome/browser/extensions/extension_action_runner.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
+#include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/extensions/load_error_reporter.h"
 #include "chrome/browser/extensions/scripting_permissions_modifier.h"
 #include "chrome/browser/net/profile_network_context_service.h"
 #include "chrome/browser/net/profile_network_context_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_paths.h"
+#include "chrome/common/extensions/api/extension_action/action_info.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/prefs/pref_service.h"
@@ -2636,6 +2641,263 @@
   }
 }
 
+// Test that the badge text for an extension will update to reflect the number
+// of actions taken on requests matching the extension's ruleset.
+IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBrowserTest,
+                       ActionsMatchedCountAsBadgeText) {
+  auto get_url_for_host = [this](std::string hostname) {
+    return embedded_test_server()->GetURL(hostname,
+                                          "/pages_with_script/index.html");
+  };
+
+  // This page simulates a user clicking on a link, so that the next page it
+  // navigates to has a Referrer header.
+  auto get_url_with_referrer = [this](std::string hostname) {
+    return embedded_test_server()->GetURL(hostname, "/simulate_click.html");
+  };
+
+  // Navigates frame with name |frame_name| to |url|.
+  auto navigate_frame = [this](const std::string& frame_name, const GURL& url) {
+    content::TestNavigationObserver navigation_observer(
+        web_contents(), 1 /*number_of_navigations*/);
+
+    // Before navigation, We set the referrer policy of the iframe to
+    // 'no-referrer' to prevent a referer header from being added for the iframe
+    // navigation.
+    ASSERT_TRUE(content::ExecuteScript(
+        GetMainFrame(),
+        base::StringPrintf(R"(
+          document.getElementsByName('%s')[0].referrerPolicy = 'no-referrer';
+          document.getElementsByName('%s')[0].src = '%s';)",
+                           frame_name.c_str(), frame_name.c_str(),
+                           url.spec().c_str())));
+    navigation_observer.Wait();
+  };
+
+  const std::string kFrameName1 = "frame1";
+  const GURL page_url = embedded_test_server()->GetURL(
+      "norulesmatched.com", "/page_with_two_frames.html");
+
+  struct {
+    std::string url_filter;
+    int id;
+    int priority;
+    std::string action_type;
+    base::Optional<std::string> redirect_url;
+    base::Optional<std::vector<std::string>> remove_headers_list;
+  } rules_data[] = {
+      {"abc.com", 1, 1, "block", base::nullopt, base::nullopt},
+      {"def.com", 2, 1, "redirect", "http://zzz.com", base::nullopt},
+      {"jkl.com", 3, 1, "removeHeaders", base::nullopt,
+       std::vector<std::string>({"referer"})},
+      {"abcd.com", 4, 1, "block", base::nullopt, base::nullopt},
+      {"abcd", 5, 1, "allow", base::nullopt, base::nullopt},
+  };
+
+  // Load the extension.
+  std::vector<TestRule> rules;
+  for (const auto& rule_data : rules_data) {
+    TestRule rule = CreateGenericRule();
+    rule.condition->url_filter = rule_data.url_filter;
+    rule.id = rule_data.id;
+    rule.priority = rule_data.priority;
+    rule.condition->resource_types =
+        std::vector<std::string>({"main_frame", "sub_frame"});
+    rule.action->type = rule_data.action_type;
+    rule.action->redirect.emplace();
+    rule.action->redirect->url = rule_data.redirect_url;
+    rule.action->remove_headers_list = rule_data.remove_headers_list;
+    rules.push_back(rule);
+  }
+
+  ASSERT_NO_FATAL_FAILURE(LoadExtensionWithRules(
+      rules, "test_extension", {URLPattern::kAllUrlsPattern}));
+
+  const Extension* dnr_extension = extension_registry()->GetExtensionById(
+      last_loaded_extension_id(), extensions::ExtensionRegistry::ENABLED);
+
+  ExtensionPrefs::Get(profile())->SetDNRUseActionCountAsBadgeText(
+      last_loaded_extension_id(), true);
+
+  ExtensionAction* action =
+      ExtensionActionManager::Get(web_contents()->GetBrowserContext())
+          ->GetExtensionAction(*dnr_extension);
+
+  struct {
+    std::string frame_hostname;
+    std::string expected_badge_text;
+    bool has_referrer_header;
+  } test_cases[] = {
+      // zzz.com does not match any rules, but we should still display 0 as the
+      // badge text as the preference is on.
+      {"zzz.com", "0", false},
+      // abc.com is blocked by a matching rule and should increment the badge
+      // text.
+      {"abc.com", "1", false},
+      // def.com is redirected by a matching rule and should increment the badge
+      // text.
+      {"def.com", "2", false},
+      // jkl.com matches with a removeHeaders rule, but has no headers.
+      // Therefore no action is taken and the badge text stays the same.
+      {"jkl.com", "2", false},
+      // jkl.com matches with a removeHeaders rule and has a referrer header.
+      // Therefore the badge text should be incremented.
+      {"jkl.com", "3", true},
+      // abcd.com matches both a block rule and an allow rule. Since the allow
+      // rule overrides the block rule, no action is taken and the badge text
+      // stays the same,
+      {"abcd.com", "3", false},
+  };
+
+  ui_test_utils::NavigateToURL(browser(), page_url);
+  ASSERT_TRUE(WasFrameWithScriptLoaded(GetMainFrame()));
+
+  // Verify that the badge text is 0 when navigation finishes.
+  int first_tab_id = ExtensionTabUtil::GetTabId(web_contents());
+  EXPECT_EQ("0", action->GetDisplayBadgeText(first_tab_id));
+
+  for (const auto& test_case : test_cases) {
+    GURL url = test_case.has_referrer_header
+                   ? get_url_with_referrer(test_case.frame_hostname)
+                   : get_url_for_host(test_case.frame_hostname);
+    SCOPED_TRACE(base::StringPrintf("Testing %s", url.spec().c_str()));
+
+    navigate_frame(kFrameName1, url);
+    EXPECT_EQ(test_case.expected_badge_text,
+              action->GetDisplayBadgeText(first_tab_id));
+  }
+
+  std::string first_tab_badge_text = action->GetDisplayBadgeText(first_tab_id);
+
+  const GURL second_tab_url = get_url_for_host("nomatch.com");
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(), second_tab_url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
+
+  ASSERT_EQ(2, browser()->tab_strip_model()->count());
+  ASSERT_TRUE(browser()->tab_strip_model()->IsTabSelected(1));
+
+  int second_tab_id = ExtensionTabUtil::GetTabId(web_contents());
+  EXPECT_EQ("0", action->GetDisplayBadgeText(second_tab_id));
+
+  // Verify that the badge text for the first tab is unaffected.
+  EXPECT_EQ(first_tab_badge_text, action->GetDisplayBadgeText(first_tab_id));
+}
+
+// Test that the action matched badge text for an extension is visible in an
+// incognito context if the extension is incognito enabled.
+IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBrowserTest,
+                       ActionsMatchedCountAsBadgeTextIncognito) {
+  TestRule rule = CreateGenericRule();
+  rule.condition->url_filter = "abc.com";
+  rule.id = kMinValidID;
+  rule.condition->resource_types = std::vector<std::string>({"main_frame"});
+  rule.action->type = "block";
+
+  std::vector<TestRule> rules({rule});
+  ASSERT_NO_FATAL_FAILURE(LoadExtensionWithRules(
+      {rules}, "test_extension", {URLPattern::kAllUrlsPattern}));
+
+  const ExtensionId extension_id = last_loaded_extension_id();
+  util::SetIsIncognitoEnabled(extension_id, profile(), true /*enabled*/);
+
+  ExtensionPrefs::Get(profile())->SetDNRUseActionCountAsBadgeText(extension_id,
+                                                                  true);
+
+  Browser* incognito_browser = CreateIncognitoBrowser();
+  ui_test_utils::NavigateToURL(incognito_browser, GURL("http://abc.com"));
+
+  content::WebContents* incognito_contents =
+      incognito_browser->tab_strip_model()->GetActiveWebContents();
+
+  const Extension* dnr_extension = extension_registry()->GetExtensionById(
+      extension_id, extensions::ExtensionRegistry::ENABLED);
+  ExtensionAction* incognito_action =
+      ExtensionActionManager::Get(incognito_contents->GetBrowserContext())
+          ->GetExtensionAction(*dnr_extension);
+
+  // TODO(crbug.com/992251): This should be a "1" after the main-frame
+  // navigation case is fixed.
+  EXPECT_EQ("0", incognito_action->GetDisplayBadgeText(
+                     ExtensionTabUtil::GetTabId(incognito_contents)));
+}
+
+// Test that the actions matched badge text for an extension will be reset
+// when a main-frame navigation finishes.
+// TODO(crbug.com/992251): Edit this test to add more main-frame cases.
+IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBrowserTest,
+                       ActionsMatchedCountAsBadgeTextMainFrame) {
+  auto get_url_for_host = [this](std::string hostname) {
+    return embedded_test_server()->GetURL(hostname,
+                                          "/pages_with_script/index.html");
+  };
+
+  struct {
+    std::string url_filter;
+    int id;
+    int priority;
+    std::string action_type;
+    std::vector<std::string> resource_types;
+    base::Optional<std::string> redirect_url;
+  } rules_data[] = {
+      {"abc.com", 1, 1, "block", std::vector<std::string>({"script"}),
+       base::nullopt},
+      {"def.com", 2, 1, "redirect", std::vector<std::string>({"main_frame"}),
+       get_url_for_host("abc.com").spec()},
+  };
+
+  // Load the extension.
+  std::vector<TestRule> rules;
+  for (const auto& rule_data : rules_data) {
+    TestRule rule = CreateGenericRule();
+    rule.condition->url_filter = rule_data.url_filter;
+    rule.id = rule_data.id;
+    rule.priority = rule_data.priority;
+    rule.condition->resource_types = rule_data.resource_types;
+    rule.action->type = rule_data.action_type;
+    rule.action->redirect.emplace();
+    rule.action->redirect->url = rule_data.redirect_url;
+    rules.push_back(rule);
+  }
+
+  ASSERT_NO_FATAL_FAILURE(LoadExtensionWithRules(
+      rules, "test_extension", {URLPattern::kAllUrlsPattern}));
+
+  const Extension* dnr_extension = extension_registry()->GetExtensionById(
+      last_loaded_extension_id(), extensions::ExtensionRegistry::ENABLED);
+
+  ExtensionPrefs::Get(profile())->SetDNRUseActionCountAsBadgeText(
+      last_loaded_extension_id(), true);
+
+  ExtensionAction* action =
+      ExtensionActionManager::Get(web_contents()->GetBrowserContext())
+          ->GetExtensionAction(*dnr_extension);
+
+  struct {
+    std::string frame_hostname;
+    std::string expected_badge_text;
+  } test_cases[] = {
+      // The script on get_url_for_host("abc.com") matches with a rule and
+      // should increment the badge text.
+      {"abc.com", "1"},
+      // No rules match, so the badge text should be 0 once navigation finishes.
+      {"nomatch.com", "0"},
+      // The request to def.com will redirect to get_url_for_host("abc.com") and
+      // the script on abc.com should match with a rule.
+      {"def.com", "1"},
+  };
+
+  int first_tab_id = ExtensionTabUtil::GetTabId(web_contents());
+  for (const auto& test_case : test_cases) {
+    GURL url = get_url_for_host(test_case.frame_hostname);
+    SCOPED_TRACE(base::StringPrintf("Testing %s", url.spec().c_str()));
+
+    ui_test_utils::NavigateToURL(browser(), url);
+    EXPECT_EQ(test_case.expected_badge_text,
+              action->GetDisplayBadgeText(first_tab_id));
+  }
+}
+
 // Test fixture to verify that host permissions for the request url and the
 // request initiator are properly checked when redirecting requests. Loads an
 // example.com url with four sub-frames named frame_[1..4] from hosts
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.cc b/chrome/browser/extensions/api/downloads/downloads_api.cc
index 2d635a8..6899282 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api.cc
@@ -45,7 +45,6 @@
 #include "chrome/browser/download/download_query.h"
 #include "chrome/browser/download/download_shelf.h"
 #include "chrome/browser/download/download_stats.h"
-#include "chrome/browser/download/drag_download_item.h"
 #include "chrome/browser/extensions/chrome_extension_function_details.h"
 #include "chrome/browser/icon_loader.h"
 #include "chrome/browser/icon_manager.h"
@@ -1495,36 +1494,6 @@
   Respond(NoArguments());
 }
 
-DownloadsDragFunction::DownloadsDragFunction() {}
-
-DownloadsDragFunction::~DownloadsDragFunction() {}
-
-ExtensionFunction::ResponseAction DownloadsDragFunction::Run() {
-  std::unique_ptr<downloads::Drag::Params> params(
-      downloads::Drag::Params::Create(*args_));
-  EXTENSION_FUNCTION_VALIDATE(params.get());
-  DownloadItem* download_item = GetDownload(
-      browser_context(), include_incognito_information(), params->download_id);
-  content::WebContents* web_contents =
-      dispatcher()->GetVisibleWebContents();
-  std::string error;
-  if (InvalidId(download_item, &error) ||
-      Fault(!web_contents, download_extension_errors::kInvisibleContext,
-            &error)) {
-    return RespondNow(Error(error));
-  }
-  RecordApiFunctions(DOWNLOADS_FUNCTION_DRAG);
-  gfx::Image* icon = g_browser_process->icon_manager()->LookupIconFromFilepath(
-      download_item->GetTargetFilePath(), IconLoader::NORMAL);
-  gfx::NativeView view = web_contents->GetNativeView();
-  {
-    // Enable nested tasks during DnD, while |DragDownload()| blocks.
-    base::MessageLoopCurrent::ScopedNestableTaskAllower allow;
-    DragDownloadItem(download_item, icon, view);
-  }
-  return RespondNow(NoArguments());
-}
-
 DownloadsSetShelfEnabledFunction::DownloadsSetShelfEnabledFunction() {}
 
 DownloadsSetShelfEnabledFunction::~DownloadsSetShelfEnabledFunction() {}
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.h b/chrome/browser/extensions/api/downloads/downloads_api.h
index 81d3cc6..1f39ba0 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api.h
+++ b/chrome/browser/extensions/api/downloads/downloads_api.h
@@ -275,19 +275,6 @@
   DISALLOW_COPY_AND_ASSIGN(DownloadsSetShelfEnabledFunction);
 };
 
-class DownloadsDragFunction : public ExtensionFunction {
- public:
-  DECLARE_EXTENSION_FUNCTION("downloads.drag", DOWNLOADS_DRAG)
-  DownloadsDragFunction();
-  ResponseAction Run() override;
-
- protected:
-  ~DownloadsDragFunction() override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(DownloadsDragFunction);
-};
-
 class DownloadsGetFileIconFunction : public ChromeAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("downloads.getFileIcon", DOWNLOADS_GETFILEICON)
diff --git a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
index 3854457..0e2a4d3 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
@@ -1232,14 +1232,6 @@
   RunFunction(new DownloadsShowDefaultFolderFunction(),
               DownloadItemIdAsArgList(item.get()));
 }
-
-IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
-                       DownloadsDragFunction) {
-  ScopedCancellingItem item(CreateFirstSlowTestDownload());
-  ASSERT_TRUE(item.get());
-
-  RunFunction(new DownloadsDragFunction(), DownloadItemIdAsArgList(item.get()));
-}
 #endif
 
 
@@ -2329,14 +2321,14 @@
                           "  \"paused\": false,"
                           "  \"url\": \"%s\"}]",
                           download_url.c_str())));
-  ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
-                      base::StringPrintf(
-                          "[{\"id\": %d,"
-                          "  \"filename\": {"
-                          "    \"previous\": \"\","
-                          "    \"current\": \"%s\"}}]",
-                          result_id,
-                          GetFilename("file.txt").c_str())));
+  // File will be renamed to file.html due to its mime type.
+  ASSERT_TRUE(
+      WaitFor(downloads::OnChanged::kEventName,
+              base::StringPrintf("[{\"id\": %d,"
+                                 "  \"filename\": {"
+                                 "    \"previous\": \"\","
+                                 "    \"current\": \"%s\"}}]",
+                                 result_id, GetFilename("file.html").c_str())));
   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
                       base::StringPrintf(
                           "[{\"id\": %d,"
@@ -3008,6 +3000,8 @@
   EXPECT_FALSE(determine_result.get());  // No return value.
 }
 
+// Tests that overriding a safe file extension to a dangerous extension will not
+// trigger the dangerous prompt and will not change the extension.
 IN_PROC_BROWSER_TEST_F(
     DownloadExtensionTest,
     DownloadExtensionTest_OnDeterminingFilename_DangerousOverride) {
@@ -3047,7 +3041,7 @@
   ASSERT_TRUE(item->GetTargetFilePath().empty());
   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
 
-  // Respond to the onDeterminingFilename.
+  // Respond to the onDeterminingFilename with a dangerous extension.
   std::string error;
   ASSERT_TRUE(ExtensionDownloadsEventRouter::DetermineFilename(
       current_browser()->profile(), false, GetExtensionId(), result_id,
@@ -3056,12 +3050,68 @@
   EXPECT_EQ("", error);
 
   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
-                      base::StringPrintf(
-                          "[{\"id\": %d,"
-                          "  \"danger\": {"
-                          "    \"previous\":\"safe\","
-                          "    \"current\":\"file\"}}]",
-                          result_id)));
+                      base::StringPrintf("[{\"id\": %d,"
+                                         "  \"state\": {"
+                                         "    \"previous\": \"in_progress\","
+                                         "    \"current\": \"complete\"}}]",
+                                         result_id)));
+  EXPECT_EQ(downloads_directory().AppendASCII("overridden.txt"),
+            item->GetTargetFilePath());
+}
+
+// Tests that overriding a dangerous file extension to a safe extension will
+// trigger the dangerous prompt and will not change the extension.
+IN_PROC_BROWSER_TEST_F(
+    DownloadExtensionTest,
+    DownloadExtensionTest_OnDeterminingFilename_SafeOverride) {
+  GoOnTheRecord();
+  LoadExtension("downloads_split");
+  AddFilenameDeterminer();
+
+  std::string download_url = "data:application/x-shockwave-flash,";
+  // Start downloading a file.
+  std::unique_ptr<base::Value> result(RunFunctionAndReturnResult(
+      new DownloadsDownloadFunction(),
+      base::StringPrintf("[{\"url\": \"%s\"}]", download_url.c_str())));
+  ASSERT_TRUE(result.get());
+  int result_id = -1;
+  ASSERT_TRUE(result->GetAsInteger(&result_id));
+  DownloadItem* item = GetCurrentManager()->GetDownload(result_id);
+  ASSERT_TRUE(item);
+  ScopedCancellingItem canceller(item);
+  ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
+
+  ASSERT_TRUE(WaitFor(
+      downloads::OnCreated::kEventName,
+      base::StringPrintf("[{\"danger\": \"safe\","
+                         "  \"incognito\": false,"
+                         "  \"id\": %d,"
+                         "  \"mime\": \"application/x-shockwave-flash\","
+                         "  \"paused\": false,"
+                         "  \"url\": \"%s\"}]",
+                         result_id, download_url.c_str())));
+  ASSERT_TRUE(WaitFor(downloads::OnDeterminingFilename::kEventName,
+                      base::StringPrintf("[{\"id\": %d,"
+                                         "  \"filename\":\"download.swf\"}]",
+                                         result_id)));
+  ASSERT_TRUE(item->GetTargetFilePath().empty());
+  ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
+
+  // Respond to the onDeterminingFilename with a safe extension.
+  std::string error;
+  ASSERT_TRUE(ExtensionDownloadsEventRouter::DetermineFilename(
+      current_browser()->profile(), false, GetExtensionId(), result_id,
+      base::FilePath(FILE_PATH_LITERAL("overridden.txt")),
+      downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY, &error));
+  EXPECT_EQ("", error);
+
+  // Dangerous download prompt will be shown.
+  ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
+                      base::StringPrintf("[{\"id\": %d, "
+                                         "  \"danger\": {"
+                                         "    \"previous\": \"safe\","
+                                         "    \"current\": \"file\"}}]",
+                                         result_id)));
 
   item->ValidateDangerousDownload();
   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
@@ -3071,6 +3121,7 @@
                           "    \"previous\":\"file\","
                           "    \"current\":\"accepted\"}}]",
                           result_id)));
+
   ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName,
                       base::StringPrintf(
                           "[{\"id\": %d,"
@@ -4342,7 +4393,8 @@
   LoadExtension("downloads_split");
   std::unique_ptr<base::Value> result(RunFunctionAndReturnResult(
       new DownloadsDownloadFunction(),
-      "[{\"url\": \"data:,\", \"filename\": \"dangerous.swf\"}]"));
+      "[{\"url\": \"data:application/x-shockwave-flash,\", \"filename\": "
+      "\"dangerous.swf\"}]"));
   ASSERT_TRUE(result.get());
   int result_id = -1;
   ASSERT_TRUE(result->GetAsInteger(&result_id));
diff --git a/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc b/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
index 5af703b..9d60fa3d 100644
--- a/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
+++ b/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
@@ -209,7 +209,8 @@
   // Test that we received the changes.
   ExtensionAction* action = GetBrowserAction(*extension);
   ASSERT_EQ("Modified", action->GetTitle(ExtensionAction::kDefaultTabId));
-  ASSERT_EQ("badge", action->GetBadgeText(ExtensionAction::kDefaultTabId));
+  ASSERT_EQ("badge",
+            action->GetExplicitlySetBadgeText(ExtensionAction::kDefaultTabId));
   ASSERT_EQ(SkColorSetARGB(255, 255, 255, 255),
             action->GetBadgeBackgroundColor(ExtensionAction::kDefaultTabId));
 
@@ -701,7 +702,8 @@
       extensions::ProcessManager::Get(browser()->profile());
   ASSERT_TRUE(manager->GetBackgroundHostForExtension(extension->id()));
   ExtensionAction* action = GetBrowserAction(*extension);
-  ASSERT_EQ("", action->GetBadgeText(ExtensionAction::kDefaultTabId));
+  ASSERT_EQ("",
+            action->GetExplicitlySetBadgeText(ExtensionAction::kDefaultTabId));
 
   content::WindowedNotificationObserver host_destroyed_observer(
       extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED,
@@ -715,7 +717,8 @@
   // and the badge text has been set.
   host_destroyed_observer.Wait();
   ASSERT_FALSE(manager->GetBackgroundHostForExtension(extension->id()));
-  ASSERT_EQ("X", action->GetBadgeText(ExtensionAction::kDefaultTabId));
+  ASSERT_EQ("X",
+            action->GetExplicitlySetBadgeText(ExtensionAction::kDefaultTabId));
 }
 
 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, BadgeBackgroundColor) {
diff --git a/chrome/browser/extensions/api/extension_action/browser_action_browsertest.cc b/chrome/browser/extensions/api/extension_action/browser_action_browsertest.cc
index 2c4893d0..5027f9a 100644
--- a/chrome/browser/extensions/api/extension_action/browser_action_browsertest.cc
+++ b/chrome/browser/extensions/api/extension_action/browser_action_browsertest.cc
@@ -94,7 +94,7 @@
 
   // If the extension hasn't already set the badge text, then we should wait for
   // it to do so.
-  if (extension_action->GetBadgeText(0) != "Hello") {
+  if (extension_action->GetExplicitlySetBadgeText(0) != "Hello") {
     ExtensionTestMessageListener listener("Badge Text Set",
                                           false /* won't send custom reply */);
     ASSERT_TRUE(listener.WaitUntilSatisfied());
diff --git a/chrome/browser/extensions/api/extension_action/extension_action_api.cc b/chrome/browser/extensions/api/extension_action/extension_action_api.cc
index 74a6724..c553738 100644
--- a/chrome/browser/extensions/api/extension_action/extension_action_api.cc
+++ b/chrome/browser/extensions/api/extension_action/extension_action_api.cc
@@ -467,8 +467,10 @@
 
 ExtensionFunction::ResponseAction
 ExtensionActionGetBadgeTextFunction::RunExtensionAction() {
-  return RespondNow(OneArgument(
-      std::make_unique<base::Value>(extension_action_->GetBadgeText(tab_id_))));
+  // TODO(crbug.com/990224): Return a placeholder value if the extension has
+  // called setActionCountAsBadgeText(true).
+  return RespondNow(OneArgument(std::make_unique<base::Value>(
+      extension_action_->GetExplicitlySetBadgeText(tab_id_))));
 }
 
 ExtensionFunction::ResponseAction
diff --git a/chrome/browser/extensions/api/extension_action/extension_action_apitest.cc b/chrome/browser/extensions/api/extension_action/extension_action_apitest.cc
index c90241d..495096e 100644
--- a/chrome/browser/extensions/api/extension_action/extension_action_apitest.cc
+++ b/chrome/browser/extensions/api/extension_action/extension_action_apitest.cc
@@ -889,7 +889,7 @@
     ValuePair custom_badge_text2{"custom badge2", "'custom badge2'"};
 
     auto get_badge_text = [](ExtensionAction* action, int tab_id) {
-      return action->GetBadgeText(tab_id);
+      return action->GetExplicitlySetBadgeText(tab_id);
     };
 
     ActionTestHelper badge_text_helper(kApiName, "setBadgeText", "getBadgeText",
diff --git a/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc b/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc
index 125a777..97da57de 100644
--- a/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc
+++ b/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc
@@ -35,7 +35,9 @@
 #include "components/language/core/browser/pref_names.h"
 #include "components/language/core/common/language_util.h"
 #include "components/language/core/common/locale_util.h"
+#include "components/spellcheck/browser/spellcheck_platform.h"
 #include "components/spellcheck/common/spellcheck_common.h"
+#include "components/spellcheck/common/spellcheck_features.h"
 #include "components/translate/core/browser/translate_download_manager.h"
 #include "components/translate/core/browser/translate_prefs.h"
 #include "third_party/icu/source/i18n/unicode/coll.h"
@@ -495,6 +497,12 @@
       SpellcheckServiceFactory::GetForContext(browser_context());
   bool success = service->GetCustomDictionary()->AddWord(params->word);
 
+#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+  if (spellcheck::UseBrowserSpellChecker()) {
+    spellcheck_platform::AddWord(base::UTF8ToUTF16(params->word));
+  }
+#endif
+
   return RespondNow(OneArgument(std::make_unique<base::Value>(success)));
 }
 
@@ -514,6 +522,12 @@
       SpellcheckServiceFactory::GetForContext(browser_context());
   bool success = service->GetCustomDictionary()->RemoveWord(params->word);
 
+#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+  if (spellcheck::UseBrowserSpellChecker()) {
+    spellcheck_platform::RemoveWord(base::UTF8ToUTF16(params->word));
+  }
+#endif
+
   return RespondNow(OneArgument(std::make_unique<base::Value>(success)));
 }
 
diff --git a/chrome/browser/extensions/extension_action.cc b/chrome/browser/extensions/extension_action.cc
index 1d76297d..a0d748c7 100644
--- a/chrome/browser/extensions/extension_action.cc
+++ b/chrome/browser/extensions/extension_action.cc
@@ -214,6 +214,7 @@
   title_.erase(tab_id);
   icon_.erase(tab_id);
   badge_text_.erase(tab_id);
+  dnr_action_count_.erase(tab_id);
   badge_text_color_.erase(tab_id);
   badge_background_color_.erase(tab_id);
   is_visible_.erase(tab_id);
@@ -251,6 +252,19 @@
   return placeholder_icon_image_;
 }
 
+std::string ExtensionAction::GetDisplayBadgeText(int tab_id) const {
+  // Tab specific badge text set by an extension overrides the automatically set
+  // action count.
+  if (HasBadgeText(tab_id))
+    return GetExplicitlySetBadgeText(tab_id);
+  if (HasDNRActionCount(tab_id))
+    return base::NumberToString(GetDNRActionCount(tab_id));
+
+  // Return the default badge text or an empty string if there is no badge text
+  // set for this tab.
+  return GetExplicitlySetBadgeText(kDefaultTabId);
+}
+
 bool ExtensionAction::HasPopupUrl(int tab_id) const {
   return HasValue(popup_url_, tab_id);
 }
@@ -279,6 +293,10 @@
   return HasValue(icon_, tab_id);
 }
 
+bool ExtensionAction::HasDNRActionCount(int tab_id) const {
+  return HasValue(dnr_action_count_, tab_id);
+}
+
 void ExtensionAction::SetDefaultIconForTest(
     std::unique_ptr<ExtensionIconSet> default_icon) {
   default_icon_ = std::move(default_icon);
diff --git a/chrome/browser/extensions/extension_action.h b/chrome/browser/extensions/extension_action.h
index b2d4893..27362cf 100644
--- a/chrome/browser/extensions/extension_action.h
+++ b/chrome/browser/extensions/extension_action.h
@@ -118,8 +118,9 @@
   void SetBadgeText(int tab_id, const std::string& text) {
     SetValue(&badge_text_, tab_id, text);
   }
-  // Get the badge text for a tab, or the default if no badge text was set.
-  std::string GetBadgeText(int tab_id) const {
+  // Get the badge text that has been set using SetBadgeText for a tab, or the
+  // default if no badge text was set.
+  std::string GetExplicitlySetBadgeText(int tab_id) const {
     return GetValue(&badge_text_, tab_id);
   }
 
@@ -143,6 +144,23 @@
     return GetValue(&badge_background_color_, tab_id);
   }
 
+  // Set this ExtensionAction's DNR matched action count on a specific tab.
+  void SetDNRActionCount(int tab_id, int action_count) {
+    SetValue(&dnr_action_count_, tab_id, action_count);
+  }
+  // Get this ExtensionAction's DNR matched action count on a specific tab.
+  // Returns -1 if no entry is found.
+  int GetDNRActionCount(int tab_id) const {
+    return GetValue(&dnr_action_count_, tab_id);
+  }
+
+  // Get the badge text displayed for a tab, calculated based on both
+  // |badge_text_| and |dnr_action_count_|. Returns in order of priority:
+  // - GetExplicitlySetBadgeText(tab_id) if it exists for the |tab_id|
+  // - GetDNRActionCount(tab_id)
+  // - The default badge text, if set, otherwise: an empty string.
+  std::string GetDisplayBadgeText(int tab_id) const;
+
   // Set this action's badge visibility on a specific tab.  Returns true if
   // the visibility has changed.
   bool SetIsVisible(int tab_id, bool value);
@@ -196,6 +214,7 @@
   bool HasBadgeTextColor(int tab_id) const;
   bool HasIsVisible(int tab_id) const;
   bool HasIcon(int tab_id) const;
+  bool HasDNRActionCount(int tab_id) const;
 
   extensions::IconImage* default_icon_image() {
     return default_icon_image_.get();
@@ -283,6 +302,11 @@
   // images that are currently in effect
   std::map<int, std::map<int, std::vector<gfx::Image> > > declarative_icon_;
 
+  // Maps tab_id to the number of actions taken based on declarative net request
+  // rule matches on incoming requests. Overrides the default |badge_text_| for
+  // this extension if it has called chrome.setActionCountAsBadgeText(true).
+  std::map<int, int> dnr_action_count_;
+
   // ExtensionIconSet containing paths to bitmaps from which default icon's
   // image representations will be selected.
   std::unique_ptr<ExtensionIconSet> default_icon_;
diff --git a/chrome/browser/extensions/extension_action_runner.cc b/chrome/browser/extensions/extension_action_runner.cc
index bcfe702..9608fa90 100644
--- a/chrome/browser/extensions/extension_action_runner.cc
+++ b/chrome/browser/extensions/extension_action_runner.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
 #include "chrome/browser/extensions/extension_action.h"
 #include "chrome/browser/extensions/extension_action_manager.h"
+#include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/extensions/permissions_updater.h"
 #include "chrome/browser/extensions/scripting_permissions_modifier.h"
 #include "chrome/browser/extensions/tab_helper.h"
@@ -35,6 +36,8 @@
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
+#include "extensions/browser/api/declarative_net_request/action_tracker.h"
+#include "extensions/browser/api/declarative_net_request/rules_monitor_service.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_messages.h"
@@ -521,11 +524,35 @@
   // run".
   ExtensionActionAPI::Get(browser_context_)
       ->ClearAllValuesForTab(web_contents());
+
+  declarative_net_request::RulesMonitorService* rules_monitor_service =
+      declarative_net_request::RulesMonitorService::Get(browser_context_);
+
+  // |rules_monitor_service| can be null for some unit tests.
+  if (rules_monitor_service) {
+    declarative_net_request::ActionTracker& action_tracker =
+        rules_monitor_service->ruleset_manager()->action_tracker();
+
+    int tab_id = ExtensionTabUtil::GetTabId(web_contents());
+    action_tracker.ResetActionCountForTab(tab_id);
+  }
 }
 
 void ExtensionActionRunner::WebContentsDestroyed() {
   ExtensionActionAPI::Get(browser_context_)
       ->ClearAllValuesForTab(web_contents());
+
+  declarative_net_request::RulesMonitorService* rules_monitor_service =
+      declarative_net_request::RulesMonitorService::Get(browser_context_);
+
+  // |rules_monitor_service| can be null for some unit tests.
+  if (rules_monitor_service) {
+    declarative_net_request::ActionTracker& action_tracker =
+        rules_monitor_service->ruleset_manager()->action_tracker();
+
+    int tab_id = ExtensionTabUtil::GetTabId(web_contents());
+    action_tracker.ClearTabData(tab_id);
+  }
 }
 
 void ExtensionActionRunner::OnExtensionUnloaded(
diff --git a/chrome/browser/extensions/extension_action_storage_manager.cc b/chrome/browser/extensions/extension_action_storage_manager.cc
index 33cdc582..d3ae2ae 100644
--- a/chrome/browser/extensions/extension_action_storage_manager.cc
+++ b/chrome/browser/extensions/extension_action_storage_manager.cc
@@ -167,7 +167,8 @@
   dict->SetString(kPopupUrlStorageKey,
                   action->GetPopupUrl(kDefaultTabId).spec());
   dict->SetString(kTitleStorageKey, action->GetTitle(kDefaultTabId));
-  dict->SetString(kBadgeTextStorageKey, action->GetBadgeText(kDefaultTabId));
+  dict->SetString(kBadgeTextStorageKey,
+                  action->GetExplicitlySetBadgeText(kDefaultTabId));
   dict->SetString(
       kBadgeBackgroundColorStorageKey,
       SkColorToRawString(action->GetBadgeBackgroundColor(kDefaultTabId)));
diff --git a/chrome/browser/extensions/extension_action_unittest.cc b/chrome/browser/extensions/extension_action_unittest.cc
index da1f427..6db6bee 100644
--- a/chrome/browser/extensions/extension_action_unittest.cc
+++ b/chrome/browser/extensions/extension_action_unittest.cc
@@ -79,17 +79,37 @@
 TEST(ExtensionActionTest, Badge) {
   std::unique_ptr<ExtensionAction> action =
       CreateAction(ActionInfo(ActionInfo::TYPE_PAGE));
-  ASSERT_EQ("", action->GetBadgeText(1));
+  ASSERT_EQ("", action->GetExplicitlySetBadgeText(1));
   action->SetBadgeText(ExtensionAction::kDefaultTabId, "foo");
-  ASSERT_EQ("foo", action->GetBadgeText(1));
-  ASSERT_EQ("foo", action->GetBadgeText(100));
+  ASSERT_EQ("foo", action->GetExplicitlySetBadgeText(1));
+  ASSERT_EQ("foo", action->GetExplicitlySetBadgeText(100));
   action->SetBadgeText(100, "bar");
-  ASSERT_EQ("foo", action->GetBadgeText(1));
-  ASSERT_EQ("bar", action->GetBadgeText(100));
+  ASSERT_EQ("foo", action->GetExplicitlySetBadgeText(1));
+  ASSERT_EQ("bar", action->GetExplicitlySetBadgeText(100));
   action->SetBadgeText(ExtensionAction::kDefaultTabId, "baz");
-  ASSERT_EQ("baz", action->GetBadgeText(1));
+  ASSERT_EQ("baz", action->GetExplicitlySetBadgeText(1));
   action->ClearAllValuesForTab(100);
-  ASSERT_EQ("baz", action->GetBadgeText(100));
+  ASSERT_EQ("baz", action->GetExplicitlySetBadgeText(100));
+}
+
+TEST(ExtensionActionTest, DisplayBadgeText) {
+  constexpr int kFirstTabId = 1;
+  constexpr int kSecondTabId = 2;
+
+  std::unique_ptr<ExtensionAction> action =
+      CreateAction(ActionInfo(ActionInfo::TYPE_PAGE));
+  ASSERT_EQ("", action->GetDisplayBadgeText(kFirstTabId));
+  action->SetDNRActionCount(kFirstTabId, 10 /* action_count */);
+  ASSERT_EQ("10", action->GetDisplayBadgeText(kFirstTabId));
+  action->SetBadgeText(ExtensionAction::kDefaultTabId, "foo");
+  ASSERT_EQ("10", action->GetDisplayBadgeText(kFirstTabId));
+  ASSERT_EQ("foo", action->GetDisplayBadgeText(kSecondTabId));
+  action->SetBadgeText(kFirstTabId, "bar");
+  ASSERT_EQ("bar", action->GetDisplayBadgeText(kFirstTabId));
+  action->SetDNRActionCount(kFirstTabId, 100 /* action_count */);
+  ASSERT_EQ("bar", action->GetDisplayBadgeText(kFirstTabId));
+  action->ClearAllValuesForTab(kFirstTabId);
+  ASSERT_EQ("foo", action->GetDisplayBadgeText(kFirstTabId));
 }
 
 TEST(ExtensionActionTest, BadgeTextColor) {
diff --git a/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc b/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc
index c1e9a9a..fbab482 100644
--- a/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc
+++ b/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc
@@ -10,13 +10,16 @@
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_macros_local.h"
+#include "base/rand_util.h"
 #include "base/sequenced_task_runner.h"
 #include "base/task/post_task.h"
 #include "base/task_runner_util.h"
+#include "base/time/default_clock.h"
 #include "components/optimization_guide/bloom_filter.h"
 #include "components/optimization_guide/hint_cache.h"
 #include "components/optimization_guide/hint_cache_store.h"
 #include "components/optimization_guide/hints_component_util.h"
+#include "components/optimization_guide/hints_fetcher.h"
 #include "components/optimization_guide/hints_processing_util.h"
 #include "components/optimization_guide/optimization_filter.h"
 #include "components/optimization_guide/optimization_guide_features.h"
@@ -27,6 +30,7 @@
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_handle.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace {
 
@@ -35,6 +39,24 @@
 // will have a newer version than it.
 constexpr char kManualConfigComponentVersion[] = "0.0.0";
 
+// Delay between retries on failed fetch and store of hints from the remote
+// Optimization Guide Service.
+constexpr base::TimeDelta kFetchRetryDelay = base::TimeDelta::FromMinutes(15);
+
+// Delay until successfully fetched hints should be updated by requesting from
+// the remote Optimization Guide Service.
+constexpr base::TimeDelta kUpdateFetchedHintsDelay =
+    base::TimeDelta::FromHours(24);
+
+// Provides a random time delta in seconds between |kFetchRandomMinDelay| and
+// |kFetchRandomMaxDelay|.
+base::TimeDelta RandomFetchDelay() {
+  constexpr int kFetchRandomMinDelaySecs = 30;
+  constexpr int kFetchRandomMaxDelaySecs = 60;
+  return base::TimeDelta::FromSeconds(
+      base::RandInt(kFetchRandomMinDelaySecs, kFetchRandomMaxDelaySecs));
+}
+
 void MaybeRunUpdateClosure(base::OnceClosure update_closure) {
   if (update_closure)
     std::move(update_closure).Run();
@@ -79,7 +101,8 @@
     const base::FilePath& profile_path,
     PrefService* pref_service,
     leveldb_proto::ProtoDatabaseProvider* database_provider,
-    optimization_guide::TopHostProvider* top_host_provider)
+    optimization_guide::TopHostProvider* top_host_provider,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
     : optimization_guide_service_(optimization_guide_service),
       background_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
           {base::ThreadPool(), base::MayBlock(),
@@ -91,7 +114,9 @@
               profile_path,
               pref_service_,
               background_task_runner_))),
-      top_host_provider_(top_host_provider) {
+      top_host_provider_(top_host_provider),
+      url_loader_factory_(url_loader_factory),
+      clock_(base::DefaultClock::GetInstance()) {
   DCHECK(optimization_guide_service_);
   hint_cache_->Initialize(
       optimization_guide::switches::ShouldPurgeHintCacheStoreOnStartup(),
@@ -312,17 +337,121 @@
   next_update_closure_ = std::move(next_update_closure);
 }
 
-void OptimizationGuideHintsManager::MaybeScheduleHintsFetch() {
-  bool hints_fetching_allowed =
-      optimization_guide::features::IsHintsFetchingEnabled() &&
-      top_host_provider_;
-  // This local histogram is only used for testing and will be removed when the
-  // actual implementation to schedule hints fetches is in place.
-  LOCAL_HISTOGRAM_BOOLEAN("OptimizationGuide.HintsFetching.Allowed",
-                          hints_fetching_allowed);
+void OptimizationGuideHintsManager::SetClockForTesting(
+    const base::Clock* clock) {
+  clock_ = clock;
+}
 
-  // TODO(crbug/969558): Implement this to actually schedule a hints fetch and
-  // remove above local histogram.
+void OptimizationGuideHintsManager::SetHintsFetcherForTesting(
+    std::unique_ptr<optimization_guide::HintsFetcher> hints_fetcher) {
+  hints_fetcher_ = std::move(hints_fetcher);
+}
+
+void OptimizationGuideHintsManager::MaybeScheduleHintsFetch() {
+  if (!optimization_guide::features::IsHintsFetchingEnabled() ||
+      !top_host_provider_) {
+    return;
+  }
+
+  if (optimization_guide::switches::ShouldOverrideFetchHintsTimer()) {
+    SetLastHintsFetchAttemptTime(clock_->Now());
+    FetchHints();
+  } else {
+    ScheduleHintsFetch();
+  }
+}
+
+void OptimizationGuideHintsManager::ScheduleHintsFetch() {
+  DCHECK(!hints_fetch_timer_.IsRunning());
+
+  const base::TimeDelta time_until_update_time =
+      hint_cache_->FetchedHintsUpdateTime() - clock_->Now();
+  const base::TimeDelta time_until_retry =
+      GetLastHintsFetchAttemptTime() + kFetchRetryDelay - clock_->Now();
+  base::TimeDelta fetcher_delay;
+  if (time_until_update_time <= base::TimeDelta() &&
+      time_until_retry <= base::TimeDelta()) {
+    // Fetched hints in the store should be updated and an attempt has not
+    // been made in last |kFetchRetryDelay|.
+    SetLastHintsFetchAttemptTime(clock_->Now());
+    hints_fetch_timer_.Start(FROM_HERE, RandomFetchDelay(), this,
+                             &OptimizationGuideHintsManager::FetchHints);
+  } else {
+    if (time_until_update_time >= base::TimeDelta()) {
+      // If the fetched hints in the store are still up-to-date, set a timer
+      // for when the hints need to be updated.
+      fetcher_delay = time_until_update_time;
+    } else {
+      // Otherwise, hints need to be updated but an attempt was made in last
+      // |kFetchRetryDelay|. Schedule the timer for after the retry
+      // delay.
+      fetcher_delay = time_until_retry;
+    }
+    hints_fetch_timer_.Start(
+        FROM_HERE, fetcher_delay, this,
+        &OptimizationGuideHintsManager::ScheduleHintsFetch);
+  }
+}
+
+void OptimizationGuideHintsManager::FetchHints() {
+  DCHECK(top_host_provider_);
+
+  size_t max_hints_to_fetch = optimization_guide::features::
+      MaxHostsForOptimizationGuideServiceHintsFetch();
+  std::vector<std::string> top_hosts =
+      top_host_provider_->GetTopHosts(max_hints_to_fetch);
+  if (top_hosts.empty())
+    return;
+  DCHECK_GE(max_hints_to_fetch, top_hosts.size());
+
+  if (!hints_fetcher_) {
+    hints_fetcher_ = std::make_unique<optimization_guide::HintsFetcher>(
+        url_loader_factory_,
+        optimization_guide::features::GetOptimizationGuideServiceURL());
+  }
+  hints_fetcher_->FetchOptimizationGuideServiceHints(
+      top_hosts, base::BindOnce(&OptimizationGuideHintsManager::OnHintsFetched,
+                                ui_weak_ptr_factory_.GetWeakPtr()));
+}
+
+void OptimizationGuideHintsManager::OnHintsFetched(
+    base::Optional<std::unique_ptr<optimization_guide::proto::GetHintsResponse>>
+        get_hints_response) {
+  if (get_hints_response) {
+    hint_cache_->UpdateFetchedHints(
+        std::move(*get_hints_response),
+        clock_->Now() + kUpdateFetchedHintsDelay,
+        base::BindOnce(&OptimizationGuideHintsManager::OnFetchedHintsStored,
+                       ui_weak_ptr_factory_.GetWeakPtr()));
+  } else {
+    // The fetch did not succeed so we will schedule to retry the fetch in
+    // after delaying for |kFetchRetryDelay|
+    // TODO(mcrouse): When the store is refactored from closures, the timer will
+    // be scheduled on failure of the store instead.
+    hints_fetch_timer_.Start(
+        FROM_HERE, kFetchRetryDelay, this,
+        &OptimizationGuideHintsManager::ScheduleHintsFetch);
+  }
+}
+
+void OptimizationGuideHintsManager::OnFetchedHintsStored() {
+  hints_fetch_timer_.Stop();
+  hints_fetch_timer_.Start(
+      FROM_HERE, hint_cache_->FetchedHintsUpdateTime() - clock_->Now(), this,
+      &OptimizationGuideHintsManager::ScheduleHintsFetch);
+}
+
+base::Time OptimizationGuideHintsManager::GetLastHintsFetchAttemptTime() const {
+  return base::Time::FromDeltaSinceWindowsEpoch(
+      base::TimeDelta::FromMicroseconds(pref_service_->GetInt64(
+          optimization_guide::prefs::kHintsFetcherLastFetchAttempt)));
+}
+
+void OptimizationGuideHintsManager::SetLastHintsFetchAttemptTime(
+    base::Time last_attempt_time) {
+  pref_service_->SetInt64(
+      optimization_guide::prefs::kHintsFetcherLastFetchAttempt,
+      last_attempt_time.ToDeltaSinceWindowsEpoch().InMicroseconds());
 }
 
 void OptimizationGuideHintsManager::LoadHintForNavigation(
diff --git a/chrome/browser/optimization_guide/optimization_guide_hints_manager.h b/chrome/browser/optimization_guide/optimization_guide_hints_manager.h
index 17e6b67..0f3e274 100644
--- a/chrome/browser/optimization_guide/optimization_guide_hints_manager.h
+++ b/chrome/browser/optimization_guide/optimization_guide_hints_manager.h
@@ -11,10 +11,13 @@
 #include <vector>
 
 #include "base/callback_forward.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
 #include "base/sequenced_task_runner.h"
 #include "base/synchronization/lock.h"
+#include "base/time/clock.h"
+#include "base/timer/timer.h"
 #include "components/optimization_guide/hints_component_info.h"
 #include "components/optimization_guide/optimization_guide_service_observer.h"
 #include "components/optimization_guide/proto/hints.pb.h"
@@ -31,9 +34,14 @@
 class ProtoDatabaseProvider;
 }  // namespace leveldb_proto
 
+namespace network {
+class SharedURLLoaderFactory;
+}  // namespace network
+
 namespace optimization_guide {
 class HintCache;
 class HintUpdateData;
+class HintsFetcher;
 class OptimizationFilter;
 class OptimizationGuideService;
 class TopHostProvider;
@@ -49,7 +57,8 @@
       const base::FilePath& profile_path,
       PrefService* pref_service,
       leveldb_proto::ProtoDatabaseProvider* database_provider,
-      optimization_guide::TopHostProvider* top_host_provider);
+      optimization_guide::TopHostProvider* top_host_provider,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
 
   ~OptimizationGuideHintsManager() override;
 
@@ -87,6 +96,18 @@
   bool HasLoadedOptimizationFilter(
       optimization_guide::proto::OptimizationType optimization_type);
 
+  // Overrides |hints_fetcher_| for testing.
+  void SetHintsFetcherForTesting(
+      std::unique_ptr<optimization_guide::HintsFetcher> hints_fetcher);
+
+  // Returns the current hints fetcher.
+  optimization_guide::HintsFetcher* hints_fetcher() const {
+    return hints_fetcher_.get();
+  }
+
+  // Overrides |clock_| for testing.
+  void SetClockForTesting(const base::Clock* clock);
+
  private:
   // Processes the hints component.
   //
@@ -123,9 +144,36 @@
   void OnComponentHintsUpdated(base::OnceClosure update_closure,
                                bool hints_updated) const;
 
-  // Method to request new hints for user's sites.
+  // Method to decide whether to fetch new hints for user's top sites and
+  // proceeds to schedule the fetch.
   void MaybeScheduleHintsFetch();
 
+  // Schedules |hints_fetch_timer_| to fire based on:
+  // 1. The update time for the fetched hints in the store and
+  // 2. The last time a fetch attempt was made.
+  void ScheduleHintsFetch();
+
+  // Called to make a request to fetch hints from the remote Optimization Guide
+  // Service.
+  void FetchHints();
+
+  // Called when the hints have been fetched from the remote Optimization Guide
+  // Service and are ready for parsing.
+  void OnHintsFetched(
+      base::Optional<
+          std::unique_ptr<optimization_guide::proto::GetHintsResponse>>
+          get_hints_response);
+
+  // Called when the fetched hints have been stored in |hint_cache| and are
+  // ready to be used.
+  void OnFetchedHintsStored();
+
+  // Returns the time when a hints fetch request was last attempted.
+  base::Time GetLastHintsFetchAttemptTime() const;
+
+  // Sets the time when a hints fetch was last attempted to |last_attempt_time|.
+  void SetLastHintsFetchAttemptTime(base::Time last_attempt_time);
+
   // Called when the request to load a hint has completed.
   void OnHintLoaded(base::OnceClosure callback,
                     const optimization_guide::proto::Hint* loaded_hint) const;
@@ -169,9 +217,25 @@
   // fetched from the remote Optimization Guide Service.
   std::unique_ptr<optimization_guide::HintCache> hint_cache_;
 
+  // The fetcher that handles making requests to update hints from the remote
+  // Optimization Guide Service.
+  std::unique_ptr<optimization_guide::HintsFetcher> hints_fetcher_;
+
   // The top host provider that can be queried. Not owned.
   optimization_guide::TopHostProvider* top_host_provider_ = nullptr;
 
+  // The URL loader factory used for fetching hints from the remote Optimization
+  // Guide Service.
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
+
+  // The timer used to schedule fetching hints from the remote Optimization
+  // Guide Service.
+  base::OneShotTimer hints_fetch_timer_;
+
+  // The clock used to schedule fetching from the remote Optimization Guide
+  // Service.
+  const base::Clock* clock_;
+
   // Used in testing to subscribe to an update event in this class.
   base::OnceClosure next_update_closure_;
 
diff --git a/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc b/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc
index e129ec87..1602ffc9 100644
--- a/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc
+++ b/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/optimization_guide/optimization_guide_hints_manager.h"
 
 #include <string>
+#include <utility>
 
 #include "base/base64.h"
 #include "base/command_line.h"
@@ -12,19 +13,30 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "components/optimization_guide/bloom_filter.h"
-#include "components/optimization_guide/command_line_top_host_provider.h"
 #include "components/optimization_guide/hints_component_util.h"
+#include "components/optimization_guide/hints_fetcher.h"
 #include "components/optimization_guide/optimization_guide_features.h"
 #include "components/optimization_guide/optimization_guide_prefs.h"
 #include "components/optimization_guide/optimization_guide_service.h"
 #include "components/optimization_guide/optimization_guide_switches.h"
 #include "components/optimization_guide/proto_database_provider_test_base.h"
+#include "components/optimization_guide/top_host_provider.h"
 #include "components/prefs/testing_pref_service.h"
 #include "content/public/test/mock_navigation_handle.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
 
+// Retry delay is 16 minutes to allow for kFetchRetryDelaySecs +
+// kFetchRandomMaxDelaySecs to pass.
+constexpr int kTestFetchRetryDelaySecs = 60 * 16;
+constexpr int kUpdateFetchHintsTimeSecs = 24 * 60 * 60;  // 24 hours.
+
 const int kBlackBlacklistBloomFilterNumHashFunctions = 7;
 const int kBlackBlacklistBloomFilterNumBits = 511;
 
@@ -53,6 +65,22 @@
   blacklist_proto->set_allocated_bloom_filter(bloom_filter_proto.release());
 }
 
+std::unique_ptr<optimization_guide::proto::GetHintsResponse> BuildHintsResponse(
+    std::vector<std::string> hosts) {
+  std::unique_ptr<optimization_guide::proto::GetHintsResponse>
+      get_hints_response =
+          std::make_unique<optimization_guide::proto::GetHintsResponse>();
+
+  for (const auto& host : hosts) {
+    optimization_guide::proto::Hint* hint = get_hints_response->add_hints();
+    hint->set_key_representation(optimization_guide::proto::HOST_SUFFIX);
+    hint->set_key(host);
+    optimization_guide::proto::PageHint* page_hint = hint->add_page_hints();
+    page_hint->set_page_pattern("page pattern");
+  }
+  return get_hints_response;
+}
+
 }  // namespace
 
 class TestOptimizationGuideService
@@ -82,6 +110,57 @@
   bool remove_observer_called_ = false;
 };
 
+// A mock class implementation of TopHostProvider.
+class MockTopHostProvider : public optimization_guide::TopHostProvider {
+ public:
+  MOCK_METHOD1(GetTopHosts, std::vector<std::string>(size_t max_sites));
+};
+
+enum class HintsFetcherEndState {
+  kFetchFailed = 0,
+  kFetchSuccessWithHints = 1,
+  kFetchSuccessWithNoHints = 2,
+};
+
+// A mock class implementation of HintsFetcher.
+class TestHintsFetcher : public optimization_guide::HintsFetcher {
+  using HintsFetcher::FetchOptimizationGuideServiceHints;
+
+ public:
+  TestHintsFetcher(
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+      GURL optimization_guide_service_url,
+      HintsFetcherEndState fetch_state)
+      : HintsFetcher(url_loader_factory, optimization_guide_service_url),
+        fetch_state_(fetch_state) {}
+
+  bool FetchOptimizationGuideServiceHints(
+      const std::vector<std::string>& hosts,
+      optimization_guide::HintsFetchedCallback hints_fetched_callback)
+      override {
+    switch (fetch_state_) {
+      case HintsFetcherEndState::kFetchFailed:
+        std::move(hints_fetched_callback).Run(base::nullopt);
+        return false;
+      case HintsFetcherEndState::kFetchSuccessWithHints:
+        hints_fetched_ = true;
+        std::move(hints_fetched_callback).Run(BuildHintsResponse({"host.com"}));
+        return true;
+      case HintsFetcherEndState::kFetchSuccessWithNoHints:
+        hints_fetched_ = true;
+        std::move(hints_fetched_callback).Run(BuildHintsResponse({}));
+        return true;
+    }
+    return true;
+  }
+
+  bool hints_fetched() { return hints_fetched_; }
+
+ private:
+  bool hints_fetched_ = false;
+  HintsFetcherEndState fetch_state_;
+};
+
 class OptimizationGuideHintsManagerTest
     : public optimization_guide::ProtoDatabaseProviderTestBase {
  public:
@@ -109,9 +188,14 @@
     pref_service_ = std::make_unique<TestingPrefServiceSimple>();
     optimization_guide::prefs::RegisterProfilePrefs(pref_service_->registry());
 
+    url_loader_factory_ =
+        base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+            &test_url_loader_factory_);
+
     hints_manager_ = std::make_unique<OptimizationGuideHintsManager>(
         optimization_guide_service_.get(), temp_dir(), pref_service_.get(),
-        db_provider_.get(), top_host_provider);
+        db_provider_.get(), top_host_provider, url_loader_factory_);
+    hints_manager_->SetClockForTesting(browser_thread_bundle_.GetMockClock());
 
     // Add observer is called after the HintCache is fully initialized,
     // indicating that the OptimizationGuideHintsManager is ready to process
@@ -171,10 +255,27 @@
     ProcessHints(config, version);
   }
 
+  std::unique_ptr<TestHintsFetcher> BuildTestHintsFetcher(
+      HintsFetcherEndState end_state) {
+    std::unique_ptr<TestHintsFetcher> hints_fetcher =
+        std::make_unique<TestHintsFetcher>(
+            url_loader_factory_, GURL("https://hintsserver.com"), end_state);
+    return hints_fetcher;
+  }
+
+  void MoveClockForwardBy(base::TimeDelta time_delta) {
+    browser_thread_bundle_.FastForwardBy(time_delta);
+    RunUntilIdle();
+  }
+
   OptimizationGuideHintsManager* hints_manager() const {
     return hints_manager_.get();
   }
 
+  TestHintsFetcher* hints_fetcher() const {
+    return static_cast<TestHintsFetcher*>(hints_manager()->hints_fetcher());
+  }
+
   GURL url_with_hints() const {
     return GURL("https://somedomain.org/news/whatever");
   }
@@ -199,11 +300,15 @@
                               serialized_config.size()));
   }
 
-  content::TestBrowserThreadBundle browser_thread_bundle_;
+  content::TestBrowserThreadBundle browser_thread_bundle_ = {
+      base::test::ScopedTaskEnvironment::MainThreadType::UI,
+      base::test::ScopedTaskEnvironment::TimeSource::MOCK_TIME};
 
   std::unique_ptr<OptimizationGuideHintsManager> hints_manager_;
   std::unique_ptr<TestOptimizationGuideService> optimization_guide_service_;
   std::unique_ptr<TestingPrefServiceSimple> pref_service_;
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
+  network::TestURLLoaderFactory test_url_loader_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(OptimizationGuideHintsManagerTest);
 };
@@ -711,46 +816,157 @@
   feature_list.InitWithFeatures(
       {optimization_guide::features::kOptimizationHintsFetching}, {});
 
-  base::HistogramTester histogram_tester;
+  std::unique_ptr<MockTopHostProvider> top_host_provider =
+      std::make_unique<MockTopHostProvider>();
+  EXPECT_CALL(*top_host_provider, GetTopHosts(testing::_)).Times(0);
 
   CreateServiceAndHintsManager(/*top_host_provider=*/nullptr);
+  hints_manager()->SetHintsFetcherForTesting(
+      BuildTestHintsFetcher(HintsFetcherEndState::kFetchSuccessWithHints));
 
-  histogram_tester.ExpectUniqueSample("OptimizationGuide.HintsFetching.Allowed",
-                                      false, 1);
+  // Force timer to expire and schedule a hints fetch.
+  MoveClockForwardBy(base::TimeDelta::FromSeconds(kTestFetchRetryDelaySecs));
+  EXPECT_FALSE(hints_fetcher()->hints_fetched());
 }
 
 TEST_F(OptimizationGuideHintsManagerTest,
        HintsFetchNotAllowedIfFeatureIsNotEnabledButTopHostProviderIsProvided) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      optimization_guide::switches::kFetchHintsOverride, "whatever.com");
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures(
       {}, {optimization_guide::features::kOptimizationHintsFetching});
 
-  base::HistogramTester histogram_tester;
+  std::unique_ptr<MockTopHostProvider> top_host_provider =
+      std::make_unique<MockTopHostProvider>();
+  EXPECT_CALL(*top_host_provider, GetTopHosts(testing::_)).Times(0);
 
-  std::unique_ptr<optimization_guide::TopHostProvider> top_host_provider =
-      optimization_guide::CommandLineTopHostProvider::CreateIfEnabled();
   CreateServiceAndHintsManager(top_host_provider.get());
-
-  histogram_tester.ExpectUniqueSample("OptimizationGuide.HintsFetching.Allowed",
-                                      false, 1);
 }
 
 TEST_F(OptimizationGuideHintsManagerTest,
        HintsFetchAllowedIfFeatureIsEnabledAndTopHostProviderIsProvided) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      optimization_guide::switches::kFetchHintsOverride, "whatever.com");
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures(
       {optimization_guide::features::kOptimizationHintsFetching}, {});
 
-  base::HistogramTester histogram_tester;
+  std::unique_ptr<MockTopHostProvider> top_host_provider =
+      std::make_unique<MockTopHostProvider>();
+  std::vector<std::string> hosts = {"example1.com", "example2.com"};
+  EXPECT_CALL(*top_host_provider, GetTopHosts(testing::_))
+      .Times(1)
+      .WillRepeatedly(testing::Return(hosts));
 
-  std::unique_ptr<optimization_guide::TopHostProvider> top_host_provider =
-      optimization_guide::CommandLineTopHostProvider::CreateIfEnabled();
   CreateServiceAndHintsManager(top_host_provider.get());
+  hints_manager()->SetHintsFetcherForTesting(
+      BuildTestHintsFetcher(HintsFetcherEndState::kFetchSuccessWithHints));
 
-  histogram_tester.ExpectUniqueSample("OptimizationGuide.HintsFetching.Allowed",
-                                      true, 1);
+  // Force timer to expire and schedule a hints fetch.
+  MoveClockForwardBy(base::TimeDelta::FromSeconds(kTestFetchRetryDelaySecs));
+  EXPECT_TRUE(hints_fetcher()->hints_fetched());
+}
+
+TEST_F(OptimizationGuideHintsManagerTest, HintsFetcherEnabledNoHostsToFetch) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      optimization_guide::features::kOptimizationHintsFetching);
+
+  std::unique_ptr<MockTopHostProvider> top_host_provider =
+      std::make_unique<MockTopHostProvider>();
+  EXPECT_CALL(*top_host_provider, GetTopHosts(testing::_)).Times(1);
+  CreateServiceAndHintsManager(top_host_provider.get());
+  hints_manager()->SetHintsFetcherForTesting(
+      BuildTestHintsFetcher(HintsFetcherEndState::kFetchSuccessWithHints));
+
+  // Force timer to expire and schedule a hints fetch.
+  MoveClockForwardBy(base::TimeDelta::FromSeconds(kTestFetchRetryDelaySecs));
+  EXPECT_FALSE(hints_fetcher()->hints_fetched());
+}
+
+TEST_F(OptimizationGuideHintsManagerTest,
+       HintsFetcherEnabledWithHostsNoHintsInResponse) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      optimization_guide::features::kOptimizationHintsFetching);
+
+  std::unique_ptr<MockTopHostProvider> top_host_provider =
+      std::make_unique<MockTopHostProvider>();
+  std::vector<std::string> hosts = {"example1.com", "example2.com"};
+  // This should be called exactly once, confirming that hints are not fetched
+  // again after |kTestFetchRetryDelaySecs|.
+  EXPECT_CALL(*top_host_provider, GetTopHosts(testing::_))
+      .Times(1)
+      .WillRepeatedly(testing::Return(hosts));
+  CreateServiceAndHintsManager(top_host_provider.get());
+  hints_manager()->SetHintsFetcherForTesting(
+      BuildTestHintsFetcher(HintsFetcherEndState::kFetchSuccessWithNoHints));
+
+  // Force timer to expire and schedule a hints fetch.
+  MoveClockForwardBy(base::TimeDelta::FromSeconds(kTestFetchRetryDelaySecs));
+  EXPECT_TRUE(hints_fetcher()->hints_fetched());
+
+  // Check that hints should not be fetched again after the delay for a failed
+  // hints fetch attempt.
+  MoveClockForwardBy(base::TimeDelta::FromSeconds(kTestFetchRetryDelaySecs));
+  EXPECT_CALL(*top_host_provider, GetTopHosts(testing::_)).Times(0);
+}
+
+TEST_F(OptimizationGuideHintsManagerTest, HintsFetcherTimerRetryDelay) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      optimization_guide::features::kOptimizationHintsFetching);
+
+  std::unique_ptr<MockTopHostProvider> top_host_provider =
+      std::make_unique<MockTopHostProvider>();
+  std::vector<std::string> hosts = {"example1.com", "example2.com"};
+  // Should be called twice: once for the failed fetch and then again for the
+  // successful fetch.
+  EXPECT_CALL(*top_host_provider, GetTopHosts(testing::_))
+      .Times(2)
+      .WillRepeatedly(testing::Return(hosts));
+
+  CreateServiceAndHintsManager(top_host_provider.get());
+  hints_manager()->SetHintsFetcherForTesting(
+      BuildTestHintsFetcher(HintsFetcherEndState::kFetchFailed));
+
+  // Force timer to expire and schedule a hints fetch - first time.
+  MoveClockForwardBy(base::TimeDelta::FromSeconds(kTestFetchRetryDelaySecs));
+  EXPECT_FALSE(hints_fetcher()->hints_fetched());
+
+  // Force speculative timer to expire after fetch fails first time, update
+  // hints fetcher so it succeeds this time.
+  hints_manager()->SetHintsFetcherForTesting(
+      BuildTestHintsFetcher(HintsFetcherEndState::kFetchSuccessWithHints));
+  MoveClockForwardBy(base::TimeDelta::FromSeconds(kTestFetchRetryDelaySecs));
+  EXPECT_TRUE(hints_fetcher()->hints_fetched());
+}
+
+TEST_F(OptimizationGuideHintsManagerTest, HintsFetcherTimerFetchSucceeds) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      optimization_guide::features::kOptimizationHintsFetching);
+
+  std::unique_ptr<MockTopHostProvider> top_host_provider =
+      std::make_unique<MockTopHostProvider>();
+  std::vector<std::string> hosts = {"example1.com", "example2.com"};
+  EXPECT_CALL(*top_host_provider, GetTopHosts(testing::_))
+      .WillRepeatedly(testing::Return(hosts));
+
+  // Force hints fetch scheduling.
+  CreateServiceAndHintsManager(top_host_provider.get());
+  hints_manager()->SetHintsFetcherForTesting(
+      BuildTestHintsFetcher(HintsFetcherEndState::kFetchSuccessWithHints));
+
+  // Force timer to expire and schedule a hints fetch that succeeds.
+  MoveClockForwardBy(base::TimeDelta::FromSeconds(kTestFetchRetryDelaySecs));
+  EXPECT_TRUE(hints_fetcher()->hints_fetched());
+
+  // TODO(mcrouse): Make sure timer is triggered by metadata entry,
+  // |hint_cache| control needed.
+  hints_manager()->SetHintsFetcherForTesting(
+      BuildTestHintsFetcher(HintsFetcherEndState::kFetchSuccessWithHints));
+
+  MoveClockForwardBy(base::TimeDelta::FromSeconds(kTestFetchRetryDelaySecs));
+  EXPECT_FALSE(hints_fetcher()->hints_fetched());
+
+  MoveClockForwardBy(base::TimeDelta::FromSeconds(kUpdateFetchHintsTimeSecs));
+  EXPECT_TRUE(hints_fetcher()->hints_fetched());
 }
diff --git a/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc b/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc
index 22252bc..a4318882 100644
--- a/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc
+++ b/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc
@@ -17,6 +17,7 @@
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/storage_partition.h"
 
 namespace {
 
@@ -57,10 +58,12 @@
   DCHECK(optimization_guide_service);
 
   top_host_provider_ = GetTopHostProviderIfUserPermitted(browser_context_);
+  Profile* profile = Profile::FromBrowserContext(browser_context_);
   hints_manager_ = std::make_unique<OptimizationGuideHintsManager>(
-      optimization_guide_service, profile_path,
-      Profile::FromBrowserContext(browser_context_)->GetPrefs(),
-      database_provider, top_host_provider_.get());
+      optimization_guide_service, profile_path, profile->GetPrefs(),
+      database_provider, top_host_provider_.get(),
+      content::BrowserContext::GetDefaultStoragePartition(profile)
+          ->GetURLLoaderFactoryForBrowserProcess());
 }
 
 void OptimizationGuideKeyedService::RegisterOptimizationTypes(
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc
index de5e56c..3dbe0c2 100644
--- a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc
@@ -6,6 +6,7 @@
 
 #include <stddef.h>
 #include <stdint.h>
+
 #include <memory>
 #include <utility>
 
@@ -46,7 +47,8 @@
 void RecordFirstMeaningfulPaintStatus(
     internal::FirstMeaningfulPaintStatus status) {
   UMA_HISTOGRAM_ENUMERATION(internal::kHistogramFirstMeaningfulPaintStatus,
-      status, internal::FIRST_MEANINGFUL_PAINT_LAST_ENTRY);
+                            status,
+                            internal::FIRST_MEANINGFUL_PAINT_LAST_ENTRY);
 }
 
 void RecordTimeToInteractiveStatus(internal::TimeToInteractiveStatus status) {
@@ -797,41 +799,50 @@
                         info.first_foreground_time.value());
   }
 
-  if (WasStartedInForegroundOptionalEventInForeground(
-          main_frame_timing.paint_timing->largest_image_paint, info)) {
-    PAGE_LOAD_HISTOGRAM(
-        internal::kHistogramLargestImagePaint,
-        main_frame_timing.paint_timing->largest_image_paint.value());
-  }
-  if (WasStartedInForegroundOptionalEventInForeground(
-          main_frame_timing.paint_timing->largest_text_paint, info)) {
-    PAGE_LOAD_HISTOGRAM(
-        internal::kHistogramLargestTextPaint,
-        main_frame_timing.paint_timing->largest_text_paint.value());
-  }
-  base::Optional<base::TimeDelta> largest_content_paint_time;
-  uint64_t largest_content_paint_size;
-  PageLoadMetricsObserver::LargestContentType largest_content_type;
-  if (AssignTimeAndSizeForLargestContentfulPaint(
-          main_frame_timing.paint_timing, &largest_content_paint_time,
-          &largest_content_paint_size, &largest_content_type) &&
+  const page_load_metrics::ContentfulPaintTimingInfo&
+      main_frame_largest_image_paint =
+          largest_contentful_paint_handler_.MainFrameLargestImagePaint();
+  if (!main_frame_largest_image_paint.IsEmpty() &&
       WasStartedInForegroundOptionalEventInForeground(
-          largest_content_paint_time, info)) {
-    PAGE_LOAD_HISTOGRAM(internal::kHistogramLargestContentfulPaintMainFrame,
-                        largest_content_paint_time.value());
-    UMA_HISTOGRAM_ENUMERATION(
-        internal::kHistogramLargestContentfulPaintMainFrameContentType,
-        largest_content_type);
+          main_frame_largest_image_paint.Time(), info)) {
+    PAGE_LOAD_HISTOGRAM(internal::kHistogramLargestImagePaint,
+                        main_frame_largest_image_paint.Time().value());
   }
 
-  const page_load_metrics::ContentfulPaintTimingInfo& paint =
-      largest_contentful_paint_handler_.MergeMainFrameAndSubframes();
-  if (!paint.IsEmpty() &&
-      WasStartedInForegroundOptionalEventInForeground(paint.Time(), info)) {
-    PAGE_LOAD_HISTOGRAM(internal::kHistogramLargestContentfulPaint,
-                        paint.Time().value());
+  const page_load_metrics::ContentfulPaintTimingInfo&
+      main_frame_largest_text_paint =
+          largest_contentful_paint_handler_.MainFrameLargestTextPaint();
+  if (!main_frame_largest_text_paint.IsEmpty() &&
+      WasStartedInForegroundOptionalEventInForeground(
+          main_frame_largest_text_paint.Time(), info)) {
+    PAGE_LOAD_HISTOGRAM(internal::kHistogramLargestTextPaint,
+                        main_frame_largest_text_paint.Time().value());
+  }
+
+  const page_load_metrics::ContentfulPaintTimingInfo&
+      main_frame_largest_contentful_paint =
+          largest_contentful_paint_handler_.MainFrameLargestContentfulPaint();
+  if (!main_frame_largest_contentful_paint.IsEmpty() &&
+      WasStartedInForegroundOptionalEventInForeground(
+          main_frame_largest_contentful_paint.Time(), info)) {
+    PAGE_LOAD_HISTOGRAM(internal::kHistogramLargestContentfulPaintMainFrame,
+                        main_frame_largest_contentful_paint.Time().value());
     UMA_HISTOGRAM_ENUMERATION(
-        internal::kHistogramLargestContentfulPaintContentType, paint.Type());
+        internal::kHistogramLargestContentfulPaintMainFrameContentType,
+        main_frame_largest_contentful_paint.Type());
+  }
+
+  const page_load_metrics::ContentfulPaintTimingInfo&
+      all_frames_largest_contentful_paint =
+          largest_contentful_paint_handler_.MergeMainFrameAndSubframes();
+  if (!all_frames_largest_contentful_paint.IsEmpty() &&
+      WasStartedInForegroundOptionalEventInForeground(
+          all_frames_largest_contentful_paint.Time(), info)) {
+    PAGE_LOAD_HISTOGRAM(internal::kHistogramLargestContentfulPaint,
+                        all_frames_largest_contentful_paint.Time().value());
+    UMA_HISTOGRAM_ENUMERATION(
+        internal::kHistogramLargestContentfulPaintContentType,
+        all_frames_largest_contentful_paint.Type());
   }
 
   if (main_frame_timing.paint_timing->first_paint &&
diff --git a/chrome/browser/page_load_metrics/observers/largest_contentful_paint_handler.h b/chrome/browser/page_load_metrics/observers/largest_contentful_paint_handler.h
index 59f205f6..0bc3200 100644
--- a/chrome/browser/page_load_metrics/observers/largest_contentful_paint_handler.h
+++ b/chrome/browser/page_load_metrics/observers/largest_contentful_paint_handler.h
@@ -78,6 +78,21 @@
     return main_frame_tree_node_id_.value();
   }
 
+  // We merge the candidates from text side and image side to get the largest
+  // candidate across both types of content.
+  const ContentfulPaintTimingInfo& MainFrameLargestContentfulPaint() {
+    return main_frame_contentful_paint_.MergeTextAndImageTiming();
+  }
+  const ContentfulPaintTimingInfo& SubframesLargestContentfulPaint() {
+    return subframe_contentful_paint_.MergeTextAndImageTiming();
+  }
+  const ContentfulPaintTimingInfo& MainFrameLargestImagePaint() {
+    return main_frame_contentful_paint_.Image();
+  }
+  const ContentfulPaintTimingInfo& MainFrameLargestTextPaint() {
+    return main_frame_contentful_paint_.Text();
+  }
+
   // We merge the candidates from main frame and subframe to get the largest
   // candidate across all frames.
   const ContentfulPaintTimingInfo& MergeMainFrameAndSubframes();
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
index 8666d1f1..0fd7666 100644
--- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
@@ -298,35 +298,41 @@
     builder.SetExperimental_PaintTiming_NavigationToFirstMeaningfulPaint(
         timing.paint_timing->first_meaningful_paint.value().InMilliseconds());
   }
-  if (timing.paint_timing->largest_image_paint.has_value() &&
+  const page_load_metrics::ContentfulPaintTimingInfo&
+      main_frame_largest_image_paint =
+          largest_contentful_paint_handler_.MainFrameLargestImagePaint();
+  if (!main_frame_largest_image_paint.IsEmpty() &&
       WasStartedInForegroundOptionalEventInForeground(
-          timing.paint_timing->largest_image_paint, info)) {
+          main_frame_largest_image_paint.Time(), info)) {
     builder.SetExperimental_PaintTiming_NavigationToLargestImagePaint(
         timing.paint_timing->largest_image_paint.value().InMilliseconds());
   }
-  if (timing.paint_timing->largest_text_paint.has_value() &&
+  const page_load_metrics::ContentfulPaintTimingInfo&
+      main_frame_largest_text_paint =
+          largest_contentful_paint_handler_.MainFrameLargestTextPaint();
+  if (!main_frame_largest_text_paint.IsEmpty() &&
       WasStartedInForegroundOptionalEventInForeground(
-          timing.paint_timing->largest_text_paint, info)) {
+          main_frame_largest_text_paint.Time(), info)) {
     builder.SetExperimental_PaintTiming_NavigationToLargestTextPaint(
         timing.paint_timing->largest_text_paint.value().InMilliseconds());
   }
-  base::Optional<base::TimeDelta> largest_content_paint_time;
-  uint64_t largest_content_paint_size;
-  PageLoadMetricsObserver::LargestContentType largest_content_type;
-  if (AssignTimeAndSizeForLargestContentfulPaint(
-          timing.paint_timing, &largest_content_paint_time,
-          &largest_content_paint_size, &largest_content_type) &&
+  const page_load_metrics::ContentfulPaintTimingInfo&
+      main_frame_largest_contentful_paint =
+          largest_contentful_paint_handler_.MainFrameLargestContentfulPaint();
+  if (!main_frame_largest_contentful_paint.IsEmpty() &&
       WasStartedInForegroundOptionalEventInForeground(
-          largest_content_paint_time, info)) {
+          main_frame_largest_contentful_paint.Time(), info)) {
     builder.SetPaintTiming_NavigationToLargestContentfulPaint_MainFrame(
-        largest_content_paint_time.value().InMilliseconds());
+        main_frame_largest_contentful_paint.Time().value().InMilliseconds());
   }
-  const page_load_metrics::ContentfulPaintTimingInfo& paint =
-      largest_contentful_paint_handler_.MergeMainFrameAndSubframes();
-  if (!paint.IsEmpty() &&
-      WasStartedInForegroundOptionalEventInForeground(paint.Time(), info)) {
+  const page_load_metrics::ContentfulPaintTimingInfo&
+      all_frames_largest_contentful_paint =
+          largest_contentful_paint_handler_.MergeMainFrameAndSubframes();
+  if (!all_frames_largest_contentful_paint.IsEmpty() &&
+      WasStartedInForegroundOptionalEventInForeground(
+          all_frames_largest_contentful_paint.Time(), info)) {
     builder.SetPaintTiming_NavigationToLargestContentfulPaint(
-        paint.Time().value().InMilliseconds());
+        all_frames_largest_contentful_paint.Time().value().InMilliseconds());
   }
   if (timing.interactive_timing->interactive) {
     base::TimeDelta time_to_interactive =
diff --git a/chrome/browser/payments/DEPS b/chrome/browser/payments/DEPS
index be3cab72..d8ca073a 100644
--- a/chrome/browser/payments/DEPS
+++ b/chrome/browser/payments/DEPS
@@ -1,3 +1,11 @@
 include_rules = [
  "+third_party/libaddressinput",
 ]
+
+specific_include_rules = {
+  "chrome_payment_request_delegate\.cc": [
+    # This delegate is hardcoded to construct a Views dialog right now, since it
+    # is only used on Views platforms.
+    "+chrome/browser/ui/views",
+  ],
+}
diff --git a/chrome/browser/payments/chrome_payment_request_delegate.cc b/chrome/browser/payments/chrome_payment_request_delegate.cc
index 0ea908a..e3c4938d 100644
--- a/chrome/browser/payments/chrome_payment_request_delegate.cc
+++ b/chrome/browser/payments/chrome_payment_request_delegate.cc
@@ -18,9 +18,9 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/views/payments/payment_request_dialog_view.h"
 #include "chrome/browser/web_data_service_factory.h"
 #include "components/autofill/core/browser/address_normalizer_impl.h"
 #include "components/autofill/core/browser/geo/region_data_loader_impl.h"
@@ -64,7 +64,7 @@
 
 void ChromePaymentRequestDelegate::ShowDialog(PaymentRequest* request) {
   DCHECK_EQ(nullptr, shown_dialog_);
-  shown_dialog_ = chrome::CreatePaymentRequestDialog(request);
+  shown_dialog_ = new payments::PaymentRequestDialogView(request, nullptr);
   shown_dialog_->ShowDialog();
 }
 
diff --git a/chrome/browser/predictors/loading_predictor_browsertest.cc b/chrome/browser/predictors/loading_predictor_browsertest.cc
index a1c33559..c99ec11 100644
--- a/chrome/browser/predictors/loading_predictor_browsertest.cc
+++ b/chrome/browser/predictors/loading_predictor_browsertest.cc
@@ -940,7 +940,8 @@
     request->url = url;
     content::SimpleURLLoaderTestHelper simple_loader_helper;
     url::Origin origin = url::Origin::Create(url);
-    request->trusted_network_isolation_key =
+    request->trusted_params = network::ResourceRequest::TrustedParams();
+    request->trusted_params->network_isolation_key =
         net::NetworkIsolationKey(origin, origin);
     std::unique_ptr<network::SimpleURLLoader> simple_loader =
         network::SimpleURLLoader::Create(std::move(request),
diff --git a/chrome/browser/resource_coordinator/local_site_characteristics_data_store.cc b/chrome/browser/resource_coordinator/local_site_characteristics_data_store.cc
index 032070c33..423cc90 100644
--- a/chrome/browser/resource_coordinator/local_site_characteristics_data_store.cc
+++ b/chrome/browser/resource_coordinator/local_site_characteristics_data_store.cc
@@ -164,11 +164,8 @@
   } else {
     std::vector<url::Origin> origins_to_remove;
 
-    // CHECK_EQ instead of DCHECK_EQ to determine whether
-    // https://crbug.com/966059 still happens in production.
-    // TODO(fdoray): Remove once https://crbug.com/966059 is fixed.
-    CHECK_EQ(deletion_info.deleted_urls_origin_map().size(),
-             CountOriginsInURLRows(deletion_info.deleted_rows()));
+    DCHECK_EQ(deletion_info.deleted_urls_origin_map().size(),
+              CountOriginsInURLRows(deletion_info.deleted_rows()));
     for (const auto& it : deletion_info.deleted_urls_origin_map()) {
       const url::Origin origin = url::Origin::Create(it.first);
       const int remaining_visits_in_history = it.second.first;
diff --git a/chrome/browser/resources/chromeos/arc_support/background.js b/chrome/browser/resources/chromeos/arc_support/background.js
index 44e3c44..df88dbf 100644
--- a/chrome/browser/resources/chromeos/arc_support/background.js
+++ b/chrome/browser/resources/chromeos/arc_support/background.js
@@ -972,10 +972,6 @@
   if (outerHeight > screen.availHeight) {
     outerHeight = screen.availHeight;
   }
-  if (appWindow.outerBounds.width == outerWidth &&
-      appWindow.outerBounds.height == outerHeight) {
-    return;
-  }
 
   appWindow.outerBounds.width = outerWidth;
   appWindow.outerBounds.height = outerHeight;
diff --git a/chrome/browser/resources/local_ntp/customize.js b/chrome/browser/resources/local_ntp/customize.js
index 33b1463..76e7f42 100644
--- a/chrome/browser/resources/local_ntp/customize.js
+++ b/chrome/browser/resources/local_ntp/customize.js
@@ -304,6 +304,13 @@
  */
 customize.colorsMenuLoaded = false;
 
+
+/**
+ * Custom color picked in hex format.
+ * @type {string}
+ */
+customize.customColorPicked = '#000000';
+
 /**
  * Sets the visibility of the settings menu and individual options depending on
  * their respective features.
@@ -2259,6 +2266,7 @@
   // Configure custom color picker.
   if (configData.chromeColorsCustomColorPicker) {
     $(customize.IDS.COLOR_PICKER_TILE).onclick = function(event) {
+      $(customize.IDS.COLOR_PICKER).value = customize.customColorPicked;
       $(customize.IDS.COLOR_PICKER).click();
     };
     $(customize.IDS.COLOR_PICKER_TILE).onkeydown =
@@ -2321,8 +2329,7 @@
     tile = $(customize.IDS.COLOR_PICKER_TILE);
 
     // Update color picker tile colors.
-    $(customize.IDS.COLOR_PICKER).value =
-        colorArrayToHex(themeInfo.colorPicked);
+    customize.customColorPicked = colorArrayToHex(themeInfo.colorPicked);
     $(customize.IDS.COLORS_MENU)
         .style.setProperty(
             '--custom-color-border', colorArrayToHex(themeInfo.colorDark));
diff --git a/chrome/browser/resources/settings/people_page/people_page.html b/chrome/browser/resources/settings/people_page/people_page.html
index 8be24f5..cea9ce9 100644
--- a/chrome/browser/resources/settings/people_page/people_page.html
+++ b/chrome/browser/resources/settings/people_page/people_page.html
@@ -28,6 +28,7 @@
 
 <if expr="chromeos">
 <link rel="import" href="account_manager.html">
+<link rel="import" href="account_manager_browser_proxy.html">
 <link rel="import" href="change_picture.html">
 <link rel="import" href="chrome://resources/cr_elements/chromeos/cr_picture/cr_png_behavior.html">
 <link rel="import" href="fingerprint_list.html">
diff --git a/chrome/browser/resources/settings/people_page/people_page.js b/chrome/browser/resources/settings/people_page/people_page.js
index c7481d27..defd0c7 100644
--- a/chrome/browser/resources/settings/people_page/people_page.js
+++ b/chrome/browser/resources/settings/people_page/people_page.js
@@ -233,10 +233,24 @@
 
   /** @override */
   attached: function() {
-    const profileInfoProxy = settings.ProfileInfoBrowserProxyImpl.getInstance();
-    profileInfoProxy.getProfileInfo().then(this.handleProfileInfo_.bind(this));
-    this.addWebUIListener(
-        'profile-info-changed', this.handleProfileInfo_.bind(this));
+    let useProfileNameAndIcon = true;
+    // <if expr="chromeos">
+    if (!loadTimeData.getBoolean('showOSSettings') &&
+        this.isAccountManagerEnabled_) {
+      // If this is SplitSettings and we have the Google Account manager,
+      // prefer the GAIA name and icon.
+      useProfileNameAndIcon = false;
+      this.addWebUIListener(
+          'accounts-changed', this.updateAccounts_.bind(this));
+      this.updateAccounts_();
+    }
+    // </if>
+    if (useProfileNameAndIcon) {
+      settings.ProfileInfoBrowserProxyImpl.getInstance().getProfileInfo().then(
+          this.handleProfileInfo_.bind(this));
+      this.addWebUIListener(
+          'profile-info-changed', this.handleProfileInfo_.bind(this));
+    }
 
     this.syncBrowserProxy_ = settings.SyncBrowserProxyImpl.getInstance();
     this.syncBrowserProxy_.getSyncStatus().then(
@@ -318,6 +332,27 @@
     this.profileIconUrl_ = info.iconUrl;
   },
 
+  // <if expr="chromeos">
+  /**
+   * @private
+   * @suppress {checkTypes} The types only exists in Chrome OS builds, but
+   * Closure doesn't understand the <if> above.
+   */
+  updateAccounts_: async function() {
+    const /** @type {!Array<{settings.Account}>} */ accounts =
+        await settings.AccountManagerBrowserProxyImpl.getInstance()
+            .getAccounts();
+    // The user might not have any GAIA accounts (e.g. guest mode, Kerberos,
+    // Active Directory). In these cases the profile row is hidden, so there's
+    // nothing to do.
+    if (accounts.length == 0) {
+      return;
+    }
+    this.profileName_ = accounts[0].fullName;
+    this.profileIconUrl_ = accounts[0].pic;
+  },
+  // </if>
+
   /**
    * Handler for when the sync state is pushed from the browser.
    * @param {?settings.SyncStatus} syncStatus
diff --git a/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer.cc b/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer.cc
index 3970f79..16b7daf 100644
--- a/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer.cc
+++ b/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer.cc
@@ -24,8 +24,6 @@
 #include "ui/views/controls/menu/menu_config.h"
 #include "url/url_constants.h"
 
-using SharingMessage = chrome_browser_sharing::SharingMessage;
-
 ClickToCallContextMenuObserver::SubMenuDelegate::SubMenuDelegate(
     ClickToCallContextMenuObserver* parent)
     : parent_(parent) {}
diff --git a/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer.h b/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer.h
index 968e3235..e48c96e 100644
--- a/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer.h
+++ b/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer.h
@@ -11,7 +11,6 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
-#include "base/memory/weak_ptr.h"
 #include "base/optional.h"
 #include "chrome/browser/sharing/sharing_device_info.h"
 #include "components/renderer_context_menu/render_view_context_menu_observer.h"
@@ -26,9 +25,7 @@
 
 class SharingService;
 
-class ClickToCallContextMenuObserver
-    : public RenderViewContextMenuObserver,
-      public base::SupportsWeakPtr<ClickToCallContextMenuObserver> {
+class ClickToCallContextMenuObserver : public RenderViewContextMenuObserver {
  public:
   class SubMenuDelegate : public ui::SimpleMenuModel::Delegate {
    public:
diff --git a/chrome/browser/sharing/shared_clipboard/shared_clipboard_context_menu_observer.cc b/chrome/browser/sharing/shared_clipboard/shared_clipboard_context_menu_observer.cc
new file mode 100644
index 0000000..d6b1cf6
--- /dev/null
+++ b/chrome/browser/sharing/shared_clipboard/shared_clipboard_context_menu_observer.cc
@@ -0,0 +1,158 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/sharing/shared_clipboard/shared_clipboard_context_menu_observer.h"
+
+#include "base/bind.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/renderer_context_menu/render_view_context_menu.h"
+#include "chrome/browser/sharing/shared_clipboard/feature_flags.h"
+#include "chrome/browser/sharing/shared_clipboard/shared_clipboard_ui_controller.h"
+#include "chrome/browser/sharing/sharing_constants.h"
+#include "chrome/browser/sharing/sharing_metrics.h"
+#include "chrome/browser/sharing/sharing_service.h"
+#include "chrome/browser/sharing/sharing_service_factory.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/vector_icons/vector_icons.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/color_palette.h"
+#include "ui/gfx/paint_vector_icon.h"
+#include "ui/native_theme/native_theme.h"
+#include "ui/resources/grit/ui_resources.h"
+#include "ui/views/controls/menu/menu_config.h"
+
+SharedClipboardContextMenuObserver::SubMenuDelegate::SubMenuDelegate(
+    SharedClipboardContextMenuObserver* parent)
+    : parent_(parent) {}
+
+SharedClipboardContextMenuObserver::SubMenuDelegate::~SubMenuDelegate() =
+    default;
+
+bool SharedClipboardContextMenuObserver::SubMenuDelegate::IsCommandIdEnabled(
+    int command_id) const {
+  // All supported commands are enabled in sub menu.
+  return true;
+}
+
+void SharedClipboardContextMenuObserver::SubMenuDelegate::ExecuteCommand(
+    int command_id,
+    int event_flags) {
+  if (command_id < kSubMenuFirstDeviceCommandId ||
+      command_id > kSubMenuLastDeviceCommandId)
+    return;
+  int device_index = command_id - kSubMenuFirstDeviceCommandId;
+  parent_->SendSharedClipboardMessage(device_index);
+}
+
+SharedClipboardContextMenuObserver::SharedClipboardContextMenuObserver(
+    RenderViewContextMenuProxy* proxy)
+    : proxy_(proxy),
+      sharing_service_(SharingServiceFactory::GetForBrowserContext(
+          proxy_->GetBrowserContext())) {}
+
+SharedClipboardContextMenuObserver::~SharedClipboardContextMenuObserver() =
+    default;
+
+void SharedClipboardContextMenuObserver::InitMenu(
+    const content::ContextMenuParams& params) {
+  text_ = params.selection_text;
+  devices_ = sharing_service_->GetDeviceCandidates(
+      static_cast<int>(SharingDeviceCapability::kNone));
+  // TODO(yasmo): add logging
+
+  if (devices_.empty())
+    return;
+
+  proxy_->AddSeparator();
+  if (devices_.size() == 1) {
+#if defined(OS_MACOSX)
+    proxy_->AddMenuItem(
+        IDC_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_SINGLE_DEVICE,
+        l10n_util::GetStringFUTF16(
+            IDS_CONTEXT_MENU_SEND_TAB_TO_SELF_SINGLE_TARGET,
+            devices_[0].human_readable_name()));
+#else
+    proxy_->AddMenuItemWithIcon(
+        IDC_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_SINGLE_DEVICE,
+        l10n_util::GetStringFUTF16(
+            IDS_CONTEXT_MENU_SEND_TAB_TO_SELF_SINGLE_TARGET,
+            devices_[0].human_readable_name()),
+        GetContextMenuIcon());
+#endif
+  } else {
+    BuildSubMenu();
+#if defined(OS_MACOSX)
+    proxy_->AddSubMenu(
+        IDC_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_MULTIPLE_DEVICES,
+        l10n_util::GetStringUTF16(IDS_CONTEXT_MENU_SEND_TAB_TO_SELF),
+        sub_menu_model_.get());
+#else
+    proxy_->AddSubMenuWithStringIdAndIcon(
+        IDC_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_MULTIPLE_DEVICES,
+        IDS_CONTEXT_MENU_SEND_TAB_TO_SELF, sub_menu_model_.get(),
+        GetContextMenuIcon());
+#endif
+  }
+}
+
+void SharedClipboardContextMenuObserver::BuildSubMenu() {
+  sub_menu_model_ = std::make_unique<ui::SimpleMenuModel>(&sub_menu_delegate_);
+
+  int command_id = kSubMenuFirstDeviceCommandId;
+  for (const auto& device : devices_) {
+    if (command_id > kSubMenuLastDeviceCommandId)
+      break;
+    sub_menu_model_->AddItem(command_id++, device.human_readable_name());
+  }
+}
+
+bool SharedClipboardContextMenuObserver::IsCommandIdSupported(int command_id) {
+  if (devices_.empty())
+    return false;
+
+  if (devices_.size() == 1) {
+    return command_id ==
+           IDC_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_SINGLE_DEVICE;
+  } else {
+    return command_id ==
+           IDC_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_MULTIPLE_DEVICES;
+  }
+}
+
+bool SharedClipboardContextMenuObserver::IsCommandIdEnabled(int command_id) {
+  // All supported commands are enabled.
+  return true;
+}
+
+void SharedClipboardContextMenuObserver::ExecuteCommand(int command_id) {
+  if (command_id ==
+      IDC_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_SINGLE_DEVICE) {
+    DCHECK(devices_.size() == 1);
+    SendSharedClipboardMessage(0);
+  }
+}
+
+void SharedClipboardContextMenuObserver::SendSharedClipboardMessage(
+    int chosen_device_index) {
+  if (chosen_device_index >= static_cast<int>(devices_.size()))
+    return;
+
+  // TODO(yasmo): Add logging
+
+  SharedClipboardUiController::DeviceSelected(proxy_->GetWebContents(), text_,
+                                              devices_[chosen_device_index]);
+}
+
+gfx::ImageSkia SharedClipboardContextMenuObserver::GetContextMenuIcon() const {
+  const ui::NativeTheme* native_theme =
+      ui::NativeTheme::GetInstanceForNativeUi();
+  bool is_dark = native_theme && native_theme->ShouldUseDarkColors();
+  int resource_id = is_dark ? IDR_SEND_TAB_TO_SELF_ICON_DARK
+                            : IDR_SEND_TAB_TO_SELF_ICON_LIGHT;
+  return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
+      resource_id);
+}
diff --git a/chrome/browser/sharing/shared_clipboard/shared_clipboard_context_menu_observer.h b/chrome/browser/sharing/shared_clipboard/shared_clipboard_context_menu_observer.h
new file mode 100644
index 0000000..99a3cd0
--- /dev/null
+++ b/chrome/browser/sharing/shared_clipboard/shared_clipboard_context_menu_observer.h
@@ -0,0 +1,83 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SHARING_SHARED_CLIPBOARD_SHARED_CLIPBOARD_CONTEXT_MENU_OBSERVER_H_
+#define CHROME_BROWSER_SHARING_SHARED_CLIPBOARD_SHARED_CLIPBOARD_CONTEXT_MENU_OBSERVER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/optional.h"
+#include "chrome/browser/sharing/sharing_device_info.h"
+#include "components/renderer_context_menu/render_view_context_menu_observer.h"
+#include "ui/base/models/simple_menu_model.h"
+
+namespace gfx {
+class ImageSkia;
+}
+
+class RenderViewContextMenuProxy;
+
+class SharingService;
+
+class SharedClipboardContextMenuObserver
+    : public RenderViewContextMenuObserver {
+ public:
+  class SubMenuDelegate : public ui::SimpleMenuModel::Delegate {
+   public:
+    explicit SubMenuDelegate(SharedClipboardContextMenuObserver* parent);
+    ~SubMenuDelegate() override;
+
+    bool IsCommandIdEnabled(int command_id) const override;
+    void ExecuteCommand(int command_id, int event_flags) override;
+
+   private:
+    SharedClipboardContextMenuObserver* const parent_;
+
+    DISALLOW_COPY_AND_ASSIGN(SubMenuDelegate);
+  };
+
+  explicit SharedClipboardContextMenuObserver(
+      RenderViewContextMenuProxy* proxy);
+  ~SharedClipboardContextMenuObserver() override;
+
+  // RenderViewContextMenuObserver implementation.
+  void InitMenu(const content::ContextMenuParams& params) override;
+  bool IsCommandIdSupported(int command_id) override;
+  bool IsCommandIdEnabled(int command_id) override;
+  void ExecuteCommand(int command_id) override;
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(SharedClipboardContextMenuObserverTest,
+                           SingleDevice_ShowMenu);
+  FRIEND_TEST_ALL_PREFIXES(SharedClipboardContextMenuObserverTest,
+                           MultipleDevices_ShowMenu);
+  FRIEND_TEST_ALL_PREFIXES(SharedClipboardContextMenuObserverTest,
+                           MultipleDevices_MoreThanMax_ShowMenu);
+
+  void BuildSubMenu();
+
+  void SendSharedClipboardMessage(int chosen_device_index);
+
+  gfx::ImageSkia GetContextMenuIcon() const;
+
+  RenderViewContextMenuProxy* proxy_ = nullptr;
+
+  SharingService* sharing_service_ = nullptr;
+
+  SubMenuDelegate sub_menu_delegate_{this};
+
+  base::string16 text_;
+
+  std::vector<SharingDeviceInfo> devices_;
+
+  std::unique_ptr<ui::SimpleMenuModel> sub_menu_model_;
+
+  DISALLOW_COPY_AND_ASSIGN(SharedClipboardContextMenuObserver);
+};
+
+#endif  // CHROME_BROWSER_SHARING_SHARED_CLIPBOARD_SHARED_CLIPBOARD_CONTEXT_MENU_OBSERVER_H_
diff --git a/chrome/browser/sharing/shared_clipboard/shared_clipboard_context_menu_observer_unittest.cc b/chrome/browser/sharing/shared_clipboard/shared_clipboard_context_menu_observer_unittest.cc
new file mode 100644
index 0000000..b882ecb
--- /dev/null
+++ b/chrome/browser/sharing/shared_clipboard/shared_clipboard_context_menu_observer_unittest.cc
@@ -0,0 +1,266 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/sharing/shared_clipboard/shared_clipboard_context_menu_observer.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/renderer_context_menu/mock_render_view_context_menu.h"
+#include "chrome/browser/sharing/shared_clipboard/feature_flags.h"
+#include "chrome/browser/sharing/sharing_constants.h"
+#include "chrome/browser/sharing/sharing_device_info.h"
+#include "chrome/browser/sharing/sharing_fcm_handler.h"
+#include "chrome/browser/sharing/sharing_fcm_sender.h"
+#include "chrome/browser/sharing/sharing_service.h"
+#include "chrome/browser/sharing/sharing_service_factory.h"
+#include "chrome/browser/sharing/sharing_sync_preference.h"
+#include "chrome/browser/sharing/vapid_key_manager.h"
+#include "content/public/common/context_menu_params.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"
+
+using ::testing::_;
+using ::testing::ByMove;
+using ::testing::Eq;
+using ::testing::NiceMock;
+using ::testing::Return;
+
+using SharingMessage = chrome_browser_sharing::SharingMessage;
+
+namespace {
+
+const char kText[] = "Some random text to be copied.";
+
+constexpr int kSeparatorCommandId = -1;
+
+class MockSharingService : public SharingService {
+ public:
+  explicit MockSharingService(std::unique_ptr<SharingFCMHandler> fcm_handler)
+      : SharingService(/* sync_prefs= */ nullptr,
+                       /* vapid_key_manager= */ nullptr,
+                       /* sharing_device_registration= */ nullptr,
+                       /* fcm_sender= */ nullptr,
+                       std::move(fcm_handler),
+                       /* gcm_driver= */ nullptr,
+                       /* device_info_tracker= */ nullptr,
+                       /* local_device_info_provider= */ nullptr,
+                       /* sync_service */ nullptr) {}
+
+  ~MockSharingService() override = default;
+
+  MOCK_CONST_METHOD1(GetDeviceCandidates,
+                     std::vector<SharingDeviceInfo>(int required_capabilities));
+
+  MOCK_METHOD4(SendMessageToDevice,
+               void(const std::string& device_guid,
+                    base::TimeDelta time_to_live,
+                    SharingMessage message,
+                    SharingService::SendMessageCallback callback));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockSharingService);
+};
+
+class SharedClipboardContextMenuObserverTest : public testing::Test {
+ public:
+  SharedClipboardContextMenuObserverTest() = default;
+
+  ~SharedClipboardContextMenuObserverTest() override = default;
+
+  void SetUp() override {
+    web_contents_ = content::WebContentsTester::CreateTestWebContents(
+        menu_.GetBrowserContext(), nullptr);
+    menu_.set_web_contents(web_contents_.get());
+    SharingServiceFactory::GetInstance()->SetTestingFactory(
+        menu_.GetBrowserContext(),
+        base::BindRepeating([](content::BrowserContext* context)
+                                -> std::unique_ptr<KeyedService> {
+          return std::make_unique<NiceMock<MockSharingService>>(
+              std::make_unique<SharingFCMHandler>(nullptr, nullptr));
+        }));
+    observer_ = std::make_unique<SharedClipboardContextMenuObserver>(&menu_);
+    menu_.SetObserver(observer_.get());
+  }
+
+  void InitMenu(const base::string16 text) {
+    content::ContextMenuParams params;
+    params.selection_text = text;
+    observer_->InitMenu(params);
+    sharing_message.mutable_shared_clipboard_message()->set_text(
+        base::UTF16ToUTF8(text));
+  }
+
+  std::vector<SharingDeviceInfo> CreateMockDevices(int count) {
+    std::vector<SharingDeviceInfo> devices;
+    for (int i = 0; i < count; i++) {
+      devices.emplace_back(
+          base::StrCat({"guid", base::NumberToString(i)}),
+          base::UTF8ToUTF16(base::StrCat({"name", base::NumberToString(i)})),
+          sync_pb::SyncEnums::TYPE_PHONE, base::Time::Now(),
+          static_cast<int>(SharingDeviceCapability::kNone));
+    }
+    return devices;
+  }
+
+ protected:
+  NiceMock<MockSharingService>* service() {
+    return static_cast<NiceMock<MockSharingService>*>(
+        SharingServiceFactory::GetForBrowserContext(menu_.GetBrowserContext()));
+  }
+
+  content::TestBrowserThreadBundle thread_bundle_;
+  MockRenderViewContextMenu menu_{/* incognito= */ false};
+  std::unique_ptr<content::WebContents> web_contents_;
+  std::unique_ptr<SharedClipboardContextMenuObserver> observer_;
+  SharingMessage sharing_message;
+
+  DISALLOW_COPY_AND_ASSIGN(SharedClipboardContextMenuObserverTest);
+};
+
+}  // namespace
+
+MATCHER_P(ProtoEquals, message, "") {
+  std::string expected_serialized, actual_serialized;
+  message.SerializeToString(&expected_serialized);
+  arg.SerializeToString(&actual_serialized);
+  return expected_serialized == actual_serialized;
+}
+
+TEST_F(SharedClipboardContextMenuObserverTest, NoDevices_DoNotShowMenu) {
+  auto devices = CreateMockDevices(0);
+
+  EXPECT_CALL(*service(), GetDeviceCandidates(_))
+      .WillOnce(Return(ByMove(std::move(devices))));
+
+  InitMenu(base::ASCIIToUTF16(kText));
+
+  EXPECT_EQ(0U, menu_.GetMenuSize());
+}
+
+TEST_F(SharedClipboardContextMenuObserverTest, SingleDevice_ShowMenu) {
+  auto devices = CreateMockDevices(1);
+  auto guid = devices[0].guid();
+
+  EXPECT_CALL(*service(), GetDeviceCandidates(_))
+      .WillOnce(Return(ByMove(std::move(devices))));
+
+  InitMenu(base::ASCIIToUTF16(kText));
+
+  // The first item is a separator and the second item is the device.
+  EXPECT_EQ(2U, menu_.GetMenuSize());
+
+  // Assert item ordering.
+  MockRenderViewContextMenu::MockMenuItem item;
+  ASSERT_TRUE(menu_.GetMenuItem(0, &item));
+  EXPECT_EQ(kSeparatorCommandId, item.command_id);
+
+  ASSERT_TRUE(menu_.GetMenuItem(1, &item));
+  EXPECT_EQ(IDC_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_SINGLE_DEVICE,
+            item.command_id);
+
+  // Emulate click on the device.
+  EXPECT_CALL(*service(), SendMessageToDevice(Eq(guid), Eq(kSharingMessageTTL),
+                                              ProtoEquals(sharing_message), _))
+      .Times(1);
+  menu_.ExecuteCommand(
+      IDC_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_SINGLE_DEVICE, 0);
+}
+
+TEST_F(SharedClipboardContextMenuObserverTest, MultipleDevices_ShowMenu) {
+  constexpr int device_count = 3;
+  auto devices = CreateMockDevices(device_count);
+  std::vector<std::string> guids;
+  for (auto& device : devices)
+    guids.push_back(device.guid());
+
+  EXPECT_CALL(*service(), GetDeviceCandidates(_))
+      .WillOnce(Return(ByMove(std::move(devices))));
+
+  InitMenu(base::ASCIIToUTF16(kText));
+
+  EXPECT_EQ(device_count + 2U, menu_.GetMenuSize());
+
+  // Assert item ordering.
+  MockRenderViewContextMenu::MockMenuItem item;
+  ASSERT_TRUE(menu_.GetMenuItem(0, &item));
+  EXPECT_EQ(kSeparatorCommandId, item.command_id);
+
+  ASSERT_TRUE(menu_.GetMenuItem(1, &item));
+  EXPECT_EQ(IDC_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_MULTIPLE_DEVICES,
+            item.command_id);
+
+  for (int i = 0; i < device_count; i++) {
+    ASSERT_TRUE(menu_.GetMenuItem(i + 2, &item));
+    EXPECT_EQ(kSubMenuFirstDeviceCommandId + i, item.command_id);
+  }
+
+  // Emulate clicks on all commands to check for commands with no device
+  // assigned.
+  for (int i = 0; i < kMaxDevicesShown; i++) {
+    if (i < device_count) {
+      EXPECT_CALL(*service(),
+                  SendMessageToDevice(Eq(guids[i]), Eq(kSharingMessageTTL),
+                                      ProtoEquals(sharing_message), _))
+          .Times(1);
+    } else {
+      EXPECT_CALL(*service(), SendMessageToDevice(_, _, _, _)).Times(0);
+    }
+    observer_->sub_menu_delegate_.ExecuteCommand(
+        kSubMenuFirstDeviceCommandId + i, 0);
+  }
+}
+
+TEST_F(SharedClipboardContextMenuObserverTest,
+       MultipleDevices_MoreThanMax_ShowMenu) {
+  int device_count = kMaxDevicesShown + 1;
+  auto devices = CreateMockDevices(device_count);
+  std::vector<std::string> guids;
+  for (auto& device : devices)
+    guids.push_back(device.guid());
+
+  EXPECT_CALL(*service(), GetDeviceCandidates(_))
+      .WillOnce(Return(ByMove(std::move(devices))));
+
+  InitMenu(base::ASCIIToUTF16(kText));
+
+  EXPECT_EQ(kMaxDevicesShown + 2U, menu_.GetMenuSize());
+
+  // Assert item ordering.
+  MockRenderViewContextMenu::MockMenuItem item;
+  ASSERT_TRUE(menu_.GetMenuItem(0, &item));
+  EXPECT_EQ(kSeparatorCommandId, item.command_id);
+
+  ASSERT_TRUE(menu_.GetMenuItem(1, &item));
+  EXPECT_EQ(IDC_CONTENT_CONTEXT_SHARING_SHARED_CLIPBOARD_MULTIPLE_DEVICES,
+            item.command_id);
+
+  for (int i = 0; i < kMaxDevicesShown; i++) {
+    ASSERT_TRUE(menu_.GetMenuItem(i + 2, &item));
+    EXPECT_EQ(kSubMenuFirstDeviceCommandId + i, item.command_id);
+  }
+
+  // Emulate clicks on all device commands to check for commands outside valid
+  // range too.
+  for (int i = 0; i < device_count; i++) {
+    if (i < kMaxDevicesShown) {
+      EXPECT_CALL(*service(),
+                  SendMessageToDevice(Eq(guids[i]), Eq(kSharingMessageTTL),
+                                      ProtoEquals(sharing_message), _))
+          .Times(1);
+    } else {
+      EXPECT_CALL(*service(), SendMessageToDevice(_, _, _, _)).Times(0);
+    }
+    observer_->sub_menu_delegate_.ExecuteCommand(
+        kSubMenuFirstDeviceCommandId + i, 0);
+  }
+}
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 6e2a3906..2c53465 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2775,6 +2775,8 @@
       "views/infobars/infobar_container_view.h",
       "views/infobars/infobar_view.cc",
       "views/infobars/infobar_view.h",
+      "views/layout/interpolating_layout_manager.cc",
+      "views/layout/interpolating_layout_manager.h",
       "views/load_complete_listener.cc",
       "views/load_complete_listener.h",
       "views/location_bar/content_setting_image_view.cc",
diff --git a/chrome/browser/ui/android/sms/sms_dialog_android.cc b/chrome/browser/ui/android/sms/sms_dialog_android.cc
index 70c0ae07..6f70378 100644
--- a/chrome/browser/ui/android/sms/sms_dialog_android.cc
+++ b/chrome/browser/ui/android/sms/sms_dialog_android.cc
@@ -32,10 +32,8 @@
 }
 
 void SmsDialogAndroid::Open(content::RenderFrameHost* host,
-                            base::OnceClosure on_confirm,
-                            base::OnceClosure on_cancel) {
-  on_confirm_ = std::move(on_confirm);
-  on_cancel_ = std::move(on_cancel);
+                            EventHandler handler) {
+  handler_ = std::move(handler);
 
   content::WebContents* web_contents =
       content::WebContents::FromRenderFrameHost(host);
@@ -55,10 +53,10 @@
   Java_SmsReceiverDialog_smsReceived(AttachCurrentThread(), java_dialog_);
 }
 
-void SmsDialogAndroid::OnConfirm(JNIEnv* env) {
-  std::move(on_confirm_).Run();
+void SmsDialogAndroid::SmsTimeout() {
+  Java_SmsReceiverDialog_smsTimeout(AttachCurrentThread(), java_dialog_);
 }
 
-void SmsDialogAndroid::OnCancel(JNIEnv* env) {
-  std::move(on_cancel_).Run();
+void SmsDialogAndroid::OnEvent(JNIEnv* env, jint event_type) {
+  std::move(handler_).Run(static_cast<Event>(event_type));
 }
diff --git a/chrome/browser/ui/android/sms/sms_dialog_android.h b/chrome/browser/ui/android/sms/sms_dialog_android.h
index 6f4caa1..8d3ef597 100644
--- a/chrome/browser/ui/android/sms/sms_dialog_android.h
+++ b/chrome/browser/ui/android/sms/sms_dialog_android.h
@@ -19,22 +19,17 @@
   explicit SmsDialogAndroid(const url::Origin& origin);
   ~SmsDialogAndroid() override;
 
-  void Open(content::RenderFrameHost*,
-            base::OnceClosure on_confirm,
-            base::OnceClosure on_cancel) override;
+  void Open(content::RenderFrameHost*, EventHandler handler) override;
   void Close() override;
   void SmsReceived() override;
+  void SmsTimeout() override;
 
-  // Report the user manually clicks the 'Confirm' button.
-  void OnConfirm(JNIEnv* env);
-
-  // Report the user manually dismisses the SMS dialog.
-  void OnCancel(JNIEnv* env);
+  // Report the user's action through |event_type|.
+  void OnEvent(JNIEnv* env, jint event_type);
 
  private:
   base::android::ScopedJavaGlobalRef<jobject> java_dialog_;
-  base::OnceClosure on_confirm_;
-  base::OnceClosure on_cancel_;
+  EventHandler handler_;
   DISALLOW_COPY_AND_ASSIGN(SmsDialogAndroid);
 };
 
diff --git a/chrome/browser/ui/browser_dialogs.h b/chrome/browser/ui/browser_dialogs.h
index 2e272c9..e47a91ca 100644
--- a/chrome/browser/ui/browser_dialogs.h
+++ b/chrome/browser/ui/browser_dialogs.h
@@ -43,11 +43,6 @@
 class AuthChallengeInfo;
 }
 
-namespace payments {
-class PaymentRequest;
-class PaymentRequestDialog;
-}  // namespace payments
-
 namespace safe_browsing {
 class ChromeCleanerController;
 class ChromeCleanerDialogController;
@@ -139,9 +134,6 @@
 task_manager::TaskManagerTableModel* ShowTaskManagerViews(Browser* browser);
 void HideTaskManagerViews();
 
-// Show the Views "Chrome Update" dialog.
-void ShowUpdateChromeDialogViews(gfx::NativeWindow parent);
-
 #endif  // OS_MACOSX
 
 #if defined(TOOLKIT_VIEWS)
@@ -152,15 +144,6 @@
     content::WebContents* web_contents,
     LoginAuthRequiredCallback auth_required_callback);
 
-// Shows the toolkit-views based BookmarkEditor.
-void ShowBookmarkEditorViews(gfx::NativeWindow parent_window,
-                             Profile* profile,
-                             const BookmarkEditor::EditDetails& details,
-                             BookmarkEditor::Configuration configuration);
-
-payments::PaymentRequestDialog* CreatePaymentRequestDialog(
-    payments::PaymentRequest* request);
-
 #endif  // TOOLKIT_VIEWS
 
 // Values used in the Dialog.Creation UMA metric. Each value represents a
diff --git a/chrome/browser/ui/extensions/extension_action_view_controller.cc b/chrome/browser/ui/extensions/extension_action_view_controller.cc
index 28d030c4..77d09ae5 100644
--- a/chrome/browser/ui/extensions/extension_action_view_controller.cc
+++ b/chrome/browser/ui/extensions/extension_action_view_controller.cc
@@ -432,7 +432,7 @@
   image_source->SetIcon(icon_factory_.GetIcon(tab_id));
 
   std::unique_ptr<IconWithBadgeImageSource::Badge> badge;
-  std::string badge_text = extension_action_->GetBadgeText(tab_id);
+  std::string badge_text = extension_action_->GetDisplayBadgeText(tab_id);
   if (!badge_text.empty()) {
     badge.reset(new IconWithBadgeImageSource::Badge(
             badge_text,
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc
index 84ebb31..429e6aa 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc
@@ -639,17 +639,3 @@
   if (!title.empty())
     ui::TreeNodeModel<EditorNode>::SetTitle(node, title);
 }
-
-namespace chrome {
-
-void ShowBookmarkEditorViews(gfx::NativeWindow parent_window,
-                             Profile* profile,
-                             const BookmarkEditor::EditDetails& details,
-                             BookmarkEditor::Configuration configuration) {
-  DCHECK(profile);
-  BookmarkEditorView* editor = new BookmarkEditorView(
-      profile, details.parent_node, details, configuration);
-  editor->Show(parent_window);
-}
-
-}  // namespace chrome
diff --git a/chrome/browser/ui/views/browser_dialogs_views.cc b/chrome/browser/ui/views/browser_dialogs_views.cc
index 8f0c610..e2943e5 100644
--- a/chrome/browser/ui/views/browser_dialogs_views.cc
+++ b/chrome/browser/ui/views/browser_dialogs_views.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/extensions/chrome_extension_chooser_dialog.h"
 #include "chrome/browser/extensions/extension_install_prompt.h"
 #include "chrome/browser/ui/login/login_handler.h"
+#include "chrome/browser/ui/views/bookmarks/bookmark_editor_view.h"
 #include "chrome/browser/ui/views/task_manager_view.h"
 
 // This file provides definitions of desktop browser dialog-creation methods for
@@ -30,8 +31,10 @@
                           Profile* profile,
                           const EditDetails& details,
                           Configuration configuration) {
-  chrome::ShowBookmarkEditorViews(parent_window, profile, details,
-                                  configuration);
+  auto editor = std::make_unique<BookmarkEditorView>(
+      profile, details.parent_node, details, configuration);
+  editor->Show(parent_window);
+  editor.release();  // BookmarkEditorView is self-deleting
 }
 
 void ChromeDevicePermissionsPrompt::ShowDialog() {
diff --git a/chrome/browser/ui/views/chrome_typography_provider.cc b/chrome/browser/ui/views/chrome_typography_provider.cc
index ff9664f..1b0e9426 100644
--- a/chrome/browser/ui/views/chrome_typography_provider.cc
+++ b/chrome/browser/ui/views/chrome_typography_provider.cc
@@ -224,7 +224,6 @@
       return gfx::kGoogleBlue700;
     case STYLE_SECONDARY:
     case STYLE_SECONDARY_MONOSPACED:
-    case STYLE_EMPHASIZED_SECONDARY:
     case STYLE_HINT:
       return native_theme->ShouldUseDarkColors() ? gfx::kGoogleGrey500
                                                  : gfx::kGoogleGrey700;
diff --git a/chrome/browser/ui/views/dropdown_bar_host.cc b/chrome/browser/ui/views/dropdown_bar_host.cc
index 9cda042..138b246 100644
--- a/chrome/browser/ui/views/dropdown_bar_host.cc
+++ b/chrome/browser/ui/views/dropdown_bar_host.cc
@@ -23,7 +23,8 @@
 // DropdownBarHost, public:
 
 DropdownBarHost::DropdownBarHost(BrowserView* browser_view)
-    : browser_view_(browser_view),
+    : AnimationDelegateViews(browser_view),
+      browser_view_(browser_view),
       view_(nullptr),
       delegate_(nullptr),
       focus_manager_(nullptr),
@@ -192,7 +193,7 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// DropdownBarHost, gfx::AnimationDelegate implementation:
+// DropdownBarHost, views::AnimationDelegateViews implementation:
 
 void DropdownBarHost::AnimationProgressed(const gfx::Animation* animation) {
   // First, we calculate how many pixels to slide the widget.
diff --git a/chrome/browser/ui/views/dropdown_bar_host.h b/chrome/browser/ui/views/dropdown_bar_host.h
index 6180f6c1..85b6464 100644
--- a/chrome/browser/ui/views/dropdown_bar_host.h
+++ b/chrome/browser/ui/views/dropdown_bar_host.h
@@ -10,9 +10,9 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "content/public/browser/native_web_keyboard_event.h"
-#include "ui/gfx/animation/animation_delegate.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/native_widget_types.h"
+#include "ui/views/animation/animation_delegate_views.h"
 #include "ui/views/focus/focus_manager.h"
 #include "ui/views/widget/widget_delegate.h"
 
@@ -40,7 +40,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 class DropdownBarHost : public ui::AcceleratorTarget,
                         public views::FocusChangeListener,
-                        public gfx::AnimationDelegate,
+                        public views::AnimationDelegateViews,
                         public views::WidgetDelegate {
  public:
   explicit DropdownBarHost(BrowserView* browser_view);
@@ -87,7 +87,7 @@
   bool AcceleratorPressed(const ui::Accelerator& accelerator) override = 0;
   bool CanHandleAccelerators() const override = 0;
 
-  // gfx::AnimationDelegate implementation:
+  // views::AnimationDelegateViews implementation:
   void AnimationProgressed(const gfx::Animation* animation) override;
   void AnimationEnded(const gfx::Animation* animation) override;
 
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc b/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc
index d42a425..6a0d4fb 100644
--- a/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc
+++ b/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc
@@ -126,8 +126,7 @@
   anchor_view->SetVisible(true);
 
   active_bubble_ = new ToolbarActionsBarBubbleViews(
-      anchor_view, gfx::Point(), anchor_view != extensions_button_,
-      std::move(controller));
+      anchor_view, anchor_view != extensions_button_, std::move(controller));
   views::BubbleDialogDelegateView::CreateBubble(active_bubble_)
       ->AddObserver(this);
   active_bubble_->Show();
diff --git a/ui/views/layout/interpolating_layout_manager.cc b/chrome/browser/ui/views/layout/interpolating_layout_manager.cc
similarity index 66%
rename from ui/views/layout/interpolating_layout_manager.cc
rename to chrome/browser/ui/views/layout/interpolating_layout_manager.cc
index 496b934..b62bb84 100644
--- a/ui/views/layout/interpolating_layout_manager.cc
+++ b/chrome/browser/ui/views/layout/interpolating_layout_manager.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/views/layout/interpolating_layout_manager.h"
+#include "chrome/browser/ui/views/layout/interpolating_layout_manager.h"
 
 #include <memory>
 #include <utility>
@@ -10,50 +10,11 @@
 #include "ui/gfx/animation/tween.h"
 #include "ui/views/view.h"
 
-namespace views {
-
-namespace {
-
-using ChildLayout = LayoutManagerBase::ChildLayout;
-using ProposedLayout = LayoutManagerBase::ProposedLayout;
-
-// Returns a layout that's linearly interpolated between |first_layout| and
-// |second_layout| by |percent|. See gfx::Tween::LinearIntValueBetween() for
-// the exact math involved.
-ProposedLayout Interpolate(double value,
-                           const ProposedLayout& start,
-                           const ProposedLayout& target) {
-  ProposedLayout layout;
-  const size_t num_children = start.child_layouts.size();
-  DCHECK_EQ(num_children, target.child_layouts.size());
-
-  // Interpolate the host size.
-  // TODO(dfried): Add direct gfx::Size interpolation to gfx::Tween.
-  const gfx::Size size =
-      gfx::Tween::SizeValueBetween(value, start.host_size, target.host_size);
-  layout.host_size = gfx::Size(size.width(), size.height());
-
-  // Interpolate the child bounds.
-  for (size_t i = 0; i < num_children; ++i) {
-    const ChildLayout& start_child = start.child_layouts[i];
-    const ChildLayout& target_child = target.child_layouts[i];
-    DCHECK_EQ(start_child.child_view, target_child.child_view);
-    layout.child_layouts.emplace_back(
-        ChildLayout{start_child.child_view,
-                    gfx::Tween::RectValueBetween(value, start_child.bounds,
-                                                 target_child.bounds),
-                    start_child.visible && target_child.visible});
-  }
-  return layout;
-}
-
-}  // namespace
-
 InterpolatingLayoutManager::InterpolatingLayoutManager() {}
 InterpolatingLayoutManager::~InterpolatingLayoutManager() = default;
 
 InterpolatingLayoutManager& InterpolatingLayoutManager::SetOrientation(
-    LayoutOrientation orientation) {
+    views::LayoutOrientation orientation) {
   if (orientation_ != orientation) {
     orientation_ = orientation;
     InvalidateLayout();
@@ -63,7 +24,7 @@
 
 void InterpolatingLayoutManager::AddLayoutInternal(
     std::unique_ptr<LayoutManagerBase> engine,
-    const Span& interpolation_range) {
+    const views::Span& interpolation_range) {
   DCHECK(engine);
 
   SyncStateTo(engine.get());
@@ -73,8 +34,8 @@
                         << interpolation_range.ToString();
 
 #if DCHECK_IS_ON()
-  // Sanity checking to ensure interpolation ranges do not overlap (we can only
-  // interpolate between two layouts currently).
+  // Sanity checking to ensure interpolation ranges do not overlap (we can
+  // only interpolate between two layouts currently).
   auto next = result.first;
   ++next;
   if (next != embedded_layouts_.end())
@@ -89,14 +50,15 @@
 
 InterpolatingLayoutManager::LayoutInterpolation
 InterpolatingLayoutManager::GetInterpolation(
-    const SizeBounds& size_bounds) const {
+    const views::SizeBounds& size_bounds) const {
   DCHECK(!embedded_layouts_.empty());
 
   LayoutInterpolation result;
 
   const base::Optional<int> dimension =
-      orientation_ == LayoutOrientation::kHorizontal ? size_bounds.width()
-                                                     : size_bounds.height();
+      orientation_ == views::LayoutOrientation::kHorizontal
+          ? size_bounds.width()
+          : size_bounds.height();
 
   // Find the larger layout that overlaps the target size.
   auto match = dimension ? embedded_layouts_.upper_bound({*dimension, 0})
@@ -108,7 +70,7 @@
   result.first = (--match)->second.get();
 
   // If the target size falls in an interpolation range, get the other layout.
-  const Span& first_span = match->first;
+  const views::Span& first_span = match->first;
   if (dimension && first_span.end() > *dimension) {
     DCHECK(match != embedded_layouts_.begin())
         << "Primary dimension size " << (dimension ? *dimension : -1)
@@ -122,9 +84,9 @@
   return result;
 }
 
-LayoutManagerBase::ProposedLayout
+views::LayoutManagerBase::ProposedLayout
 InterpolatingLayoutManager::CalculateProposedLayout(
-    const SizeBounds& size_bounds) const {
+    const views::SizeBounds& size_bounds) const {
   // For interpolating layout we will never call this method except for fully-
   // specified sizes.
   DCHECK(size_bounds.width());
@@ -157,24 +119,27 @@
   InvalidateLayout();
 }
 
-gfx::Size InterpolatingLayoutManager::GetPreferredSize(const View* host) const {
+gfx::Size InterpolatingLayoutManager::GetPreferredSize(
+    const views::View* host) const {
   DCHECK_EQ(host_view(), host);
   DCHECK(host);
   return GetDefaultLayout()->GetPreferredSize(host);
 }
 
-gfx::Size InterpolatingLayoutManager::GetMinimumSize(const View* host) const {
+gfx::Size InterpolatingLayoutManager::GetMinimumSize(
+    const views::View* host) const {
   DCHECK_EQ(host_view(), host);
   DCHECK(host);
   return GetSmallestLayout()->GetMinimumSize(host);
 }
 
-int InterpolatingLayoutManager::GetPreferredHeightForWidth(const View* host,
-                                                           int width) const {
-  // It is in general not possible to determine what the correct
-  // height-for-width trade-off is while interpolating between two already-
-  // generated layouts because the values tend to rely on the behavior of
-  // individual child views at specific dimensions.
+int InterpolatingLayoutManager::GetPreferredHeightForWidth(
+    const views::View* host,
+    int width) const {
+  // It is in general not possible to determine what the correct height-for-
+  // width trade-off is while interpolating between two already-generated
+  // layouts because the values tend to rely on the behavior of individual child
+  // views at specific dimensions.
   //
   // The two reasonable choices are to use the larger of the two values (with
   // the understanding that the height of the view may "pop" at the edge of the
@@ -203,49 +168,88 @@
     embedded.second->InvalidateLayout();
 }
 
-void InterpolatingLayoutManager::SetChildViewIgnoredByLayout(View* child_view,
-                                                             bool ignored) {
+void InterpolatingLayoutManager::SetChildViewIgnoredByLayout(
+    views::View* child_view,
+    bool ignored) {
   LayoutManagerBase::SetChildViewIgnoredByLayout(child_view, ignored);
   for (auto& embedded : embedded_layouts_)
     embedded.second->SetChildViewIgnoredByLayout(child_view, ignored);
 }
 
-void InterpolatingLayoutManager::Installed(View* host_view) {
+// static
+views::LayoutManagerBase::ProposedLayout
+InterpolatingLayoutManager::Interpolate(double value,
+                                        const ProposedLayout& start,
+                                        const ProposedLayout& target) {
+  if (value >= 1.0)
+    return target;
+
+  ProposedLayout layout;
+
+  // Interpolate the host size.
+  layout.host_size =
+      gfx::Tween::SizeValueBetween(value, start.host_size, target.host_size);
+
+  // The views may not be listed in the same order and some views might be
+  // omitted from either the |start| or |target| layout.
+  std::map<const views::View*, size_t> start_view_to_index;
+  for (size_t i = 0; i < start.child_layouts.size(); ++i)
+    start_view_to_index.emplace(start.child_layouts[i].child_view, i);
+  for (const ChildLayout& target_child : target.child_layouts) {
+    // Try to match the view from the target with the view from the start.
+    const auto start_match = start_view_to_index.find(target_child.child_view);
+    if (start_match == start_view_to_index.end()) {
+      // If there is no match, make the view present but invisible.
+      layout.child_layouts.push_back({target_child.child_view, false});
+    } else {
+      // Tween the two layouts.
+      const ChildLayout& start_child = start.child_layouts[start_match->second];
+      layout.child_layouts.push_back(
+          {target_child.child_view, start_child.visible && target_child.visible,
+           gfx::Tween::RectValueBetween(value, start_child.bounds,
+                                        target_child.bounds)});
+    }
+  }
+  return layout;
+}
+
+void InterpolatingLayoutManager::Installed(views::View* host_view) {
   LayoutManagerBase::Installed(host_view);
   for (auto& embedded : embedded_layouts_)
     embedded.second->Installed(host_view);
 }
 
-void InterpolatingLayoutManager::ViewAdded(View* host_view, View* child_view) {
+void InterpolatingLayoutManager::ViewAdded(views::View* host_view,
+                                           views::View* child_view) {
   LayoutManagerBase::ViewAdded(host_view, child_view);
   for (auto& embedded : embedded_layouts_)
     embedded.second->ViewAdded(host_view, child_view);
 }
 
-void InterpolatingLayoutManager::ViewRemoved(View* host_view,
-                                             View* child_view) {
+void InterpolatingLayoutManager::ViewRemoved(views::View* host_view,
+                                             views::View* child_view) {
   LayoutManagerBase::ViewRemoved(host_view, child_view);
   for (auto& embedded : embedded_layouts_)
     embedded.second->ViewRemoved(host_view, child_view);
 }
 
-void InterpolatingLayoutManager::ViewVisibilitySet(View* host,
-                                                   View* view,
+void InterpolatingLayoutManager::ViewVisibilitySet(views::View* host,
+                                                   views::View* view,
                                                    bool visible) {
   LayoutManagerBase::ViewVisibilitySet(host, view, visible);
   for (auto& embedded : embedded_layouts_)
     embedded.second->ViewVisibilitySet(host, view, visible);
 }
 
-const LayoutManagerBase* InterpolatingLayoutManager::GetDefaultLayout() const {
+const views::LayoutManagerBase* InterpolatingLayoutManager::GetDefaultLayout()
+    const {
   DCHECK(!embedded_layouts_.empty());
   return default_layout_ ? default_layout_
                          : embedded_layouts_.rbegin()->second.get();
 }
 
-const LayoutManagerBase* InterpolatingLayoutManager::GetSmallestLayout() const {
+const views::LayoutManagerBase* InterpolatingLayoutManager::GetSmallestLayout()
+    const {
   DCHECK(!embedded_layouts_.empty());
   return embedded_layouts_.begin()->second.get();
 }
-
-}  // namespace views
diff --git a/ui/views/layout/interpolating_layout_manager.h b/chrome/browser/ui/views/layout/interpolating_layout_manager.h
similarity index 67%
rename from ui/views/layout/interpolating_layout_manager.h
rename to chrome/browser/ui/views/layout/interpolating_layout_manager.h
index 0cc084c..7923c719 100644
--- a/ui/views/layout/interpolating_layout_manager.h
+++ b/chrome/browser/ui/views/layout/interpolating_layout_manager.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_VIEWS_LAYOUT_INTERPOLATING_LAYOUT_MANAGER_H_
-#define UI_VIEWS_LAYOUT_INTERPOLATING_LAYOUT_MANAGER_H_
+#ifndef CHROME_BROWSER_UI_VIEWS_LAYOUT_INTERPOLATING_LAYOUT_MANAGER_H_
+#define CHROME_BROWSER_UI_VIEWS_LAYOUT_INTERPOLATING_LAYOUT_MANAGER_H_
 
 #include <map>
 #include <memory>
@@ -12,8 +12,6 @@
 #include "ui/views/layout/flex_layout_types.h"
 #include "ui/views/layout/layout_manager_base.h"
 
-namespace views {
-
 // Layout which interpolates between multiple embedded LayoutManagerBase
 // layouts.
 //
@@ -47,13 +45,14 @@
 // Note that behavior when interpolation ranges overlap is undefined, but will
 // be guaranteed to at least be the result of mixing two adjacent layouts that
 // fall over the range in a way that is not completely irrational.
-class VIEWS_EXPORT InterpolatingLayoutManager : public LayoutManagerBase {
+class InterpolatingLayoutManager : public views::LayoutManagerBase {
  public:
   InterpolatingLayoutManager();
   ~InterpolatingLayoutManager() override;
 
-  InterpolatingLayoutManager& SetOrientation(LayoutOrientation orientation);
-  LayoutOrientation orientation() const { return orientation_; }
+  InterpolatingLayoutManager& SetOrientation(
+      views::LayoutOrientation orientation);
+  views::LayoutOrientation orientation() const { return orientation_; }
 
   // Adds a layout which starts and finished phasing in at |start_interpolation|
   // and |end_interpolation|, respectively. Currently, having more than one
@@ -63,7 +62,7 @@
   // a typed raw pointer to the added layout engine.
   template <class T>
   T* AddLayout(std::unique_ptr<T> layout_manager,
-               const Span& interpolation_range = Span()) {
+               const views::Span& interpolation_range = views::Span()) {
     T* const temp = layout_manager.get();
     AddLayoutInternal(std::move(layout_manager), interpolation_range);
     return temp;
@@ -75,20 +74,31 @@
   void SetDefaultLayout(LayoutManagerBase* default_layout);
 
   // LayoutManagerBase:
-  gfx::Size GetPreferredSize(const View* host) const override;
-  gfx::Size GetMinimumSize(const View* host) const override;
-  int GetPreferredHeightForWidth(const View* host, int width) const override;
+  gfx::Size GetPreferredSize(const views::View* host) const override;
+  gfx::Size GetMinimumSize(const views::View* host) const override;
+  int GetPreferredHeightForWidth(const views::View* host,
+                                 int width) const override;
   void InvalidateLayout() override;
-  void SetChildViewIgnoredByLayout(View* child_view, bool ignored) override;
+  void SetChildViewIgnoredByLayout(views::View* child_view,
+                                   bool ignored) override;
+
+  // Returns a layout that's linearly interpolated between |start| and |target|
+  // by |value|, which should be between 0 and 1. See
+  // gfx::Tween::LinearIntValueBetween() for the exact math involved.
+  static ProposedLayout Interpolate(double value,
+                                    const ProposedLayout& start,
+                                    const ProposedLayout& target);
 
  protected:
   // LayoutManagerBase:
-  void Installed(View* host_view) override;
-  void ViewAdded(View* host_view, View* child_view) override;
-  void ViewRemoved(View* host_view, View* child_view) override;
-  void ViewVisibilitySet(View* host, View* view, bool visible) override;
+  void Installed(views::View* host_view) override;
+  void ViewAdded(views::View* host_view, views::View* child_view) override;
+  void ViewRemoved(views::View* host_view, views::View* child_view) override;
+  void ViewVisibilitySet(views::View* host,
+                         views::View* view,
+                         bool visible) override;
   ProposedLayout CalculateProposedLayout(
-      const SizeBounds& size_bounds) const override;
+      const views::SizeBounds& size_bounds) const override;
 
  private:
   // Describes an interpolation between two layouts as a pointer to each and
@@ -104,12 +114,12 @@
   };
 
   void AddLayoutInternal(std::unique_ptr<LayoutManagerBase> layout,
-                         const Span& interpolation_range);
+                         const views::Span& interpolation_range);
 
   // Given a set of size bounds and the current layout's orientation, returns
   // a LayoutInterpolation providing the two layouts to interpolate between.
   // If only one layout applies, only |right| is set and |percent| is set to 1.
-  LayoutInterpolation GetInterpolation(const SizeBounds& bounds) const;
+  LayoutInterpolation GetInterpolation(const views::SizeBounds& bounds) const;
 
   // Returns the default layout, or the largest layout if the default has not
   // been set.
@@ -118,15 +128,13 @@
   // Returns the smallest layout; useful for calculating minimum layout size.
   const LayoutManagerBase* GetSmallestLayout() const;
 
-  LayoutOrientation orientation_ = LayoutOrientation::kHorizontal;
+  views::LayoutOrientation orientation_ = views::LayoutOrientation::kHorizontal;
 
   // Maps from interpolation range to embedded layout.
-  std::map<Span, std::unique_ptr<LayoutManagerBase>> embedded_layouts_;
+  std::map<views::Span, std::unique_ptr<LayoutManagerBase>> embedded_layouts_;
   LayoutManagerBase* default_layout_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(InterpolatingLayoutManager);
 };
 
-}  // namespace views
-
-#endif  // UI_VIEWS_LAYOUT_INTERPOLATING_LAYOUT_MANAGER_H_
+#endif  // CHROME_BROWSER_UI_VIEWS_LAYOUT_INTERPOLATING_LAYOUT_MANAGER_H_
diff --git a/ui/views/layout/interpolating_layout_manager_unittest.cc b/chrome/browser/ui/views/layout/interpolating_layout_manager_unittest.cc
similarity index 98%
rename from ui/views/layout/interpolating_layout_manager_unittest.cc
rename to chrome/browser/ui/views/layout/interpolating_layout_manager_unittest.cc
index cf44cda..4175611 100644
--- a/ui/views/layout/interpolating_layout_manager_unittest.cc
+++ b/chrome/browser/ui/views/layout/interpolating_layout_manager_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/views/layout/interpolating_layout_manager.h"
+#include "chrome/browser/ui/views/layout/interpolating_layout_manager.h"
 
 #include <memory>
 
@@ -11,7 +11,7 @@
 #include "ui/views/test/test_views.h"
 #include "ui/views/view.h"
 
-namespace views {
+using namespace views;
 
 namespace {
 
@@ -319,5 +319,3 @@
                 expected_other.child_layouts[0].bounds),
             actual.child_layouts[0].bounds);
 }
-
-}  // namespace views
diff --git a/chrome/browser/ui/views/payments/payment_request_dialog_view.cc b/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
index 969180d..09c60a7b 100644
--- a/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
+++ b/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
@@ -37,16 +37,6 @@
 #include "ui/views/layout/fill_layout.h"
 #include "ui/views/layout/grid_layout.h"
 
-namespace chrome {
-
-payments::PaymentRequestDialog* CreatePaymentRequestDialog(
-    payments::PaymentRequest* request) {
-  return new payments::PaymentRequestDialogView(request,
-                                                /* no observer */ nullptr);
-}
-
-}  // namespace chrome
-
 namespace payments {
 
 namespace {
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view.cc b/chrome/browser/ui/views/profiles/profile_menu_view.cc
index 6050c46..b59debc 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_view.cc
@@ -64,10 +64,6 @@
 // Number of times the Dice sign-in promo illustration should be shown.
 constexpr int kDiceSigninPromoIllustrationShowCountMax = 10;
 
-bool IsProfileChooser(profiles::BubbleViewMode mode) {
-  return mode == profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER;
-}
-
 BadgedProfilePhoto::BadgeType GetProfileBadgeType(Profile* profile) {
   if (profile->IsSupervised()) {
     return profile->IsChild() ? BadgedProfilePhoto::BADGE_TYPE_CHILD
@@ -135,11 +131,9 @@
 
 ProfileMenuView::ProfileMenuView(views::Button* anchor_button,
                                        Browser* browser,
-                                       profiles::BubbleViewMode view_mode,
                                        signin::GAIAServiceType service_type,
                                        signin_metrics::AccessPoint access_point)
     : ProfileMenuViewBase(anchor_button, browser),
-      view_mode_(view_mode),
       gaia_service_type_(service_type),
       access_point_(access_point),
       dice_enabled_(AccountConsistencyModeManager::IsDiceEnabledForProfile(
@@ -181,13 +175,6 @@
       this, browser()));
   avatar_menu_->RebuildMenu();
 
-  Profile* profile = browser()->profile();
-  signin::IdentityManager* identity_manager =
-      IdentityManagerFactory::GetForProfile(profile);
-
-  if (identity_manager)
-    identity_manager->AddObserver(this);
-
   if (dice_enabled_) {
     // Fetch DICE accounts. Note: This always includes the primary account if it
     // is set.
@@ -195,68 +182,22 @@
         signin_ui_util::GetAccountsForDicePromos(browser()->profile());
   }
 
-  ShowViewOrOpenTab(view_mode_);
+  ShowView(avatar_menu_.get());
 }
 
 void ProfileMenuView::OnAvatarMenuChanged(
     AvatarMenu* avatar_menu) {
-  if (IsProfileChooser(view_mode_)) {
-    // Refresh the view with the new menu. We can't just update the local copy
-    // as this may have been triggered by a sign out action, in which case
-    // the view is being destroyed.
-    ShowView(view_mode_, avatar_menu);
-  }
+  // Refresh the view with the new menu. We can't just update the local copy
+  // as this may have been triggered by a sign out action, in which case
+  // the view is being destroyed.
+  ShowView(avatar_menu);
 }
 
-void ProfileMenuView::OnRefreshTokenUpdatedForAccount(
-    const CoreAccountInfo& account_info) {
-  if (view_mode_ == profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT ||
-      view_mode_ == profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH) {
-    ShowViewOrOpenTab(profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER);
-  }
-}
-
-void ProfileMenuView::ShowView(profiles::BubbleViewMode view_to_display,
-                                  AvatarMenu* avatar_menu) {
-  if (browser()->profile()->IsSupervised() &&
-      view_to_display == profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT) {
-    LOG(WARNING) << "Supervised user attempted to add account";
-    return;
-  }
-
-  view_mode_ = view_to_display;
-  switch (view_mode_) {
-    case profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN:
-    case profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT:
-    case profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH:
-      // The modal sign-in view is shown in for bubble view modes.
-      // See |SigninViewController::ShouldShowSigninForMode|.
-      NOTREACHED();
-      break;
-    case profiles::BUBBLE_VIEW_MODE_INCOGNITO:
-      // Covered in IncognitoView.
-      NOTREACHED();
-      break;
-    case profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER:
-      AddProfileMenuView(avatar_menu);
-      break;
-  }
+void ProfileMenuView::ShowView(AvatarMenu* avatar_menu) {
+  AddProfileMenuView(avatar_menu);
   RepopulateViewFromMenuItems();
 }
 
-void ProfileMenuView::ShowViewOrOpenTab(profiles::BubbleViewMode mode) {
-  if (SigninViewController::ShouldShowSigninForMode(mode)) {
-    // Hides the user menu if it is currently shown. The user menu automatically
-    // closes when it loses focus; however, on Windows, the signin modals do not
-    // take away focus, thus we need to manually close the bubble.
-    Hide();
-    browser()->signin_view_controller()->ShowSignin(mode, browser(),
-                                                    access_point_);
-  } else {
-    ShowView(mode, avatar_menu_.get());
-  }
-}
-
 void ProfileMenuView::FocusButtonOnKeyboardOpen() {
   if (first_profile_button_)
     first_profile_button_->RequestFocus();
@@ -266,10 +207,6 @@
   // Unsubscribe from everything early so that the updates do not reach the
   // bubble and change its state.
   avatar_menu_.reset();
-  signin::IdentityManager* identity_manager =
-      IdentityManagerFactory::GetForProfile(browser()->profile());
-  if (identity_manager)
-    identity_manager->RemoveObserver(this);
 }
 
 views::View* ProfileMenuView::GetInitiallyFocusedView() {
@@ -346,11 +283,15 @@
               signin::PrimaryAccountMutator::ClearAccountsAction::kDefault,
               signin_metrics::USER_CLICKED_SIGNOUT_SETTINGS,
               signin_metrics::SignoutDelete::IGNORE_METRIC);
-          ShowViewOrOpenTab(profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN);
+          Hide();
+          browser()->signin_view_controller()->ShowSignin(
+              profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN, browser(), access_point_);
         }
         break;
       case sync_ui_util::AUTH_ERROR:
-        ShowViewOrOpenTab(profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH);
+        Hide();
+        browser()->signin_view_controller()->ShowSignin(
+            profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH, browser(), access_point_);
         break;
       case sync_ui_util::UPGRADE_CLIENT_ERROR:
         chrome::OpenUpdateChromeDialog(browser());
@@ -378,7 +319,9 @@
       PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_NAME);
     }
   } else if (sender == signin_current_profile_button_) {
-    ShowViewOrOpenTab(profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN);
+    Hide();
+    browser()->signin_view_controller()->ShowSignin(
+        profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN, browser(), access_point_);
   } else if (sender == signin_with_gaia_account_button_) {
     DCHECK(dice_signin_button_view_->account());
     Hide();
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view.h b/chrome/browser/ui/views/profiles/profile_menu_view.h
index 08ef753d..32f2986 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view.h
+++ b/chrome/browser/ui/views/profiles/profile_menu_view.h
@@ -16,10 +16,8 @@
 #include "chrome/browser/profiles/avatar_menu_observer.h"
 #include "chrome/browser/sync/sync_ui_util.h"
 #include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/profile_chooser_constants.h"
 #include "chrome/browser/ui/views/profiles/profile_menu_view_base.h"
 #include "components/signin/core/browser/signin_header_helper.h"
-#include "components/signin/public/identity_manager/identity_manager.h"
 #include "ui/views/controls/styled_label.h"
 
 namespace views {
@@ -33,13 +31,10 @@
 
 // This bubble view is displayed when the user clicks on the avatar button.
 // It displays a list of profiles and allows users to switch between profiles.
-class ProfileMenuView : public ProfileMenuViewBase,
-                           public AvatarMenuObserver,
-                           public signin::IdentityManager::Observer {
+class ProfileMenuView : public ProfileMenuViewBase, public AvatarMenuObserver {
  public:
   ProfileMenuView(views::Button* anchor_button,
                      Browser* browser,
-                     profiles::BubbleViewMode view_mode,
                      signin::GAIAServiceType service_type,
                      signin_metrics::AccessPoint access_point);
   ~ProfileMenuView() override;
@@ -70,10 +65,6 @@
   // AvatarMenuObserver:
   void OnAvatarMenuChanged(AvatarMenu* avatar_menu) override;
 
-  // signin::IdentityManager::Observer overrides.
-  void OnRefreshTokenUpdatedForAccount(
-      const CoreAccountInfo& account_info) override;
-
   // We normally close the bubble any time it becomes inactive but this can lead
   // to flaky tests where unexpected UI events are triggering this behavior.
   // Tests set this to "false" for more consistent operation.
@@ -81,11 +72,8 @@
 
   void Reset();
 
-  // Shows the bubble with the |view_to_display|.
-  void ShowView(profiles::BubbleViewMode view_to_display,
-                AvatarMenu* avatar_menu);
-  // Shows the bubble view or opens a tab based on given |mode|.
-  void ShowViewOrOpenTab(profiles::BubbleViewMode mode);
+  // Shows the bubble view.
+  void ShowView(AvatarMenu* avatar_menu);
 
   // Adds the profile chooser view.
   void AddProfileMenuView(AvatarMenu* avatar_menu);
@@ -178,9 +166,6 @@
   // View for the signin/turn-on-sync button in the dice promo.
   DiceSigninButtonView* dice_signin_button_view_;
 
-  // Active view mode.
-  profiles::BubbleViewMode view_mode_;
-
   // The GAIA service type provided in the response header.
   signin::GAIAServiceType gaia_service_type_;
 
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view_base.cc b/chrome/browser/ui/views/profiles/profile_menu_view_base.cc
index e2f10326..5672e95 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view_base.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_view_base.cc
@@ -72,17 +72,16 @@
   if (IsShowing())
     return;
 
-  DCHECK_EQ(browser->profile()->IsIncognitoProfile(),
-            view_mode == profiles::BUBBLE_VIEW_MODE_INCOGNITO);
-
   ProfileMenuViewBase* bubble;
   if (view_mode == profiles::BUBBLE_VIEW_MODE_INCOGNITO) {
+    DCHECK(browser->profile()->IsIncognitoProfile());
     bubble = new IncognitoMenuView(anchor_button, browser);
   } else {
+    DCHECK_EQ(profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER, view_mode);
 #if !defined(OS_CHROMEOS)
-    bubble = new ProfileMenuView(anchor_button, browser, view_mode,
-                                    manage_accounts_params.service_type,
-                                    access_point);
+    bubble =
+        new ProfileMenuView(anchor_button, browser,
+                            manage_accounts_params.service_type, access_point);
 #else
     NOTREACHED();
     return;
diff --git a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc
index 6c71348b..bdae240 100644
--- a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc
+++ b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc
@@ -51,12 +51,15 @@
   num_tabs_--;
   // RemoveTabAt() expects the controller state to have been updated already.
   const bool was_active = index == active_index_;
-  if (active_index_ > index) {
+  if (was_active) {
+    active_index_ = std::min(active_index_, num_tabs_ - 1);
+    selection_model_.SetSelectedIndex(active_index_);
+  } else if (active_index_ > index) {
     --active_index_;
-  } else if (active_index_ == index) {
-    SetActiveIndex(std::min(active_index_, num_tabs_ - 1));
   }
   tab_strip_->RemoveTabAt(nullptr, index, was_active);
+  if (was_active && IsValidIndex(active_index_))
+    tab_strip_->SetSelection(selection_model_);
 }
 
 void FakeBaseTabStripController::MoveTabIntoGroup(
diff --git a/chrome/browser/ui/views/tabs/tab_strip_unittest.cc b/chrome/browser/ui/views/tabs/tab_strip_unittest.cc
index 11f9470..5ee2da4 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_unittest.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip_unittest.cc
@@ -1128,4 +1128,23 @@
   EXPECT_EQ(0u, ListGroupHeaders().size());
 }
 
+TEST_P(TabStripTest, ChangingLayoutTypeResizesTabs) {
+  tab_strip_->SetBounds(0, 0, 1000, 100);
+
+  tab_strip_->AddTabAt(0, TabRendererData(), false);
+  Tab* tab = tab_strip_->tab_at(0);
+  const int initial_height = tab->height();
+
+  ui::test::MaterialDesignControllerTestAPI other_layout(!GetParam());
+
+  CompleteAnimationAndLayout();
+  if (GetParam()) {
+    // Touch -> normal.
+    EXPECT_LT(tab->height(), initial_height);
+  } else {
+    // Normal -> touch.
+    EXPECT_GT(tab->height(), initial_height);
+  }
+}
+
 INSTANTIATE_TEST_SUITE_P(, TabStripTest, ::testing::Values(false, true));
diff --git a/chrome/browser/ui/views/toolbar/browser_actions_container.cc b/chrome/browser/ui/views/toolbar/browser_actions_container.cc
index d473ab7..61bc70d5 100644
--- a/chrome/browser/ui/views/toolbar/browser_actions_container.cc
+++ b/chrome/browser/ui/views/toolbar/browser_actions_container.cc
@@ -319,8 +319,7 @@
   }
 
   ToolbarActionsBarBubbleViews* bubble = new ToolbarActionsBarBubbleViews(
-      anchor_view, gfx::Point(), anchored_to_action_view,
-      std::move(controller));
+      anchor_view, anchored_to_action_view, std::move(controller));
   active_bubble_ = bubble;
   views::BubbleDialogDelegateView::CreateBubble(bubble);
   bubble->GetWidget()->AddObserver(this);
diff --git a/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.cc b/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.cc
index 99c15d26..1921528b 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.cc
@@ -27,16 +27,14 @@
 
 ToolbarActionsBarBubbleViews::ToolbarActionsBarBubbleViews(
     views::View* anchor_view,
-    const gfx::Point& anchor_point,
     bool anchored_to_action,
     std::unique_ptr<ToolbarActionsBarBubbleDelegate> delegate)
     : views::BubbleDialogDelegateView(anchor_view,
                                       views::BubbleBorder::TOP_RIGHT),
       delegate_(std::move(delegate)),
       anchored_to_action_(anchored_to_action) {
+  DCHECK(anchor_view);
   set_close_on_deactivate(delegate_->ShouldCloseOnDeactivate());
-  if (!anchor_view)
-    SetAnchorRect(gfx::Rect(anchor_point, gfx::Size()));
   chrome::RecordDialogCreation(chrome::DialogIdentifier::TOOLBAR_ACTIONS_BAR);
 }
 
diff --git a/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.h b/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.h
index 1e105f7..72565050 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.h
+++ b/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.h
@@ -22,11 +22,9 @@
 class ToolbarActionsBarBubbleViews : public views::BubbleDialogDelegateView,
                                      public views::ButtonListener {
  public:
-  // Creates the bubble anchored to |anchor_view| or, if that is null, to
-  // |anchor_point| in screen coordinates.
+  // Creates the bubble anchored to |anchor_view|, which may not be nullptr.
   ToolbarActionsBarBubbleViews(
       views::View* anchor_view,
-      const gfx::Point& anchor_point,
       bool anchored_to_action,
       std::unique_ptr<ToolbarActionsBarBubbleDelegate> delegate);
   ~ToolbarActionsBarBubbleViews() override;
diff --git a/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views_unittest.cc b/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views_unittest.cc
index c021fe36..03216b7a 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views_unittest.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views_unittest.cc
@@ -64,7 +64,7 @@
     anchor_widget_ = CreateAnchorWidget();
     bool anchored_to_action = false;
     bubble_ = new ToolbarActionsBarBubbleViews(
-        anchor_widget_->GetContentsView(), gfx::Point(), anchored_to_action,
+        anchor_widget_->GetContentsView(), anchored_to_action,
         delegate->GetDelegate());
     bubble_widget_ = views::BubbleDialogDelegateView::CreateBubble(bubble_);
     bubble_->Show();
@@ -248,8 +248,7 @@
                                                ActionString());
   delegate.set_dismiss_button_text(DismissString());
   ToolbarActionsBarBubbleViews* bubble = new ToolbarActionsBarBubbleViews(
-      anchor_widget->GetContentsView(), gfx::Point(), false,
-      delegate.GetDelegate());
+      anchor_widget->GetContentsView(), false, delegate.GetDelegate());
 
   EXPECT_FALSE(delegate.shown());
   EXPECT_FALSE(delegate.close_action());
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
index 7a2a3a4..87c7dab 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -68,6 +68,7 @@
 #include "chromeos/login/auth/cryptohome_key_constants.h"
 #include "chromeos/login/auth/saml_password_attributes.h"
 #include "chromeos/login/auth/user_context.h"
+#include "chromeos/network/onc/certificate_scope.h"
 #include "chromeos/settings/cros_settings_names.h"
 #include "components/login/localized_values_builder.h"
 #include "components/policy/proto/chrome_device_policy.pb.h"
@@ -1320,7 +1321,8 @@
             g_browser_process->platform_part()
                 ->browser_policy_connector_chromeos()
                 ->GetDeviceNetworkConfigurationUpdater()
-                ->GetAllAuthorityCertificates());
+                ->GetAllAuthorityCertificates(
+                    chromeos::onc::CertificateScope::Default()));
   }
 
   LoadAuthExtension(!gaia_silent_load_ /* force */, false /* offline */);
diff --git a/chrome/chrome_cleaner/DEPS b/chrome/chrome_cleaner/DEPS
index f7285e7..f69b764 100644
--- a/chrome/chrome_cleaner/DEPS
+++ b/chrome/chrome_cleaner/DEPS
@@ -1,5 +1,14 @@
+# chrome_cleaner is built into a separate executable and should not inherit
+# rules from chromium.
+noparent = True
+
 include_rules = [
+  "+base",
   "+components/chrome_cleaner",
+  "+crypto",
+  "+mojo/public",
   "+sandbox/win/src",
+  "+testing",
   "+third_party/protobuf/src/google/protobuf",
+  "+url",
 ]
diff --git a/chrome/chrome_cleaner/chrome_utils/DEPS b/chrome/chrome_cleaner/chrome_utils/DEPS
deleted file mode 100644
index 9648b97a..0000000
--- a/chrome/chrome_cleaner/chrome_utils/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
-  "+components/chrome_cleaner",
-]
diff --git a/chrome/chrome_cleaner/cleaner/DEPS b/chrome/chrome_cleaner/cleaner/DEPS
deleted file mode 100644
index 9648b97a..0000000
--- a/chrome/chrome_cleaner/cleaner/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
-  "+components/chrome_cleaner",
-]
diff --git a/chrome/chrome_cleaner/engines/DEPS b/chrome/chrome_cleaner/engines/DEPS
deleted file mode 100644
index ef8ad28..0000000
--- a/chrome/chrome_cleaner/engines/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
-  "+mojo/public",
-]
diff --git a/chrome/chrome_cleaner/ipc/DEPS b/chrome/chrome_cleaner/ipc/DEPS
index f4d373b..9243dcd6 100644
--- a/chrome/chrome_cleaner/ipc/DEPS
+++ b/chrome/chrome_cleaner/ipc/DEPS
@@ -1,4 +1,3 @@
 include_rules = [
   "+mojo/core/embedder",
-  "+mojo/public/cpp",
 ]
diff --git a/chrome/chrome_cleaner/logging/DEPS b/chrome/chrome_cleaner/logging/DEPS
index 6c0df623..7097cb4 100644
--- a/chrome/chrome_cleaner/logging/DEPS
+++ b/chrome/chrome_cleaner/logging/DEPS
@@ -1,4 +1,3 @@
 include_rules = [
   "+net/traffic_annotation",
-  "+url",
 ]
diff --git a/chrome/chrome_cleaner/mojom/typemaps/DEPS b/chrome/chrome_cleaner/mojom/typemaps/DEPS
index 0a4da77..b4c64d8 100644
--- a/chrome/chrome_cleaner/mojom/typemaps/DEPS
+++ b/chrome/chrome_cleaner/mojom/typemaps/DEPS
@@ -1,9 +1,4 @@
 include_rules = [
-  # Allow the typemaps to access their dependencies.
-  '+mojo/public/cpp/bindings',
-  '+mojo/public/cpp/base',
-  '+mojo/public/cpp/system/platform_handle.h',
-
   # Allow unit tests to set up a mojo embedder.
   '+mojo/core/embedder',
 ]
diff --git a/chrome/chrome_cleaner/os/DEPS b/chrome/chrome_cleaner/os/DEPS
deleted file mode 100644
index a7d4f73..0000000
--- a/chrome/chrome_cleaner/os/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
-  "+components/chrome_cleaner/public/constants",
-]
diff --git a/chrome/chrome_cleaner/parsers/DEPS b/chrome/chrome_cleaner/parsers/DEPS
deleted file mode 100644
index 093b1d9..0000000
--- a/chrome/chrome_cleaner/parsers/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
-  "+mojo/public/cpp",
-]
diff --git a/chrome/chrome_cleaner/settings/DEPS b/chrome/chrome_cleaner/settings/DEPS
deleted file mode 100644
index ef8ad28..0000000
--- a/chrome/chrome_cleaner/settings/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
-  "+mojo/public",
-]
diff --git a/chrome/common/extensions/api/downloads.idl b/chrome/common/extensions/api/downloads.idl
index bd0c9b4..4a49058 100644
--- a/chrome/common/extensions/api/downloads.idl
+++ b/chrome/common/extensions/api/downloads.idl
@@ -516,10 +516,6 @@
     // |callback|: Called when the danger prompt dialog closes.
     static void acceptDanger(long downloadId, optional NullCallback callback);
 
-    // Initiate dragging the downloaded file to another application. Call in a
-    // javascript <code>ondragstart</code> handler.
-    static void drag(long downloadId);
-
     // Enable or disable the gray shelf at the bottom of every window associated
     // with the current browser profile. The shelf will be disabled as long as
     // at least one extension has disabled it. Enabling the shelf while at least
diff --git a/chrome/common/extensions/docs/examples/api/downloads/download_manager/popup.js b/chrome/common/extensions/docs/examples/api/downloads/download_manager/popup.js
index 1f37123..412a3af 100644
--- a/chrome/common/extensions/docs/examples/api/downloads/download_manager/popup.js
+++ b/chrome/common/extensions/docs/examples/api/downloads/download_manager/popup.js
@@ -199,10 +199,6 @@
     item.open();
     return false;
   };
-  item.getElement('open-filename').ondragstart = function() {
-    item.drag();
-    return false;
-  };
   item.getElement('pause').onclick = function() {
     item.pause();
     return false;
@@ -450,10 +446,6 @@
   document.getElementById('items').removeChild(this.div);
 };
 
-DownloadItem.prototype.drag = function() {
-  chrome.downloads.drag(this.id);
-};
-
 DownloadItem.prototype.show = function() {
   chrome.downloads.show(this.id);
 };
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 591c345..4030cb5fe 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3925,6 +3925,7 @@
       "../browser/sharing/click_to_call/click_to_call_context_menu_observer_unittest.cc",
       "../browser/sharing/click_to_call/click_to_call_ui_controller_unittest.cc",
       "../browser/sharing/click_to_call/click_to_call_utils_unittest.cc",
+      "../browser/sharing/shared_clipboard/shared_clipboard_context_menu_observer_unittest.cc",
       "../browser/sharing/shared_clipboard/shared_clipboard_ui_controller_unittest.cc",
       "../browser/ui/autofill/payments/local_card_migration_bubble_controller_impl_unittest.cc",
       "../browser/ui/autofill/payments/save_card_bubble_controller_impl_unittest.cc",
@@ -4883,6 +4884,7 @@
       "../browser/ui/views/hover_button_unittest.cc",
       "../browser/ui/views/infobars/infobar_view_unittest.cc",
       "../browser/ui/views/intent_picker_bubble_view_unittest.cc",
+      "../browser/ui/views/layout/interpolating_layout_manager_unittest.cc",
       "../browser/ui/views/layout_provider_unittest.cc",
       "../browser/ui/views/location_bar/icon_label_bubble_view_unittest.cc",
       "../browser/ui/views/location_bar/location_icon_view_unittest.cc",
diff --git a/chrome/test/chromedriver/log_replay/client_replay.py b/chrome/test/chromedriver/log_replay/client_replay.py
index 315eb06..2405d35 100755
--- a/chrome/test/chromedriver/log_replay/client_replay.py
+++ b/chrome/test/chromedriver/log_replay/client_replay.py
@@ -748,8 +748,13 @@
           self._id_map[id_old] = id_new
         self._staged_logged_ids = None
 
-    if "sessionId" in response and self._staged_logged_session_id:
-      self._id_map[self._staged_logged_session_id] = response["sessionId"]
+    # In W3C format, the http response is a single key dict,
+    # where the value is another dictionary
+    # sessionId is contained in the nested dictionary
+    if ("value" in response and "sessionId" in response["value"]
+        and self._staged_logged_session_id):
+      self._id_map[self._staged_logged_session_id] = (
+        response["value"]["sessionId"])
       self._staged_logged_session_id = None
 
   def _IngestLoggedResponse(self, response):
diff --git a/chrome/test/chromedriver/log_replay/client_replay_unittest.py b/chrome/test/chromedriver/log_replay/client_replay_unittest.py
index 912bfb1..58dc576 100755
--- a/chrome/test/chromedriver/log_replay/client_replay_unittest.py
+++ b/chrome/test/chromedriver/log_replay/client_replay_unittest.py
@@ -116,6 +116,23 @@
     self.assertEqual(response.GetPayloadPrimitive(), {"param2": 42})
     self.assertEqual(response.session_id, _SESSION_ID)
 
+  def testIngestRealResponseInitSession(self):
+    real_resp = {u'value': {
+        u'sessionId': u'b15232d5497ec0d8300a5a1ea56f33ce',
+        u'capabilities': {
+            u'browserVersion': u'76.0.3809.100',
+            u'browserName': u'chrome',
+        }
+    }}
+
+    command_sequence = client_replay.CommandSequence()
+    command_sequence._staged_logged_session_id = _SESSION_ID_ALT
+    command_sequence._IngestRealResponse(real_resp)
+
+    self.assertEqual(
+        command_sequence._id_map[_SESSION_ID_ALT], _SESSION_ID)
+    self.assertEqual(command_sequence._staged_logged_session_id, None)
+
   def testGetPayload_simple(self):
     string_buffer = StringIO.StringIO(_RESPONSE_ONLY)
     header = string_buffer.readline()
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeEnabled-video_suggestion_with_dark_dominant_color.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeEnabled-video_suggestion_with_dark_dominant_color.Nexus_5-19.png.sha1
index ee627614a..8a3127ee 100644
--- a/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeEnabled-video_suggestion_with_dark_dominant_color.Nexus_5-19.png.sha1
+++ b/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeEnabled-video_suggestion_with_dark_dominant_color.Nexus_5-19.png.sha1
@@ -1 +1 @@
-b4ff7f7b88cbb4d7b73b370bb475a0c546b586fa
\ No newline at end of file
+95b1f25236225a4865abd94d1724bad724d7c3ef
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeEnabled-video_suggestion_with_dark_thumbnail.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeEnabled-video_suggestion_with_dark_thumbnail.Nexus_5-19.png.sha1
index 02ec298..61f80700 100644
--- a/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeEnabled-video_suggestion_with_dark_thumbnail.Nexus_5-19.png.sha1
+++ b/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeEnabled-video_suggestion_with_dark_thumbnail.Nexus_5-19.png.sha1
@@ -1 +1 @@
-d187a8ab5917cf503f85feeb78ba23cbd1f80ec0
\ No newline at end of file
+317dc3bff0867710f7bbe01e7875bee73bef2599
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeEnabled-video_suggestion_with_light_dominant_color.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeEnabled-video_suggestion_with_light_dominant_color.Nexus_5-19.png.sha1
index b82dacf..996efde 100644
--- a/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeEnabled-video_suggestion_with_light_dominant_color.Nexus_5-19.png.sha1
+++ b/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeEnabled-video_suggestion_with_light_dominant_color.Nexus_5-19.png.sha1
@@ -1 +1 @@
-e6a100f55ea3621417e8dc0afcd52c323aa5c79a
\ No newline at end of file
+14ac5323250ad7dd55f3e84bd4e852aa5a0544c3
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeEnabled-video_suggestion_with_light_thumbnail.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeEnabled-video_suggestion_with_light_thumbnail.Nexus_5-19.png.sha1
index 9048dc3c..9ecac9ba 100644
--- a/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeEnabled-video_suggestion_with_light_thumbnail.Nexus_5-19.png.sha1
+++ b/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeEnabled-video_suggestion_with_light_thumbnail.Nexus_5-19.png.sha1
@@ -1 +1 @@
-47112bbdb0b531bfb7fbf81d0ed6bcbe83574279
\ No newline at end of file
+028a4f7a66d38531661aaa613ba43807508dd16f
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/BookmarkTest.NightModeEnabled-bookmark_manager_folder_selected.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/BookmarkTest.NightModeEnabled-bookmark_manager_folder_selected.Nexus_5-19.png.sha1
index a71e4f3..01c9e20 100644
--- a/chrome/test/data/android/render_tests/BookmarkTest.NightModeEnabled-bookmark_manager_folder_selected.Nexus_5-19.png.sha1
+++ b/chrome/test/data/android/render_tests/BookmarkTest.NightModeEnabled-bookmark_manager_folder_selected.Nexus_5-19.png.sha1
@@ -1 +1 @@
-7c70275234e91d8d976305e3f191fc2014fa156f
\ No newline at end of file
+754e30663c932bb8439ba53a5674a5caf05bbda2
\ No newline at end of file
diff --git a/chrome/test/data/extensions/api_test/downloads/test.js b/chrome/test/data/extensions/api_test/downloads/test.js
index e10baea7..a29d9bf5 100644
--- a/chrome/test/data/extensions/api_test/downloads/test.js
+++ b/chrome/test/data/extensions/api_test/downloads/test.js
@@ -12,8 +12,8 @@
 
 var contents = [
   'download', 'search', 'pause', 'resume', 'cancel', 'getFileIcon', 'open',
-  'show', 'erase', 'acceptDanger', 'drag',
-  'onCreated', 'onChanged', 'onErased', 'onDeterminingFilename'];
+  'show', 'erase', 'acceptDanger', 'onCreated', 'onChanged', 'onErased',
+  'onDeterminingFilename'];
 
 if (!chrome.downloads ||
     !contains_all(chrome.downloads, contents)) {
diff --git a/chrome/test/data/webui/settings/a11y/tts_subpage_a11y_test.js b/chrome/test/data/webui/settings/a11y/tts_subpage_a11y_test.js
index cd0e10a..0d7e730 100644
--- a/chrome/test/data/webui/settings/a11y/tts_subpage_a11y_test.js
+++ b/chrome/test/data/webui/settings/a11y/tts_subpage_a11y_test.js
@@ -9,15 +9,31 @@
 
 // SettingsAccessibilityTest fixture.
 GEN_INCLUDE([
+  '//chrome/test/data/webui/polymer_browser_test_base.js',
   'settings_accessibility_test.js',
 ]);
 
+GEN('#include "chromeos/constants/chromeos_features.h"');
+
+// TODO(crbug/950007): refactor this into an OSSettingsAccessibilityTest class
 // eslint-disable-next-line no-var
-var TtsAccessibilityTest = class extends SettingsAccessibilityTest {
+var TtsAccessibilityTest = class extends PolymerTest {
   /** @override */
   get commandLineSwitches() {
     return ['enable-experimental-a11y-features'];
   }
+
+  /** @override */
+  get featureList() {
+    // Always test with SplitSettings on because the pages are the same in the
+    // legacy combined settings and we don't want to test everything twice.
+    return {enabled: ['chromeos::features::kSplitSettings']};
+  }
+
+  /** @override */
+  get browsePreload() {
+    return 'chrome://os-settings/';
+  }
 };
 
 AccessibilityTest.define('TtsAccessibilityTest', {
diff --git a/chrome/test/data/webui/settings/people_page_test.js b/chrome/test/data/webui/settings/people_page_test.js
index a3a82c0..0021ffb 100644
--- a/chrome/test/data/webui/settings/people_page_test.js
+++ b/chrome/test/data/webui/settings/people_page_test.js
@@ -33,9 +33,15 @@
         // UnifiedConsentUITest suite.
         unifiedConsentEnabled: false,
       });
+      if (cr.isChromeOS) {
+        loadTimeData.overrideValues({
+          // Account Manager is tested in the Chrome OS-specific section below.
+          isAccountManagerEnabled: false,
+        });
+      }
     });
 
-    setup(function() {
+    setup(async function() {
       browserProxy = new TestProfileInfoBrowserProxy();
       settings.ProfileInfoBrowserProxyImpl.instance_ = browserProxy;
 
@@ -47,14 +53,9 @@
       peoplePage.pageVisibility = settings.pageVisibility;
       document.body.appendChild(peoplePage);
 
-      return Promise
-          .all([
-            browserProxy.whenCalled('getProfileInfo'),
-            syncBrowserProxy.whenCalled('getSyncStatus')
-          ])
-          .then(function() {
-            Polymer.dom.flush();
-          });
+      await syncBrowserProxy.whenCalled('getSyncStatus');
+      await browserProxy.whenCalled('getProfileInfo');
+      Polymer.dom.flush();
     });
 
     teardown(function() {
@@ -587,18 +588,70 @@
   });
 
   if (cr.isChromeOS) {
-    suite('Chrome OS with SplitSettings', function() {
+    /** @implements {settings.AccountManagerBrowserProxy} */
+    class TestAccountManagerBrowserProxy extends TestBrowserProxy {
+      constructor() {
+        super([
+          'getAccounts',
+          'addAccount',
+          'reauthenticateAccount',
+          'removeAccount',
+          'showWelcomeDialogIfRequired',
+        ]);
+      }
+
+      /** @override */
+      getAccounts() {
+        this.methodCalled('getAccounts');
+        return Promise.resolve([{
+          id: '123',
+          accountType: 1,
+          isDeviceAccount: false,
+          isSignedIn: true,
+          unmigrated: false,
+          fullName: 'Primary Account',
+          email: 'user@gmail.com',
+          pic: 'data:image/png;base64,primaryAccountPicData',
+        }]);
+      }
+
+      /** @override */
+      addAccount() {
+        this.methodCalled('addAccount');
+      }
+
+      /** @override */
+      reauthenticateAccount(account_email) {
+        this.methodCalled('reauthenticateAccount', account_email);
+      }
+
+      /** @override */
+      removeAccount(account) {
+        this.methodCalled('removeAccount', account);
+      }
+
+      /** @override */
+      showWelcomeDialogIfRequired() {
+        this.methodCalled('showWelcomeDialogIfRequired');
+      }
+    }
+
+    suite('Chrome OS', function() {
       /** @type {SettingsPeoplePageElement} */
       let peoplePage = null;
       /** @type {settings.SyncBrowserProxy} */
       let browserProxy = null;
       /** @type {settings.ProfileInfoBrowserProxy} */
       let profileInfoBrowserProxy = null;
+      /** @type {settings.AccountManagerBrowserProxy} */
+      let accountManagerBrowserProxy = null;
 
       suiteSetup(function() {
         loadTimeData.overrideValues({
           // Simulate SplitSettings (OS settings in their own surface).
           showOSSettings: false,
+          // Simulate ChromeOSAccountManager (Google Accounts support).
+          isAccountManagerEnabled: true,
         });
       });
 
@@ -610,19 +663,33 @@
         settings.ProfileInfoBrowserProxyImpl.instance_ =
             profileInfoBrowserProxy;
 
+        accountManagerBrowserProxy = new TestAccountManagerBrowserProxy();
+        settings.AccountManagerBrowserProxyImpl.instance_ =
+            accountManagerBrowserProxy;
+
         PolymerTest.clearBody();
         peoplePage = document.createElement('settings-people-page');
         peoplePage.pageVisibility = settings.pageVisibility;
         document.body.appendChild(peoplePage);
 
-        Polymer.dom.flush();
+        await accountManagerBrowserProxy.whenCalled('getAccounts');
         await browserProxy.whenCalled('getSyncStatus');
+        Polymer.dom.flush();
       });
 
       teardown(function() {
         peoplePage.remove();
       });
 
+      test('GAIA name and picture', async () => {
+        chai.assert.include(
+            peoplePage.$$('#profile-icon').style.backgroundImage,
+            'data:image/png;base64,primaryAccountPicData');
+        assertEquals(
+            'Primary Account',
+            peoplePage.$$('#profile-name').textContent.trim());
+      });
+
       test('clicking profile row does not open change picture page', () => {
         // Simulate a signed-in user.
         sync_test_util.simulateSyncStatus({
diff --git a/chrome/updater/BUILD.gn b/chrome/updater/BUILD.gn
index edc93537..e161ec5 100644
--- a/chrome/updater/BUILD.gn
+++ b/chrome/updater/BUILD.gn
@@ -85,7 +85,7 @@
     ]
 
     if (is_win) {
-      deps += [ "//chrome/updater/win:unittest" ]
+      deps += [ "//chrome/updater/win:updater_tests" ]
 
       data_deps = [
         "//chrome/updater/win:updater",
diff --git a/chrome/updater/updater_constants.cc b/chrome/updater/updater_constants.cc
index ed9df7edd..281447b 100644
--- a/chrome/updater/updater_constants.cc
+++ b/chrome/updater/updater_constants.cc
@@ -11,6 +11,7 @@
 const char kInstall[] = "install";
 const char kUninstall[] = "uninstall";
 const char kTestSwitch[] = "test";
+const char kInitDoneNotifierSwitch[] = "init-done-notifier";
 
 const char kNoRateLimit[] = "--no-rate-limit";
 
diff --git a/chrome/updater/updater_constants.h b/chrome/updater/updater_constants.h
index 5fc5e69..37fadddf6 100644
--- a/chrome/updater/updater_constants.h
+++ b/chrome/updater/updater_constants.h
@@ -28,6 +28,10 @@
 // https://bugs.chromium.org/p/crashpad/issues/detail?id=23
 extern const char kNoRateLimit[];
 
+// The handle of an event to signal when the initialization of the main process
+// is complete.
+extern const char kInitDoneNotifierSwitch[];
+
 // URLs.
 //
 // Omaha server end point.
diff --git a/chrome/updater/win/BUILD.gn b/chrome/updater/win/BUILD.gn
index 8aaf244..d27a45fc 100644
--- a/chrome/updater/win/BUILD.gn
+++ b/chrome/updater/win/BUILD.gn
@@ -5,7 +5,7 @@
 import("//chrome/process_version_rc_template.gni")
 import("//testing/test.gni")
 
-# This target build the updater executable and its installer.
+# This target builds the updater executable, its installer, and unittests.
 group("win") {
   deps = [
     ":updater",
@@ -64,18 +64,29 @@
     "setup/setup.h",
     "setup/uninstall.cc",
     "setup/uninstall.h",
+    "task_scheduler.cc",
+    "task_scheduler.h",
     "util.cc",
     "util.h",
   ]
 
+  defines = [ "SECURITY_WIN32" ]
+
+  libs = [
+    "secur32.lib",
+    "taskschd.lib",
+  ]
+
   deps = [
     "//base",
     "//chrome/installer/util:with_no_strings",
+    "//chrome/updater:common",
     "//components/update_client",
   ]
 }
 
-source_set("unittest") {
+# Tests built into Chrome's unit_tests.exe.
+source_set("updater_tests") {
   testonly = true
 
   sources = [
@@ -90,6 +101,27 @@
   ]
 
   data_deps = [
+    ":updater_unittests",
     "//chrome/updater/win/installer:installer_unittest",
   ]
 }
+
+# Specific tests which must run in their own process due to COM, security, or
+# test isolation requirements.
+test("updater_unittests") {
+  testonly = true
+
+  sources = [
+    "//chrome/updater/win/test/test_main.cc",
+    "task_scheduler_unittest.cc",
+  ]
+
+  deps = [
+    ":code",
+    "//base",
+    "//base/test:test_support",
+    "//chrome/updater/win/test:test_executables",
+    "//chrome/updater/win/test:test_strings",
+    "//testing/gtest",
+  ]
+}
diff --git a/chrome/updater/win/task_scheduler.cc b/chrome/updater/win/task_scheduler.cc
new file mode 100644
index 0000000..bdbc206
--- /dev/null
+++ b/chrome/updater/win/task_scheduler.cc
@@ -0,0 +1,961 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/updater/win/task_scheduler.h"
+
+#include <mstask.h>
+#include <oleauto.h>
+#include <security.h>
+#include <taskschd.h>
+#include <wrl/client.h>
+
+#include <utility>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/native_library.h"
+#include "base/path_service.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string16.h"
+#include "base/strings/stringprintf.h"
+#include "base/time/time.h"
+#include "base/win/scoped_bstr.h"
+#include "base/win/scoped_co_mem.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/scoped_variant.h"
+#include "base/win/windows_version.h"
+#include "chrome/updater/win/util.h"
+
+namespace updater {
+
+namespace {
+
+// Names of the TaskSchedulerV2 libraries so we can pin them below.
+const wchar_t kV2Library[] = L"taskschd.dll";
+
+// Text for times used in the V2 API of the Task Scheduler.
+const wchar_t kOneHourText[] = L"PT1H";
+const wchar_t kFiveHoursText[] = L"PT5H";
+const wchar_t kZeroMinuteText[] = L"PT0M";
+const wchar_t kFifteenMinutesText[] = L"PT15M";
+const wchar_t kTwentyFourHoursText[] = L"PT24H";
+
+// Most of the users with pending logs succeeds within 7 days, so no need to
+// try for longer than that, especially for those who keep crashing.
+const int kNumDaysBeforeExpiry = 7;
+const size_t kNumDeleteTaskRetry = 3;
+const size_t kDeleteRetryDelayInMs = 100;
+
+// Return |timestamp| in the following string format YYYY-MM-DDTHH:MM:SS.
+base::string16 GetTimestampString(const base::Time& timestamp) {
+  base::Time::Exploded exploded_time;
+  // The Z timezone info at the end of the string means UTC.
+  timestamp.UTCExplode(&exploded_time);
+  return base::StringPrintf(L"%04d-%02d-%02dT%02d:%02d:%02dZ",
+                            exploded_time.year, exploded_time.month,
+                            exploded_time.day_of_month, exploded_time.hour,
+                            exploded_time.minute, exploded_time.second);
+}
+
+bool LocalSystemTimeToUTCFileTime(const SYSTEMTIME& system_time_local,
+                                  FILETIME* file_time_utc) {
+  DCHECK(file_time_utc);
+  SYSTEMTIME system_time_utc = {};
+  if (!::TzSpecificLocalTimeToSystemTime(nullptr, &system_time_local,
+                                         &system_time_utc) ||
+      !::SystemTimeToFileTime(&system_time_utc, file_time_utc)) {
+    PLOG(ERROR) << "Failed to convert local system time to UTC file time.";
+    return false;
+  }
+  return true;
+}
+
+bool UTCFileTimeToLocalSystemTime(const FILETIME& file_time_utc,
+                                  SYSTEMTIME* system_time_local) {
+  DCHECK(system_time_local);
+  SYSTEMTIME system_time_utc = {};
+  if (!::FileTimeToSystemTime(&file_time_utc, &system_time_utc) ||
+      !::SystemTimeToTzSpecificLocalTime(nullptr, &system_time_utc,
+                                         system_time_local)) {
+    PLOG(ERROR) << "Failed to convert file time to UTC local system.";
+    return false;
+  }
+  return true;
+}
+
+bool GetCurrentUser(base::win::ScopedBstr* user_name) {
+  DCHECK(user_name);
+  ULONG user_name_size = 256;
+  // Paranoia... ;-)
+  DCHECK_EQ(sizeof(OLECHAR), sizeof(WCHAR));
+  if (!::GetUserNameExW(
+          NameSamCompatible,
+          user_name->AllocateBytes(user_name_size * sizeof(OLECHAR)),
+          &user_name_size)) {
+    if (::GetLastError() != ERROR_MORE_DATA) {
+      PLOG(ERROR) << "GetUserNameEx failed.";
+      return false;
+    }
+    if (!::GetUserNameExW(
+            NameSamCompatible,
+            user_name->AllocateBytes(user_name_size * sizeof(OLECHAR)),
+            &user_name_size)) {
+      DCHECK_NE(static_cast<DWORD>(ERROR_MORE_DATA), ::GetLastError());
+      PLOG(ERROR) << "GetUserNameEx failed.";
+      return false;
+    }
+  }
+  return true;
+}
+
+void PinModule(const wchar_t* module_name) {
+  // Force the DLL to stay loaded until program termination. We have seen
+  // cases where it gets unloaded even though we still have references to
+  // the objects we just CoCreated.
+  base::NativeLibrary module_handle = nullptr;
+  if (!::GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN, module_name,
+                            &module_handle)) {
+    PLOG(ERROR) << "Failed to pin '" << module_name << "'.";
+  }
+}
+
+// A task scheduler class uses the V2 API of the task scheduler.
+class TaskSchedulerV2 final : public TaskScheduler {
+ public:
+  static bool Initialize() {
+    DCHECK(!task_service_);
+    DCHECK(!root_task_folder_);
+
+    HRESULT hr =
+        ::CoCreateInstance(CLSID_TaskScheduler, nullptr, CLSCTX_INPROC_SERVER,
+                           IID_PPV_ARGS(&task_service_));
+    if (FAILED(hr)) {
+      PLOG(ERROR) << "CreateInstance failed for CLSID_TaskScheduler. "
+                  << std::hex << hr;
+      return false;
+    }
+    hr = task_service_->Connect(base::win::ScopedVariant::kEmptyVariant,
+                                base::win::ScopedVariant::kEmptyVariant,
+                                base::win::ScopedVariant::kEmptyVariant,
+                                base::win::ScopedVariant::kEmptyVariant);
+    if (FAILED(hr)) {
+      PLOG(ERROR) << "Failed to connect to task service. " << std::hex << hr;
+      return false;
+    }
+    hr = task_service_->GetFolder(base::win::ScopedBstr(L"\\"),
+                                  &root_task_folder_);
+    if (FAILED(hr)) {
+      LOG(ERROR) << "Can't get task service folder. " << std::hex << hr;
+      return false;
+    }
+    PinModule(kV2Library);
+    return true;
+  }
+
+  static void Terminate() {
+    root_task_folder_.Reset();
+    task_service_.Reset();
+  }
+
+  TaskSchedulerV2() {
+    DCHECK(task_service_);
+    DCHECK(root_task_folder_);
+  }
+
+  // TaskScheduler overrides.
+  bool IsTaskRegistered(const wchar_t* task_name) override {
+    DCHECK(task_name);
+    if (!root_task_folder_)
+      return false;
+
+    return GetTask(task_name, nullptr);
+  }
+
+  bool GetNextTaskRunTime(const wchar_t* task_name,
+                          base::Time* next_run_time) override {
+    DCHECK(task_name);
+    DCHECK(next_run_time);
+    if (!root_task_folder_)
+      return false;
+
+    Microsoft::WRL::ComPtr<IRegisteredTask> registered_task;
+    if (!GetTask(task_name, &registered_task))
+      return false;
+
+    // We unfortunately can't use get_NextRunTime because of a known bug which
+    // requires hotfix: http://support.microsoft.com/kb/2495489/en-us. So fetch
+    // one of the run times in the next day.
+    // Also, although it's not obvious from MSDN, IRegisteredTask::GetRunTimes
+    // expects local time.
+    SYSTEMTIME start_system_time = {};
+    GetLocalTime(&start_system_time);
+
+    base::Time tomorrow(base::Time::NowFromSystemTime() +
+                        base::TimeDelta::FromDays(1));
+    SYSTEMTIME end_system_time = {};
+    if (!UTCFileTimeToLocalSystemTime(tomorrow.ToFileTime(), &end_system_time))
+      return false;
+
+    DWORD num_run_times = 1;
+    SYSTEMTIME* raw_run_times = nullptr;
+    HRESULT hr = registered_task->GetRunTimes(
+        &start_system_time, &end_system_time, &num_run_times, &raw_run_times);
+    if (FAILED(hr)) {
+      PLOG(ERROR) << "Failed to GetRunTimes, " << std::hex << hr;
+      return false;
+    }
+
+    if (num_run_times == 0)
+      return false;
+
+    base::win::ScopedCoMem<SYSTEMTIME> run_times;
+    run_times.Reset(raw_run_times);
+    // Again, although unclear from MSDN, IRegisteredTask::GetRunTimes returns
+    // local times.
+    FILETIME file_time = {};
+    if (!LocalSystemTimeToUTCFileTime(run_times[0], &file_time))
+      return false;
+    *next_run_time = base::Time::FromFileTime(file_time);
+    return true;
+  }
+
+  bool SetTaskEnabled(const wchar_t* task_name, bool enabled) override {
+    DCHECK(task_name);
+    if (!root_task_folder_)
+      return false;
+
+    Microsoft::WRL::ComPtr<IRegisteredTask> registered_task;
+    if (!GetTask(task_name, &registered_task)) {
+      LOG(ERROR) << "Failed to find the task " << task_name
+                 << " to enable/disable";
+      return false;
+    }
+
+    HRESULT hr;
+    hr = registered_task->put_Enabled(enabled ? VARIANT_TRUE : VARIANT_FALSE);
+    if (FAILED(hr)) {
+      PLOG(ERROR) << "Failed to set enabled status of task named " << task_name
+                  << ". " << std::hex << hr;
+      return false;
+    }
+    return true;
+  }
+
+  bool IsTaskEnabled(const wchar_t* task_name) override {
+    DCHECK(task_name);
+    if (!root_task_folder_)
+      return false;
+
+    Microsoft::WRL::ComPtr<IRegisteredTask> registered_task;
+    if (!GetTask(task_name, &registered_task))
+      return false;
+
+    HRESULT hr;
+    VARIANT_BOOL is_enabled;
+    hr = registered_task->get_Enabled(&is_enabled);
+    if (FAILED(hr)) {
+      LOG(ERROR) << "Failed to get enabled status for task named " << task_name
+                 << ". " << std::hex << hr << ": "
+                 << logging::SystemErrorCodeToString(hr);
+      return false;
+    }
+
+    return is_enabled == VARIANT_TRUE;
+  }
+
+  bool GetTaskNameList(std::vector<base::string16>* task_names) override {
+    DCHECK(task_names);
+    if (!root_task_folder_)
+      return false;
+
+    for (TaskIterator it(root_task_folder_.Get()); !it.done(); it.Next())
+      task_names->push_back(it.name());
+    return true;
+  }
+
+  bool GetTaskInfo(const wchar_t* task_name, TaskInfo* info) override {
+    DCHECK(task_name);
+    DCHECK(info);
+    if (!root_task_folder_)
+      return false;
+
+    Microsoft::WRL::ComPtr<IRegisteredTask> registered_task;
+    if (!GetTask(task_name, &registered_task))
+      return false;
+
+    // Collect information into internal storage to ensure that we start with
+    // a clean slate and don't return partial results on error.
+    TaskInfo info_storage;
+    HRESULT hr =
+        GetTaskDescription(registered_task.Get(), &info_storage.description);
+    if (FAILED(hr)) {
+      LOG(ERROR) << "Failed to get description for task '" << task_name << "'. "
+                 << std::hex << hr << ": "
+                 << logging::SystemErrorCodeToString(hr);
+      return false;
+    }
+
+    if (!GetTaskExecActions(registered_task.Get(),
+                            &info_storage.exec_actions)) {
+      LOG(ERROR) << "Failed to get actions for task '" << task_name << "'";
+      return false;
+    }
+
+    hr = GetTaskLogonType(registered_task.Get(), &info_storage.logon_type);
+    if (FAILED(hr)) {
+      LOG(ERROR) << "Failed to get logon type for task '" << task_name << "'. "
+                 << std::hex << hr << ": "
+                 << logging::SystemErrorCodeToString(hr);
+      return false;
+    }
+    info_storage.name = task_name;
+    std::swap(*info, info_storage);
+    return true;
+  }
+
+  bool DeleteTask(const wchar_t* task_name) override {
+    DCHECK(task_name);
+    if (!root_task_folder_)
+      return false;
+
+    VLOG(1) << "Delete Task '" << task_name << "'.";
+
+    HRESULT hr =
+        root_task_folder_->DeleteTask(base::win::ScopedBstr(task_name), 0);
+    // This can happen, e.g., while running tests, when the file system stresses
+    // quite a lot. Give it a few more chances to succeed.
+    size_t num_retries_left = kNumDeleteTaskRetry;
+
+    if (FAILED(hr)) {
+      while ((hr == HRESULT_FROM_WIN32(ERROR_TRANSACTION_NOT_ACTIVE) ||
+              hr == HRESULT_FROM_WIN32(ERROR_TRANSACTION_ALREADY_ABORTED)) &&
+             --num_retries_left && IsTaskRegistered(task_name)) {
+        LOG(WARNING) << "Retrying delete task because transaction not active, "
+                     << std::hex << hr << ".";
+        hr = root_task_folder_->DeleteTask(base::win::ScopedBstr(task_name), 0);
+        ::Sleep(kDeleteRetryDelayInMs);
+      }
+      if (!IsTaskRegistered(task_name))
+        hr = S_OK;
+    }
+
+    if (FAILED(hr) && hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) {
+      PLOG(ERROR) << "Can't delete task. " << std::hex << hr;
+      return false;
+    }
+
+    DCHECK(!IsTaskRegistered(task_name));
+    return true;
+  }
+
+  bool RegisterTask(const wchar_t* task_name,
+                    const wchar_t* task_description,
+                    const base::CommandLine& run_command,
+                    TriggerType trigger_type,
+                    bool hidden) override {
+    DCHECK(task_name);
+    DCHECK(task_description);
+    if (!DeleteTask(task_name))
+      return false;
+
+    // Create the task definition object to create the task.
+    Microsoft::WRL::ComPtr<ITaskDefinition> task;
+    DCHECK(task_service_);
+    HRESULT hr = task_service_->NewTask(0, &task);
+    if (FAILED(hr)) {
+      PLOG(ERROR) << "Can't create new task. " << std::hex << hr;
+      return false;
+    }
+
+    base::win::ScopedBstr user_name;
+    if (!GetCurrentUser(&user_name))
+      return false;
+
+    if (trigger_type != TRIGGER_TYPE_NOW) {
+      // Allow the task to run elevated on startup.
+      Microsoft::WRL::ComPtr<IPrincipal> principal;
+      hr = task->get_Principal(&principal);
+      if (FAILED(hr)) {
+        PLOG(ERROR) << "Can't get principal. " << std::hex << hr;
+        return false;
+      }
+
+      hr = principal->put_UserId(user_name);
+      if (FAILED(hr)) {
+        PLOG(ERROR) << "Can't put user id. " << std::hex << hr;
+        return false;
+      }
+
+      hr = principal->put_LogonType(TASK_LOGON_INTERACTIVE_TOKEN);
+      if (FAILED(hr)) {
+        PLOG(ERROR) << "Can't put logon type. " << std::hex << hr;
+        return false;
+      }
+    }
+
+    Microsoft::WRL::ComPtr<IRegistrationInfo> registration_info;
+    hr = task->get_RegistrationInfo(&registration_info);
+    if (FAILED(hr)) {
+      PLOG(ERROR) << "Can't get registration info. " << std::hex << hr;
+      return false;
+    }
+
+    hr = registration_info->put_Author(user_name);
+    if (FAILED(hr)) {
+      PLOG(ERROR) << "Can't set registration info author. " << std::hex << hr;
+      return false;
+    }
+
+    base::win::ScopedBstr description(task_description);
+    hr = registration_info->put_Description(description);
+    if (FAILED(hr)) {
+      PLOG(ERROR) << "Can't set description. " << std::hex << hr;
+      return false;
+    }
+
+    Microsoft::WRL::ComPtr<ITaskSettings> task_settings;
+    hr = task->get_Settings(&task_settings);
+    if (FAILED(hr)) {
+      PLOG(ERROR) << "Can't get task settings. " << std::hex << hr;
+      return false;
+    }
+
+    hr = task_settings->put_StartWhenAvailable(VARIANT_TRUE);
+    if (FAILED(hr)) {
+      PLOG(ERROR) << "Can't put 'StartWhenAvailable' to true. " << std::hex
+                  << hr;
+      return false;
+    }
+
+    // TODO(csharp): Find a way to only set this for log upload retry.
+    hr = task_settings->put_DeleteExpiredTaskAfter(
+        base::win::ScopedBstr(kZeroMinuteText));
+    if (FAILED(hr)) {
+      PLOG(ERROR) << "Can't put 'DeleteExpiredTaskAfter'. " << std::hex << hr;
+      return false;
+    }
+
+    hr = task_settings->put_DisallowStartIfOnBatteries(VARIANT_FALSE);
+    if (FAILED(hr)) {
+      PLOG(ERROR) << "Can't put 'DisallowStartIfOnBatteries' to false. "
+                  << std::hex << hr;
+      return false;
+    }
+
+    hr = task_settings->put_StopIfGoingOnBatteries(VARIANT_FALSE);
+    if (FAILED(hr)) {
+      PLOG(ERROR) << "Can't put 'StopIfGoingOnBatteries' to false. " << std::hex
+                  << hr;
+      return false;
+    }
+
+    if (hidden) {
+      hr = task_settings->put_Hidden(VARIANT_TRUE);
+      if (FAILED(hr)) {
+        PLOG(ERROR) << "Can't put 'Hidden' to true. " << std::hex << hr;
+        return false;
+      }
+    }
+
+    Microsoft::WRL::ComPtr<ITriggerCollection> trigger_collection;
+    hr = task->get_Triggers(&trigger_collection);
+    if (FAILED(hr)) {
+      PLOG(ERROR) << "Can't get trigger collection. " << std::hex << hr;
+      return false;
+    }
+
+    TASK_TRIGGER_TYPE2 task_trigger_type = TASK_TRIGGER_EVENT;
+    base::win::ScopedBstr repetition_interval;
+    switch (trigger_type) {
+      case TRIGGER_TYPE_POST_REBOOT:
+        task_trigger_type = TASK_TRIGGER_LOGON;
+        break;
+      case TRIGGER_TYPE_NOW:
+        task_trigger_type = TASK_TRIGGER_REGISTRATION;
+        break;
+      case TRIGGER_TYPE_HOURLY:
+      case TRIGGER_TYPE_EVERY_FIVE_HOURS:
+        task_trigger_type = TASK_TRIGGER_DAILY;
+        if (trigger_type == TRIGGER_TYPE_EVERY_FIVE_HOURS) {
+          repetition_interval.Reset(::SysAllocString(kFiveHoursText));
+        } else if (trigger_type == TRIGGER_TYPE_HOURLY) {
+          repetition_interval.Reset(::SysAllocString(kOneHourText));
+        } else {
+          NOTREACHED() << "Unknown TriggerType?";
+        }
+        break;
+      default:
+        NOTREACHED() << "Unknown TriggerType?";
+    }
+
+    Microsoft::WRL::ComPtr<ITrigger> trigger;
+    hr = trigger_collection->Create(task_trigger_type, &trigger);
+    if (FAILED(hr)) {
+      PLOG(ERROR) << "Can't create trigger of type " << task_trigger_type
+                  << ". " << std::hex << hr;
+      return false;
+    }
+
+    if (trigger_type == TRIGGER_TYPE_HOURLY ||
+        trigger_type == TRIGGER_TYPE_EVERY_FIVE_HOURS) {
+      Microsoft::WRL::ComPtr<IDailyTrigger> daily_trigger;
+      hr = trigger.As(&daily_trigger);
+      if (FAILED(hr)) {
+        PLOG(ERROR) << "Can't Query for registration trigger. " << std::hex
+                    << hr;
+        return false;
+      }
+
+      hr = daily_trigger->put_DaysInterval(1);
+      if (FAILED(hr)) {
+        PLOG(ERROR) << "Can't put 'DaysInterval' to 1, " << std::hex << hr;
+        return false;
+      }
+
+      Microsoft::WRL::ComPtr<IRepetitionPattern> repetition_pattern;
+      hr = trigger->get_Repetition(&repetition_pattern);
+      if (FAILED(hr)) {
+        PLOG(ERROR) << "Can't get 'Repetition'. " << std::hex << hr;
+        return false;
+      }
+
+      // The duration is the time to keep repeating until the next daily
+      // trigger.
+      hr = repetition_pattern->put_Duration(
+          base::win::ScopedBstr(kTwentyFourHoursText));
+      if (FAILED(hr)) {
+        PLOG(ERROR) << "Can't put 'Duration' to " << kTwentyFourHoursText
+                    << ". " << std::hex << hr;
+        return false;
+      }
+
+      hr = repetition_pattern->put_Interval(repetition_interval);
+      if (FAILED(hr)) {
+        PLOG(ERROR) << "Can't put 'Interval' to " << repetition_interval << ". "
+                    << std::hex << hr;
+        return false;
+      }
+
+      // Start now.
+      base::Time now(base::Time::NowFromSystemTime());
+      base::win::ScopedBstr start_boundary(GetTimestampString(now));
+      hr = trigger->put_StartBoundary(start_boundary);
+      if (FAILED(hr)) {
+        PLOG(ERROR) << "Can't put 'StartBoundary' to " << start_boundary << ". "
+                    << std::hex << hr;
+        return false;
+      }
+    }
+
+    if (trigger_type == TRIGGER_TYPE_POST_REBOOT) {
+      Microsoft::WRL::ComPtr<ILogonTrigger> logon_trigger;
+      hr = trigger.As(&logon_trigger);
+      if (FAILED(hr)) {
+        PLOG(ERROR) << "Can't query trigger for 'ILogonTrigger'. " << std::hex
+                    << hr;
+        return false;
+      }
+
+      hr = logon_trigger->put_Delay(base::win::ScopedBstr(kFifteenMinutesText));
+      if (FAILED(hr)) {
+        PLOG(ERROR) << "Can't put 'Delay'. " << std::hex << hr;
+        return false;
+      }
+    }
+
+    // None of the triggers should go beyond kNumDaysBeforeExpiry.
+    base::Time expiry_date(base::Time::NowFromSystemTime() +
+                           base::TimeDelta::FromDays(kNumDaysBeforeExpiry));
+    base::win::ScopedBstr end_boundary(GetTimestampString(expiry_date));
+    hr = trigger->put_EndBoundary(end_boundary);
+    if (FAILED(hr)) {
+      PLOG(ERROR) << "Can't put 'EndBoundary' to " << end_boundary << ". "
+                  << std::hex << hr;
+      return false;
+    }
+
+    Microsoft::WRL::ComPtr<IActionCollection> actions;
+    hr = task->get_Actions(&actions);
+    if (FAILED(hr)) {
+      PLOG(ERROR) << "Can't get actions collection. " << std::hex << hr;
+      return false;
+    }
+
+    Microsoft::WRL::ComPtr<IAction> action;
+    hr = actions->Create(TASK_ACTION_EXEC, &action);
+    if (FAILED(hr)) {
+      PLOG(ERROR) << "Can't create exec action. " << std::hex << hr;
+      return false;
+    }
+
+    Microsoft::WRL::ComPtr<IExecAction> exec_action;
+    hr = action.As(&exec_action);
+    if (FAILED(hr)) {
+      PLOG(ERROR) << "Can't query for exec action. " << std::hex << hr;
+      return false;
+    }
+
+    base::win::ScopedBstr path(run_command.GetProgram().value());
+    hr = exec_action->put_Path(path);
+    if (FAILED(hr)) {
+      PLOG(ERROR) << "Can't set path of exec action. " << std::hex << hr;
+      return false;
+    }
+
+    base::win::ScopedBstr args(run_command.GetArgumentsString());
+    hr = exec_action->put_Arguments(args);
+    if (FAILED(hr)) {
+      PLOG(ERROR) << "Can't set arguments of exec action. " << std::hex << hr;
+      return false;
+    }
+
+    Microsoft::WRL::ComPtr<IRegisteredTask> registered_task;
+    base::win::ScopedVariant user(user_name);
+
+    DCHECK(root_task_folder_);
+    hr = root_task_folder_->RegisterTaskDefinition(
+        base::win::ScopedBstr(task_name), task.Get(), TASK_CREATE,
+        *user.AsInput(),  // Not really input, but API expect non-const.
+        base::win::ScopedVariant::kEmptyVariant, TASK_LOGON_NONE,
+        base::win::ScopedVariant::kEmptyVariant, &registered_task);
+    if (FAILED(hr)) {
+      LOG(ERROR) << "RegisterTaskDefinition failed. " << std::hex << hr << ": "
+                 << logging::SystemErrorCodeToString(hr);
+      return false;
+    }
+
+    DCHECK(IsTaskRegistered(task_name));
+
+    VLOG(1) << "Successfully registered: "
+            << run_command.GetCommandLineString();
+    return true;
+  }
+
+ private:
+  // Helper class that lets us iterate over all registered tasks.
+  class TaskIterator {
+   public:
+    explicit TaskIterator(ITaskFolder* task_folder) {
+      DCHECK(task_folder);
+      HRESULT hr = task_folder->GetTasks(TASK_ENUM_HIDDEN, &tasks_);
+      if (FAILED(hr)) {
+        PLOG(ERROR) << "Failed to get registered tasks from folder. "
+                    << std::hex << hr;
+        done_ = true;
+        return;
+      }
+      hr = tasks_->get_Count(&num_tasks_);
+      if (FAILED(hr)) {
+        PLOG(ERROR) << "Failed to get registered tasks count. " << std::hex
+                    << hr;
+        done_ = true;
+        return;
+      }
+      Next();
+    }
+
+    // Increment to the next valid item in the task list. Skip entries for
+    // which we cannot retrieve a name.
+    void Next() {
+      DCHECK(!done_);
+      task_.Reset();
+      name_.clear();
+      if (++task_index_ >= num_tasks_) {
+        done_ = true;
+        return;
+      }
+
+      // Note: get_Item uses 1 based indices.
+      HRESULT hr =
+          tasks_->get_Item(base::win::ScopedVariant(task_index_ + 1), &task_);
+      if (FAILED(hr)) {
+        PLOG(ERROR) << "Failed to get task at index: " << task_index_ << ". "
+                    << std::hex << hr;
+        Next();
+        return;
+      }
+
+      base::win::ScopedBstr task_name_bstr;
+      hr = task_->get_Name(task_name_bstr.Receive());
+      if (FAILED(hr)) {
+        PLOG(ERROR) << "Failed to get name at index: " << task_index_ << ". "
+                    << std::hex << hr;
+        Next();
+        return;
+      }
+      name_ = base::string16(task_name_bstr ? task_name_bstr : L"");
+    }
+
+    // Detach the currently active task and pass ownership to the caller.
+    // After this method has been called, the -> operator must no longer be
+    // used.
+    IRegisteredTask* Detach() { return task_.Detach(); }
+
+    // Provide access to the current task.
+    IRegisteredTask* operator->() const {
+      IRegisteredTask* result = task_.Get();
+      DCHECK(result);
+      return result;
+    }
+
+    const base::string16& name() const { return name_; }
+    bool done() const { return done_; }
+
+   private:
+    Microsoft::WRL::ComPtr<IRegisteredTaskCollection> tasks_;
+    Microsoft::WRL::ComPtr<IRegisteredTask> task_;
+    base::string16 name_;
+    long task_index_ = -1;  // NOLINT, API requires a long.
+    long num_tasks_ = 0;    // NOLINT, API requires a long.
+    bool done_ = false;
+  };
+
+  // Return the task with |task_name| and false if not found. |task| can be null
+  // when only interested in task's existence.
+  bool GetTask(const wchar_t* task_name, IRegisteredTask** task) {
+    for (TaskIterator it(root_task_folder_.Get()); !it.done(); it.Next()) {
+      if (::_wcsicmp(it.name().c_str(), task_name) == 0) {
+        if (task)
+          *task = it.Detach();
+        return true;
+      }
+    }
+    return false;
+  }
+
+  // Return the description of the task.
+  HRESULT GetTaskDescription(IRegisteredTask* task,
+                             base::string16* description) {
+    DCHECK(task);
+    DCHECK(description);
+
+    base::win::ScopedBstr task_name_bstr;
+    HRESULT hr = task->get_Name(task_name_bstr.Receive());
+    base::string16 task_name =
+        base::string16(task_name_bstr ? task_name_bstr : L"");
+    if (FAILED(hr)) {
+      LOG(ERROR) << "Failed to get task name";
+    }
+
+    Microsoft::WRL::ComPtr<ITaskDefinition> task_info;
+    hr = task->get_Definition(&task_info);
+    if (FAILED(hr)) {
+      LOG(ERROR) << "Failed to get definition for task, " << task_name << ": "
+                 << logging::SystemErrorCodeToString(hr);
+      return hr;
+    }
+
+    Microsoft::WRL::ComPtr<IRegistrationInfo> reg_info;
+    hr = task_info->get_RegistrationInfo(&reg_info);
+    if (FAILED(hr)) {
+      LOG(ERROR) << "Failed to get registration info, " << task_name << ": "
+                 << logging::SystemErrorCodeToString(hr);
+      return hr;
+    }
+
+    base::win::ScopedBstr raw_description;
+    hr = reg_info->get_Description(raw_description.Receive());
+    if (FAILED(hr)) {
+      LOG(ERROR) << "Failed to get description, " << task_name << ": "
+                 << logging::SystemErrorCodeToString(hr);
+      return hr;
+    }
+    *description = base::string16(raw_description ? raw_description : L"");
+    return ERROR_SUCCESS;
+  }
+
+  // Return all executable actions associated with the given task. Non-exec
+  // actions are silently ignored.
+  bool GetTaskExecActions(IRegisteredTask* task,
+                          std::vector<TaskExecAction>* actions) {
+    DCHECK(task);
+    DCHECK(actions);
+    Microsoft::WRL::ComPtr<ITaskDefinition> task_definition;
+    HRESULT hr = task->get_Definition(&task_definition);
+    if (FAILED(hr)) {
+      PLOG(ERROR) << "Failed to get definition of task, " << std::hex << hr;
+      return false;
+    }
+
+    Microsoft::WRL::ComPtr<IActionCollection> action_collection;
+    hr = task_definition->get_Actions(&action_collection);
+    if (FAILED(hr)) {
+      PLOG(ERROR) << "Failed to get action collection, " << std::hex << hr;
+      return false;
+    }
+
+    long actions_count = 0;  // NOLINT, API requires a long.
+    hr = action_collection->get_Count(&actions_count);
+    if (FAILED(hr)) {
+      PLOG(ERROR) << "Failed to get number of actions, " << std::hex << hr;
+      return false;
+    }
+
+    // Find and return as many exec actions as possible in |actions| and return
+    // false if there were any errors on the way. Note that the indexing of
+    // actions is 1-based.
+    bool success = true;
+    for (long action_index = 1;  // NOLINT
+         action_index <= actions_count; ++action_index) {
+      Microsoft::WRL::ComPtr<IAction> action;
+      hr = action_collection->get_Item(action_index, &action);
+      if (FAILED(hr)) {
+        PLOG(ERROR) << "Failed to get action at index " << action_index << ", "
+                    << std::hex << hr;
+        success = false;
+        continue;
+      }
+
+      ::TASK_ACTION_TYPE action_type;
+      hr = action->get_Type(&action_type);
+      if (FAILED(hr)) {
+        PLOG(ERROR) << "Failed to get the type of action at index "
+                    << action_index << ", " << std::hex << hr;
+        success = false;
+        continue;
+      }
+
+      // We only care about exec actions for now. The other types are
+      // TASK_ACTION_COM_HANDLER, TASK_ACTION_SEND_EMAIL,
+      // TASK_ACTION_SHOW_MESSAGE. The latter two are marked as deprecated in
+      // the Task Scheduler's GUI.
+      if (action_type != ::TASK_ACTION_EXEC)
+        continue;
+
+      Microsoft::WRL::ComPtr<IExecAction> exec_action;
+      hr = action.As(&exec_action);
+      if (FAILED(hr)) {
+        PLOG(ERROR) << "Failed to query from action, " << std::hex << hr;
+        success = false;
+        continue;
+      }
+
+      base::win::ScopedBstr application_path;
+      hr = exec_action->get_Path(application_path.Receive());
+      if (FAILED(hr)) {
+        PLOG(ERROR) << "Failed to get path from action, " << std::hex << hr;
+        success = false;
+        continue;
+      }
+
+      base::win::ScopedBstr working_dir;
+      hr = exec_action->get_WorkingDirectory(working_dir.Receive());
+      if (FAILED(hr)) {
+        PLOG(ERROR) << "Failed to get working directory for action, "
+                    << std::hex << hr;
+        success = false;
+        continue;
+      }
+
+      base::win::ScopedBstr parameters;
+      hr = exec_action->get_Arguments(parameters.Receive());
+      if (FAILED(hr)) {
+        PLOG(ERROR) << "Failed to get arguments from action of task, "
+                    << std::hex << hr;
+        success = false;
+        continue;
+      }
+
+      actions->push_back(
+          {base::FilePath(application_path ? application_path : L""),
+           base::FilePath(working_dir ? working_dir : L""),
+           base::string16(parameters ? parameters : L"")});
+    }
+    return success;
+  }
+
+  // Return the log-on type required for the task's actions to be run.
+  HRESULT GetTaskLogonType(IRegisteredTask* task, uint32_t* logon_type) {
+    DCHECK(task);
+    DCHECK(logon_type);
+    Microsoft::WRL::ComPtr<ITaskDefinition> task_info;
+    HRESULT hr = task->get_Definition(&task_info);
+    if (FAILED(hr)) {
+      LOG(ERROR) << "Failed to get definition, " << std::hex << hr << ": "
+                 << logging::SystemErrorCodeToString(hr);
+      return hr;
+    }
+
+    Microsoft::WRL::ComPtr<IPrincipal> principal;
+    hr = task_info->get_Principal(&principal);
+    if (FAILED(hr)) {
+      LOG(ERROR) << "Failed to get principal info, " << std::hex << hr << ": "
+                 << logging::SystemErrorCodeToString(hr);
+      return hr;
+    }
+
+    TASK_LOGON_TYPE raw_logon_type;
+    hr = principal->get_LogonType(&raw_logon_type);
+    if (FAILED(hr)) {
+      LOG(ERROR) << "Failed to get logon type info, " << std::hex << hr << ": "
+                 << logging::SystemErrorCodeToString(hr);
+      return hr;
+    }
+
+    switch (raw_logon_type) {
+      case TASK_LOGON_INTERACTIVE_TOKEN:
+        *logon_type = LOGON_INTERACTIVE;
+        break;
+      case TASK_LOGON_GROUP:     // fall-thru
+      case TASK_LOGON_PASSWORD:  // fall-thru
+      case TASK_LOGON_SERVICE_ACCOUNT:
+        *logon_type = LOGON_SERVICE;
+        break;
+      case TASK_LOGON_S4U:
+        *logon_type = LOGON_SERVICE | LOGON_S4U;
+        break;
+      case TASK_LOGON_INTERACTIVE_TOKEN_OR_PASSWORD:
+        *logon_type = LOGON_INTERACTIVE | LOGON_SERVICE;
+        break;
+      default:
+        *logon_type = LOGON_UNKNOWN;
+        break;
+    }
+    return ERROR_SUCCESS;
+  }
+
+  static Microsoft::WRL::ComPtr<ITaskService> task_service_;
+  static Microsoft::WRL::ComPtr<ITaskFolder> root_task_folder_;
+
+  DISALLOW_COPY_AND_ASSIGN(TaskSchedulerV2);
+};
+
+Microsoft::WRL::ComPtr<ITaskService> TaskSchedulerV2::task_service_;
+Microsoft::WRL::ComPtr<ITaskFolder> TaskSchedulerV2::root_task_folder_;
+
+}  // namespace
+
+TaskScheduler::TaskInfo::TaskInfo() = default;
+
+TaskScheduler::TaskInfo::TaskInfo(const TaskScheduler::TaskInfo&) = default;
+
+TaskScheduler::TaskInfo::TaskInfo(TaskScheduler::TaskInfo&&) = default;
+
+TaskScheduler::TaskInfo& TaskScheduler::TaskInfo::operator=(
+    const TaskScheduler::TaskInfo&) = default;
+
+TaskScheduler::TaskInfo& TaskScheduler::TaskInfo::operator=(
+    TaskScheduler::TaskInfo&&) = default;
+
+TaskScheduler::TaskInfo::~TaskInfo() = default;
+
+// static.
+bool TaskScheduler::Initialize() {
+  return TaskSchedulerV2::Initialize();
+}
+
+// static.
+void TaskScheduler::Terminate() {
+  TaskSchedulerV2::Terminate();
+}
+
+// static.
+std::unique_ptr<TaskScheduler> TaskScheduler::CreateInstance() {
+  return std::make_unique<TaskSchedulerV2>();
+}
+
+TaskScheduler::TaskScheduler() = default;
+
+}  // namespace updater
diff --git a/chrome/updater/win/task_scheduler.h b/chrome/updater/win/task_scheduler.h
new file mode 100644
index 0000000..2708621
--- /dev/null
+++ b/chrome/updater/win/task_scheduler.h
@@ -0,0 +1,141 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_UPDATER_WIN_TASK_SCHEDULER_H_
+#define CHROME_UPDATER_WIN_TASK_SCHEDULER_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+
+namespace base {
+class CommandLine;
+class Time;
+}  // namespace base
+
+namespace updater {
+
+// This class wraps a scheduled task and expose an API to parametrize a task
+// before calling |Register|, or to verify its existence, or delete it.
+class TaskScheduler {
+ public:
+  // The type of trigger to register for this task.
+  enum TriggerType {
+    TRIGGER_TYPE_POST_REBOOT = 0,  // Only run once post-reboot.
+    TRIGGER_TYPE_NOW = 1,          // Run right now (mainly for tests).
+    TRIGGER_TYPE_HOURLY = 2,       // Run every hour.
+    TRIGGER_TYPE_EVERY_FIVE_HOURS = 3,
+    TRIGGER_TYPE_MAX,
+  };
+
+  // The log-on requirements for a task to be scheduled. Note that a task can
+  // have both the interactive and service bit set. In that case the
+  // interactive token will be used when available, and a stored password
+  // otherwise.
+  enum LogonType {
+    LOGON_UNKNOWN = 0,
+
+    // Run the task with the user's interactive token when logged in.
+    LOGON_INTERACTIVE = 1 << 0,
+
+    // The task will run whether the user is logged in or not using either a
+    // user/password specified at registration time, a service account or a
+    // service for user (S4U).
+    LOGON_SERVICE = 1 << 1,
+
+    // The task is run as a service for user and as such will be on an
+    // invisible desktop.
+    LOGON_S4U = 1 << 2,
+  };
+
+  // Struct representing a single scheduled task action.
+  struct TaskExecAction {
+    base::FilePath application_path;
+    base::FilePath working_dir;
+    base::string16 arguments;
+  };
+
+  // Detailed description of a scheduled task. This type is returned by the
+  // GetTaskInfo() method.
+  struct TaskInfo {
+    TaskInfo();
+    TaskInfo(const TaskInfo&);
+    TaskInfo(TaskInfo&&);
+    ~TaskInfo();
+    TaskInfo& operator=(const TaskInfo&);
+    TaskInfo& operator=(TaskInfo&&);
+
+    base::string16 name;
+
+    // Description of the task.
+    base::string16 description;
+
+    // A scheduled task can have more than one action associated with it and
+    // actions can be of types other than executables (for example, sending
+    // emails). This list however contains only the execution actions.
+    std::vector<TaskExecAction> exec_actions;
+
+    // The log-on requirements for the task's actions to be run. A bit mask with
+    // the mapping defined by LogonType.
+    uint32_t logon_type = 0;
+  };
+
+  // Control the lifespan of static data for the TaskScheduler. |Initialize|
+  // must be called before the first call to |CreateInstance|, and not other
+  // methods can be called after |Terminate| was called (unless |Initialize| is
+  // called again). |Initialize| can't be called out of balance with
+  // |Terminate|. |Terminate| can be called any number of times.
+  static bool Initialize();
+  static void Terminate();
+
+  static std::unique_ptr<TaskScheduler> CreateInstance();
+  virtual ~TaskScheduler() {}
+
+  // Identify whether the task is registered or not.
+  virtual bool IsTaskRegistered(const wchar_t* task_name) = 0;
+
+  // Return the time of the next schedule run for the given task name. Return
+  // false on failure.
+  virtual bool GetNextTaskRunTime(const wchar_t* task_name,
+                                  base::Time* next_run_time) = 0;
+
+  // Delete the task if it exists. No-op if the task doesn't exist. Return false
+  // on failure to delete an existing task.
+  virtual bool DeleteTask(const wchar_t* task_name) = 0;
+
+  // Enable or disable task based on the value of |enabled|. Return true if the
+  // task exists and the operation succeeded.
+  virtual bool SetTaskEnabled(const wchar_t* task_name, bool enabled) = 0;
+
+  // Return true if task exists and is enabled.
+  virtual bool IsTaskEnabled(const wchar_t* task_name) = 0;
+
+  // List all currently registered scheduled tasks.
+  virtual bool GetTaskNameList(std::vector<base::string16>* task_names) = 0;
+
+  // Return detailed information about a task. Return true if no errors were
+  // encountered. On error, the struct is left unmodified.
+  virtual bool GetTaskInfo(const wchar_t* task_name, TaskInfo* info) = 0;
+
+  // Register the task to run the specified application and using the given
+  // |trigger_type|.
+  virtual bool RegisterTask(const wchar_t* task_name,
+                            const wchar_t* task_description,
+                            const base::CommandLine& run_command,
+                            TriggerType trigger_type,
+                            bool hidden) = 0;
+
+ protected:
+  TaskScheduler();
+
+  DISALLOW_COPY_AND_ASSIGN(TaskScheduler);
+};
+
+}  // namespace updater
+
+#endif  // CHROME_UPDATER_WIN_TASK_SCHEDULER_H_
diff --git a/chrome/updater/win/task_scheduler_unittest.cc b/chrome/updater/win/task_scheduler_unittest.cc
new file mode 100644
index 0000000..3b20a78
--- /dev/null
+++ b/chrome/updater/win/task_scheduler_unittest.cc
@@ -0,0 +1,319 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/updater/win/task_scheduler.h"
+
+#include <taskschd.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/stl_util.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/test_timeouts.h"
+#include "base/time/time.h"
+#include "base/win/scoped_bstr.h"
+#include "base/win/scoped_variant.h"
+#include "base/win/windows_version.h"
+#include "chrome/updater/win/test/test_executables.h"
+#include "chrome/updater/win/test/test_strings.h"
+#include "chrome/updater/win/util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace updater {
+
+namespace {
+
+// The name of the tasks as will be visible in the scheduler so we know we can
+// safely delete them if they get stuck for whatever reason.
+const wchar_t kTaskName1[] = L"Chrome Updater Test task 1 (delete me)";
+const wchar_t kTaskName2[] = L"Chrome Updater Test task 2 (delete me)";
+// Optional descriptions for the above tasks.
+const wchar_t kTaskDescription1[] =
+    L"Task 1 used only for Chrome Updater unit testing.";
+const wchar_t kTaskDescription2[] =
+    L"Task 2 used only for Chrome Updater unit testing.";
+// A command-line switch used in testing.
+const char kTestSwitch[] = "a_switch";
+
+class TaskSchedulerTests : public testing::Test {
+ public:
+  void SetUp() override {
+    task_scheduler_ = TaskScheduler::CreateInstance();
+    // In case previous tests failed and left these tasks in the scheduler.
+    EXPECT_TRUE(task_scheduler_->DeleteTask(kTaskName1));
+    EXPECT_TRUE(task_scheduler_->DeleteTask(kTaskName2));
+    ASSERT_FALSE(IsProcessRunning(kTestProcessExecutableName));
+  }
+
+  void TearDown() override {
+    // Make sure to not leave tasks behind.
+    EXPECT_TRUE(task_scheduler_->DeleteTask(kTaskName1));
+    EXPECT_TRUE(task_scheduler_->DeleteTask(kTaskName2));
+    // Make sure every processes launched with scheduled task are completed.
+    ASSERT_TRUE(WaitForProcessesStopped(kTestProcessExecutableName));
+  }
+
+ protected:
+  std::unique_ptr<TaskScheduler> task_scheduler_;
+};
+
+}  // namespace
+
+TEST_F(TaskSchedulerTests, DeleteAndIsRegistered) {
+  EXPECT_FALSE(task_scheduler_->IsTaskRegistered(kTaskName1));
+
+  // Construct the full-path of the test executable.
+  base::FilePath executable_path;
+  ASSERT_TRUE(base::PathService::Get(base::DIR_EXE, &executable_path));
+  base::CommandLine command_line(
+      executable_path.Append(kTestProcessExecutableName));
+
+  // Validate that the task is properly seen as registered when it is.
+  EXPECT_TRUE(
+      task_scheduler_->RegisterTask(kTaskName1, kTaskDescription1, command_line,
+                                    TaskScheduler::TRIGGER_TYPE_NOW, false));
+  EXPECT_TRUE(task_scheduler_->IsTaskRegistered(kTaskName1));
+
+  // Validate that a task with a similar name is not seen as registered.
+  EXPECT_FALSE(task_scheduler_->IsTaskRegistered(kTaskName2));
+
+  // While the first one is still seen as registered, until it gets deleted.
+  EXPECT_TRUE(task_scheduler_->IsTaskRegistered(kTaskName1));
+  EXPECT_TRUE(task_scheduler_->DeleteTask(kTaskName1));
+  EXPECT_FALSE(task_scheduler_->IsTaskRegistered(kTaskName1));
+  // The other task should still not be registered.
+  EXPECT_FALSE(task_scheduler_->IsTaskRegistered(kTaskName2));
+}
+
+TEST_F(TaskSchedulerTests, RunAProgramNow) {
+  base::FilePath executable_path;
+  ASSERT_TRUE(base::PathService::Get(base::DIR_EXE, &executable_path));
+  base::CommandLine command_line(
+      executable_path.Append(kTestProcessExecutableName));
+
+  // Create a unique name for a shared event to be waited for in this process
+  // and signaled in the test process to confirm it was scheduled and ran.
+  const base::string16 event_name =
+      base::StrCat({kTestProcessExecutableName, L"-",
+                    base::NumberToString16(::GetCurrentProcessId())});
+  base::WaitableEvent event(base::win::ScopedHandle(
+      ::CreateEvent(nullptr, FALSE, FALSE, event_name.c_str())));
+  ASSERT_NE(event.handle(), nullptr);
+
+  command_line.AppendSwitchNative(kTestEventToSignal, event_name);
+  EXPECT_TRUE(
+      task_scheduler_->RegisterTask(kTaskName1, kTaskDescription1, command_line,
+                                    TaskScheduler::TRIGGER_TYPE_NOW, false));
+  EXPECT_TRUE(event.TimedWait(TestTimeouts::action_max_timeout()));
+  base::Time next_run_time;
+  EXPECT_FALSE(task_scheduler_->GetNextTaskRunTime(kTaskName1, &next_run_time));
+  EXPECT_TRUE(task_scheduler_->DeleteTask(kTaskName1));
+}
+
+TEST_F(TaskSchedulerTests, Hourly) {
+  base::FilePath executable_path;
+  ASSERT_TRUE(base::PathService::Get(base::DIR_EXE, &executable_path));
+  base::CommandLine command_line(
+      executable_path.Append(kTestProcessExecutableName));
+
+  base::Time now(base::Time::NowFromSystemTime());
+  EXPECT_TRUE(
+      task_scheduler_->RegisterTask(kTaskName1, kTaskDescription1, command_line,
+                                    TaskScheduler::TRIGGER_TYPE_HOURLY, false));
+  EXPECT_TRUE(task_scheduler_->IsTaskRegistered(kTaskName1));
+
+  base::TimeDelta one_hour(base::TimeDelta::FromHours(1));
+  base::TimeDelta one_minute(base::TimeDelta::FromMinutes(1));
+
+  base::Time next_run_time;
+  EXPECT_TRUE(task_scheduler_->GetNextTaskRunTime(kTaskName1, &next_run_time));
+  EXPECT_LT(next_run_time, now + one_hour + one_minute);
+  EXPECT_GT(next_run_time, now + one_hour - one_minute);
+
+  EXPECT_TRUE(task_scheduler_->DeleteTask(kTaskName1));
+  EXPECT_FALSE(task_scheduler_->IsTaskRegistered(kTaskName1));
+  EXPECT_FALSE(task_scheduler_->GetNextTaskRunTime(kTaskName1, &next_run_time));
+}
+
+TEST_F(TaskSchedulerTests, EveryFiveHours) {
+  base::FilePath executable_path;
+  ASSERT_TRUE(base::PathService::Get(base::DIR_EXE, &executable_path));
+  base::CommandLine command_line(
+      executable_path.Append(kTestProcessExecutableName));
+
+  base::Time now(base::Time::NowFromSystemTime());
+  EXPECT_TRUE(task_scheduler_->RegisterTask(
+      kTaskName1, kTaskDescription1, command_line,
+      TaskScheduler::TRIGGER_TYPE_EVERY_FIVE_HOURS, false));
+  EXPECT_TRUE(task_scheduler_->IsTaskRegistered(kTaskName1));
+
+  base::TimeDelta six_hours(base::TimeDelta::FromHours(5));
+  base::TimeDelta one_minute(base::TimeDelta::FromMinutes(1));
+
+  base::Time next_run_time;
+  EXPECT_TRUE(task_scheduler_->GetNextTaskRunTime(kTaskName1, &next_run_time));
+  EXPECT_LT(next_run_time, now + six_hours + one_minute);
+  EXPECT_GT(next_run_time, now + six_hours - one_minute);
+
+  EXPECT_TRUE(task_scheduler_->DeleteTask(kTaskName1));
+  EXPECT_FALSE(task_scheduler_->IsTaskRegistered(kTaskName1));
+  EXPECT_FALSE(task_scheduler_->GetNextTaskRunTime(kTaskName1, &next_run_time));
+}
+
+TEST_F(TaskSchedulerTests, SetTaskEnabled) {
+  base::FilePath executable_path;
+  ASSERT_TRUE(base::PathService::Get(base::DIR_EXE, &executable_path));
+  base::CommandLine command_line(
+      executable_path.Append(kTestProcessExecutableName));
+
+  EXPECT_TRUE(
+      task_scheduler_->RegisterTask(kTaskName1, kTaskDescription1, command_line,
+                                    TaskScheduler::TRIGGER_TYPE_HOURLY, false));
+  EXPECT_TRUE(task_scheduler_->IsTaskRegistered(kTaskName1));
+  EXPECT_TRUE(task_scheduler_->IsTaskEnabled(kTaskName1));
+
+  EXPECT_TRUE(task_scheduler_->SetTaskEnabled(kTaskName1, true));
+  EXPECT_TRUE(task_scheduler_->IsTaskEnabled(kTaskName1));
+  EXPECT_TRUE(task_scheduler_->SetTaskEnabled(kTaskName1, false));
+  EXPECT_FALSE(task_scheduler_->IsTaskEnabled(kTaskName1));
+  EXPECT_TRUE(task_scheduler_->SetTaskEnabled(kTaskName1, true));
+  EXPECT_TRUE(task_scheduler_->IsTaskEnabled(kTaskName1));
+
+  EXPECT_TRUE(task_scheduler_->DeleteTask(kTaskName1));
+}
+
+TEST_F(TaskSchedulerTests, GetTaskNameList) {
+  base::FilePath executable_path;
+  ASSERT_TRUE(base::PathService::Get(base::DIR_EXE, &executable_path));
+  base::CommandLine command_line(
+      executable_path.Append(kTestProcessExecutableName));
+
+  EXPECT_TRUE(
+      task_scheduler_->RegisterTask(kTaskName1, kTaskDescription1, command_line,
+                                    TaskScheduler::TRIGGER_TYPE_HOURLY, false));
+  EXPECT_TRUE(task_scheduler_->IsTaskRegistered(kTaskName1));
+  EXPECT_TRUE(
+      task_scheduler_->RegisterTask(kTaskName2, kTaskDescription2, command_line,
+                                    TaskScheduler::TRIGGER_TYPE_HOURLY, false));
+  EXPECT_TRUE(task_scheduler_->IsTaskRegistered(kTaskName2));
+
+  std::vector<base::string16> task_names;
+  EXPECT_TRUE(task_scheduler_->GetTaskNameList(&task_names));
+  EXPECT_TRUE(base::Contains(task_names, kTaskName1));
+  EXPECT_TRUE(base::Contains(task_names, kTaskName2));
+
+  EXPECT_TRUE(task_scheduler_->DeleteTask(kTaskName1));
+  EXPECT_TRUE(task_scheduler_->DeleteTask(kTaskName2));
+}
+
+TEST_F(TaskSchedulerTests, GetTasksIncludesHidden) {
+  base::FilePath executable_path;
+  ASSERT_TRUE(base::PathService::Get(base::DIR_EXE, &executable_path));
+  base::CommandLine command_line(
+      executable_path.Append(kTestProcessExecutableName));
+
+  EXPECT_TRUE(
+      task_scheduler_->RegisterTask(kTaskName1, kTaskDescription1, command_line,
+                                    TaskScheduler::TRIGGER_TYPE_HOURLY, true));
+
+  EXPECT_TRUE(task_scheduler_->IsTaskRegistered(kTaskName1));
+
+  std::vector<base::string16> task_names;
+  EXPECT_TRUE(task_scheduler_->GetTaskNameList(&task_names));
+  EXPECT_TRUE(base::Contains(task_names, kTaskName1));
+
+  EXPECT_TRUE(task_scheduler_->DeleteTask(kTaskName1));
+}
+
+TEST_F(TaskSchedulerTests, GetTaskInfoExecActions) {
+  base::FilePath executable_path;
+  ASSERT_TRUE(base::PathService::Get(base::DIR_EXE, &executable_path));
+  base::CommandLine command_line1(
+      executable_path.Append(kTestProcessExecutableName));
+
+  EXPECT_TRUE(task_scheduler_->RegisterTask(
+      kTaskName1, kTaskDescription1, command_line1,
+      TaskScheduler::TRIGGER_TYPE_HOURLY, false));
+  EXPECT_TRUE(task_scheduler_->IsTaskRegistered(kTaskName1));
+
+  TaskScheduler::TaskInfo info;
+  EXPECT_FALSE(task_scheduler_->GetTaskInfo(kTaskName2, &info));
+  EXPECT_EQ(0UL, info.exec_actions.size());
+  EXPECT_TRUE(task_scheduler_->GetTaskInfo(kTaskName1, &info));
+  ASSERT_EQ(1UL, info.exec_actions.size());
+  EXPECT_EQ(command_line1.GetProgram(), info.exec_actions[0].application_path);
+  EXPECT_EQ(command_line1.GetArgumentsString(), info.exec_actions[0].arguments);
+
+  base::CommandLine command_line2(
+      executable_path.Append(kTestProcessExecutableName));
+  command_line2.AppendSwitch(kTestSwitch);
+  EXPECT_TRUE(task_scheduler_->RegisterTask(
+      kTaskName2, kTaskDescription2, command_line2,
+      TaskScheduler::TRIGGER_TYPE_HOURLY, false));
+  EXPECT_TRUE(task_scheduler_->IsTaskRegistered(kTaskName2));
+
+  // The |info| struct is re-used to ensure that new task information overwrites
+  // the previous contents of the struct.
+  EXPECT_TRUE(task_scheduler_->GetTaskInfo(kTaskName2, &info));
+  ASSERT_EQ(1UL, info.exec_actions.size());
+  EXPECT_EQ(command_line2.GetProgram(), info.exec_actions[0].application_path);
+  EXPECT_EQ(command_line2.GetArgumentsString(), info.exec_actions[0].arguments);
+
+  EXPECT_TRUE(task_scheduler_->DeleteTask(kTaskName1));
+  EXPECT_TRUE(task_scheduler_->DeleteTask(kTaskName2));
+}
+
+TEST_F(TaskSchedulerTests, GetTaskInfoNameAndDescription) {
+  base::FilePath executable_path;
+  ASSERT_TRUE(base::PathService::Get(base::DIR_EXE, &executable_path));
+  base::CommandLine command_line1(
+      executable_path.Append(kTestProcessExecutableName));
+
+  EXPECT_TRUE(task_scheduler_->RegisterTask(
+      kTaskName1, kTaskDescription1, command_line1,
+      TaskScheduler::TRIGGER_TYPE_HOURLY, false));
+  EXPECT_TRUE(task_scheduler_->IsTaskRegistered(kTaskName1));
+
+  TaskScheduler::TaskInfo info;
+  EXPECT_FALSE(task_scheduler_->GetTaskInfo(kTaskName2, &info));
+  EXPECT_EQ(L"", info.description);
+  EXPECT_EQ(L"", info.name);
+
+  EXPECT_TRUE(task_scheduler_->GetTaskInfo(kTaskName1, &info));
+  EXPECT_EQ(kTaskDescription1, info.description);
+  EXPECT_EQ(kTaskName1, info.name);
+
+  EXPECT_TRUE(task_scheduler_->DeleteTask(kTaskName1));
+}
+
+TEST_F(TaskSchedulerTests, GetTaskInfoLogonType) {
+  base::FilePath executable_path;
+  ASSERT_TRUE(base::PathService::Get(base::DIR_EXE, &executable_path));
+  base::CommandLine command_line1(
+      executable_path.Append(kTestProcessExecutableName));
+
+  EXPECT_TRUE(task_scheduler_->RegisterTask(
+      kTaskName1, kTaskDescription1, command_line1,
+      TaskScheduler::TRIGGER_TYPE_HOURLY, false));
+  EXPECT_TRUE(task_scheduler_->IsTaskRegistered(kTaskName1));
+
+  TaskScheduler::TaskInfo info;
+  EXPECT_FALSE(task_scheduler_->GetTaskInfo(kTaskName2, &info));
+  EXPECT_EQ(0U, info.logon_type);
+  EXPECT_TRUE(task_scheduler_->GetTaskInfo(kTaskName1, &info));
+  EXPECT_TRUE(info.logon_type & TaskScheduler::LOGON_INTERACTIVE);
+  EXPECT_FALSE(info.logon_type & TaskScheduler::LOGON_SERVICE);
+  EXPECT_FALSE(info.logon_type & TaskScheduler::LOGON_S4U);
+
+  EXPECT_TRUE(task_scheduler_->DeleteTask(kTaskName1));
+}
+
+}  // namespace updater
diff --git a/chrome/updater/win/test/BUILD.gn b/chrome/updater/win/test/BUILD.gn
new file mode 100644
index 0000000..d1d2c72d
--- /dev/null
+++ b/chrome/updater/win/test/BUILD.gn
@@ -0,0 +1,61 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//testing/test.gni")
+
+source_set("test_strings") {
+  testonly = true
+
+  sources = [
+    "test_strings.cc",
+    "test_strings.h",
+  ]
+}
+
+source_set("test_common") {
+  testonly = true
+
+  sources = [
+    "test_inheritable_event.cc",
+    "test_inheritable_event.h",
+    "test_initializer.cc",
+    "test_initializer.h",
+  ]
+}
+
+source_set("test_executables") {
+  testonly = true
+
+  sources = [
+    "test_executables.cc",
+    "test_executables.h",
+  ]
+
+  data_deps = [
+    ":updater_test_process",
+  ]
+
+  deps = [
+    ":test_common",
+    ":test_strings",
+    "//base",
+  ]
+}
+
+executable("updater_test_process") {
+  testonly = true
+
+  sources = [
+    "test_process_main.cc",
+  ]
+
+  deps = [
+    ":test_common",
+    ":test_strings",
+    "//base",
+    "//base/test:test_support",
+    "//build/win:default_exe_manifest",
+    "//chrome/updater/win:code",
+  ]
+}
diff --git a/chrome/updater/win/test/test_executables.cc b/chrome/updater/win/test/test_executables.cc
new file mode 100644
index 0000000..8f4e38e
--- /dev/null
+++ b/chrome/updater/win/test/test_executables.cc
@@ -0,0 +1,65 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/updater/win/test/test_executables.h"
+
+#include <memory>
+
+#include "base/base_paths.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/process/launch.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/win/win_util.h"
+#include "chrome/updater/updater_constants.h"
+#include "chrome/updater/win/test/test_inheritable_event.h"
+#include "chrome/updater/win/test/test_strings.h"
+
+namespace updater {
+
+// If you add another test executable here, also add it to the data_deps in
+// the "test_executables" target of updater/win/test/BUILD.gn.
+const base::char16 kTestProcessExecutableName[] = L"updater_test_process.exe";
+
+base::Process LongRunningProcess(base::CommandLine* cmd) {
+  base::FilePath exe_dir;
+  if (!base::PathService::Get(base::DIR_EXE, &exe_dir)) {
+    LOG(ERROR) << "Failed to get the executable path, unable to create always "
+                  "running process";
+    return base::Process();
+  }
+
+  base::FilePath exe_path = exe_dir.Append(updater::kTestProcessExecutableName);
+  base::CommandLine command_line(exe_path);
+
+  // This will ensure this new process will run for one minute before dying.
+  command_line.AppendSwitchASCII(updater::kTestSleepMinutesSwitch, "1");
+
+  auto init_done_event = updater::CreateInheritableEvent(
+      base::WaitableEvent::ResetPolicy::AUTOMATIC,
+      base::WaitableEvent::InitialState::NOT_SIGNALED);
+  command_line.AppendSwitchNative(
+      updater::kInitDoneNotifierSwitch,
+      base::NumberToString16(
+          base::win::HandleToUint32(init_done_event->handle())));
+
+  if (cmd)
+    *cmd = command_line;
+
+  base::LaunchOptions launch_options;
+  launch_options.handles_to_inherit.push_back(init_done_event->handle());
+  base::Process result = base::LaunchProcess(command_line, launch_options);
+
+  if (!init_done_event->TimedWait(base::TimeDelta::FromSeconds(10))) {
+    LOG(ERROR) << "Process did not signal";
+    result.Terminate(/*exit_code=*/1, /*wait=*/false);
+    return base::Process();
+  }
+
+  return result;
+}
+
+}  // namespace updater
diff --git a/chrome/updater/win/test/test_executables.h b/chrome/updater/win/test/test_executables.h
new file mode 100644
index 0000000..1ebe8b3
--- /dev/null
+++ b/chrome/updater/win/test/test_executables.h
@@ -0,0 +1,30 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_UPDATER_WIN_TEST_TEST_EXECUTABLES_H_
+#define CHROME_UPDATER_WIN_TEST_TEST_EXECUTABLES_H_
+
+#include "base/process/process.h"
+#include "base/strings/string16.h"
+
+namespace base {
+class CommandLine;
+}  // namespace base
+
+namespace updater {
+
+// The name of the service executable used for tests.
+extern const base::char16 kTestServiceExecutableName[];
+
+// The name of the executable used for tests.
+extern const base::char16 kTestProcessExecutableName[];
+
+// Creates a process that will run for a minute, which is long enough to be
+// killed by a reasonably fast unit or integration test.
+// Populates |command_line| with the used command line if it is not nullptr.
+base::Process LongRunningProcess(base::CommandLine* command_line);
+
+}  // namespace updater
+
+#endif  // CHROME_UPDATER_WIN_TEST_TEST_EXECUTABLES_H_
diff --git a/chrome/updater/win/test/test_inheritable_event.cc b/chrome/updater/win/test/test_inheritable_event.cc
new file mode 100644
index 0000000..1866165
--- /dev/null
+++ b/chrome/updater/win/test/test_inheritable_event.cc
@@ -0,0 +1,32 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/updater/win/test/test_inheritable_event.h"
+
+#include <windows.h>
+
+#include <utility>
+
+#include "base/logging.h"
+
+namespace updater {
+
+std::unique_ptr<base::WaitableEvent> CreateInheritableEvent(
+    base::WaitableEvent::ResetPolicy reset_policy,
+    base::WaitableEvent::InitialState initial_state) {
+  SECURITY_ATTRIBUTES attributes = {sizeof(SECURITY_ATTRIBUTES)};
+  attributes.bInheritHandle = true;
+
+  HANDLE handle = ::CreateEvent(
+      &attributes, reset_policy == base::WaitableEvent::ResetPolicy::MANUAL,
+      initial_state == base::WaitableEvent::InitialState::SIGNALED, nullptr);
+  if (handle == nullptr || handle == INVALID_HANDLE_VALUE) {
+    PLOG(ERROR) << "Could not create inheritable event";
+    return nullptr;
+  }
+  base::win::ScopedHandle event_handle(handle);
+  return std::make_unique<base::WaitableEvent>(std::move(event_handle));
+}
+
+}  // namespace updater
diff --git a/chrome/updater/win/test/test_inheritable_event.h b/chrome/updater/win/test/test_inheritable_event.h
new file mode 100644
index 0000000..3912f9d4
--- /dev/null
+++ b/chrome/updater/win/test/test_inheritable_event.h
@@ -0,0 +1,20 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_UPDATER_WIN_TEST_TEST_INHERITABLE_EVENT_H_
+#define CHROME_UPDATER_WIN_TEST_TEST_INHERITABLE_EVENT_H_
+
+#include <memory>
+
+#include "base/synchronization/waitable_event.h"
+
+namespace updater {
+
+std::unique_ptr<base::WaitableEvent> CreateInheritableEvent(
+    base::WaitableEvent::ResetPolicy reset_policy,
+    base::WaitableEvent::InitialState initial_state);
+
+}  // namespace updater
+
+#endif  // CHROME_UPDATER_WIN_TEST_TEST_INHERITABLE_EVENT_H_
diff --git a/chrome/updater/win/test/test_initializer.cc b/chrome/updater/win/test/test_initializer.cc
new file mode 100644
index 0000000..e84914b
--- /dev/null
+++ b/chrome/updater/win/test/test_initializer.cc
@@ -0,0 +1,57 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/updater/win/test/test_initializer.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/command_line.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/time/time.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/win_util.h"
+#include "chrome/updater/updater_constants.h"
+
+namespace updater {
+
+namespace {
+
+std::unique_ptr<base::WaitableEvent> SignalInitializationDone() {
+  base::win::ScopedHandle init_done_notifier;
+
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  uint32_t handle = 0;
+  if (command_line->HasSwitch(kInitDoneNotifierSwitch) &&
+      base::StringToUint(
+          command_line->GetSwitchValueNative(kInitDoneNotifierSwitch),
+          &handle)) {
+    init_done_notifier.Set(base::win::Uint32ToHandle(handle));
+  }
+
+  std::unique_ptr<base::WaitableEvent> notifier_event;
+  if (init_done_notifier.IsValid()) {
+    notifier_event =
+        std::make_unique<base::WaitableEvent>(std::move(init_done_notifier));
+    notifier_event->Signal();
+  }
+
+  return notifier_event;
+}
+
+}  // namespace
+
+void NotifyInitializationDoneForTesting() {
+  auto notifier_event = SignalInitializationDone();
+
+  // The event has ResetPolicy AUTOMATIC, so after the test is woken up it is
+  // immediately reset. Wait at most 5 seconds for the test to signal that
+  // it's ready using the same event before continuing. If the test takes
+  // longer than that stop waiting to prevent hangs.
+  if (notifier_event)
+    notifier_event->TimedWait(base::TimeDelta::FromSeconds(5));
+}
+
+}  // namespace updater
diff --git a/chrome/updater/win/test/test_initializer.h b/chrome/updater/win/test/test_initializer.h
new file mode 100644
index 0000000..8c38625
--- /dev/null
+++ b/chrome/updater/win/test/test_initializer.h
@@ -0,0 +1,19 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_UPDATER_WIN_TEST_TEST_INITIALIZER_H_
+#define CHROME_UPDATER_WIN_TEST_TEST_INITIALIZER_H_
+
+namespace updater {
+
+// Signals the event handle that was passed on the command line with
+// --init-done-notifier, if it exists. Then waits for the event to be signalled
+// again before continuing. This allows a test harness to pause the binary's
+// execution, do some extra setup, and resume it.
+// Note, this means the event must be AUTOMATIC.
+void NotifyInitializationDoneForTesting();
+
+}  // namespace updater
+
+#endif  // CHROME_UPDATER_WIN_TEST_TEST_INITIALIZER_H_
diff --git a/chrome/updater/win/test/test_main.cc b/chrome/updater/win/test/test_main.cc
new file mode 100644
index 0000000..edeb235
--- /dev/null
+++ b/chrome/updater/win/test/test_main.cc
@@ -0,0 +1,45 @@
+// Copyright 2019 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 <memory>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/logging.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+#include "base/win/scoped_com_initializer.h"
+#include "chrome/updater/win/task_scheduler.h"
+#include "chrome/updater/win/util.h"
+
+int main(int argc, char** argv) {
+  // ScopedCOMInitializer keeps COM initialized in a specific scope. We don't
+  // want to initialize it for sandboxed processes, so manage its lifetime with
+  // a unique_ptr, which will call ScopedCOMInitializer's destructor when it
+  // goes out of scope below.
+  auto scoped_com_initializer =
+      std::make_unique<base::win::ScopedCOMInitializer>(
+          base::win::ScopedCOMInitializer::kMTA);
+  bool success = updater::InitializeCOMSecurity();
+  DCHECK(success) << "InitializeCOMSecurity() failed.";
+
+  success = updater::TaskScheduler::Initialize();
+  DCHECK(success) << "TaskScheduler::Initialize() failed.";
+
+  // Some tests will fail if two tests try to launch test_process.exe
+  // simultaneously, so run the tests serially. This will still shard them and
+  // distribute the shards to different swarming bots, but tests will run
+  // serially on each bot.
+  base::TestSuite test_suite(argc, argv);
+  const int result = base::LaunchUnitTestsWithOptions(
+      argc, argv,
+      /*parallel_jobs=*/1U,        // Like LaunchUnitTestsSerially
+      /*default_batch_limit=*/10,  // Like LaunchUnitTestsSerially
+      false,
+      base::BindOnce(&base::TestSuite::Run, base::Unretained(&test_suite)));
+
+  updater::TaskScheduler::Terminate();
+
+  return result;
+}
diff --git a/chrome/updater/win/test/test_process_main.cc b/chrome/updater/win/test/test_process_main.cc
new file mode 100644
index 0000000..32f34b4
--- /dev/null
+++ b/chrome/updater/win/test/test_process_main.cc
@@ -0,0 +1,54 @@
+// Copyright 2019 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 <windows.h>
+
+#include <string>
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/time/time.h"
+#include "chrome/updater/win/test/test_initializer.h"
+#include "chrome/updater/win/test/test_strings.h"
+
+int main(int, char**) {
+  bool success = base::CommandLine::Init(0, nullptr);
+  DCHECK(success);
+
+  updater::NotifyInitializationDoneForTesting();
+
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(updater::kTestSleepMinutesSwitch)) {
+    std::string value =
+        command_line->GetSwitchValueASCII(updater::kTestSleepMinutesSwitch);
+    int sleep_minutes = 0;
+    if (base::StringToInt(value, &sleep_minutes) && sleep_minutes > 0) {
+      VLOG(1) << "Process is sleeping for " << sleep_minutes << " minutes";
+      ::Sleep(base::TimeDelta::FromMinutes(sleep_minutes).InMilliseconds());
+    } else {
+      LOG(ERROR) << "Invalid sleep delay value " << value;
+    }
+    NOTREACHED();
+    return 1;
+  }
+
+  if (command_line->HasSwitch(updater::kTestEventToSignal)) {
+    VLOG(1) << "Process is signaling event '" << updater::kTestEventToSignal
+            << "'";
+    base::string16 event_name =
+        command_line->GetSwitchValueNative(updater::kTestEventToSignal);
+    base::win::ScopedHandle handle(
+        ::OpenEvent(EVENT_ALL_ACCESS, TRUE, event_name.c_str()));
+    PLOG_IF(ERROR, !handle.IsValid())
+        << "Cannot create event '" << updater::kTestEventToSignal << "'";
+    base::WaitableEvent event(std::move(handle));
+    event.Signal();
+  }
+
+  VLOG(1) << "Process ended.";
+  return 0;
+}
diff --git a/chrome/updater/win/test/test_strings.cc b/chrome/updater/win/test/test_strings.cc
new file mode 100644
index 0000000..031003f
--- /dev/null
+++ b/chrome/updater/win/test/test_strings.cc
@@ -0,0 +1,13 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/updater/win/test/test_strings.h"
+
+namespace updater {
+
+// Command line switches.
+const char kTestSleepMinutesSwitch[] = "test-sleep-minutes";
+const char kTestEventToSignal[] = "test-event-to-signal";
+
+}  // namespace updater
diff --git a/chrome/updater/win/test/test_strings.h b/chrome/updater/win/test/test_strings.h
new file mode 100644
index 0000000..ac95ff90
--- /dev/null
+++ b/chrome/updater/win/test/test_strings.h
@@ -0,0 +1,23 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_UPDATER_WIN_TEST_TEST_STRINGS_H_
+#define CHROME_UPDATER_WIN_TEST_TEST_STRINGS_H_
+
+#include <windows.h>
+
+namespace updater {
+
+// Command line switches.
+
+// The switch to activate the sleeping action for specified delay in minutes
+// before killing the process.
+extern const char kTestSleepMinutesSwitch[];
+
+// The switch to signal the event with the name given as a switch value.
+extern const char kTestEventToSignal[];
+
+}  // namespace updater
+
+#endif  // CHROME_UPDATER_WIN_TEST_TEST_STRINGS_H_
diff --git a/chrome/updater/win/util.cc b/chrome/updater/win/util.cc
index 821c729..c7bf448 100644
--- a/chrome/updater/win/util.cc
+++ b/chrome/updater/win/util.cc
@@ -4,13 +4,141 @@
 
 #include "chrome/updater/win/util.h"
 
+#include <aclapi.h>
+#include <shlobj.h>
 #include <windows.h>
 
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/process/process_iterator.h"
+
 namespace updater {
 
+namespace {
+
+// The number of iterations to poll if a process is stopped correctly.
+const unsigned int kMaxProcessQueryIterations = 50;
+
+// The sleep time in ms between each poll.
+const unsigned int kProcessQueryWaitTimeMs = 100;
+
+}  // namespace
+
 HRESULT HRESULTFromLastError() {
   const auto error_code = ::GetLastError();
   return (error_code != NO_ERROR) ? HRESULT_FROM_WIN32(error_code) : E_FAIL;
 }
 
+bool IsProcessRunning(const wchar_t* executable) {
+  base::NamedProcessIterator iter(executable, nullptr);
+  const base::ProcessEntry* entry = iter.NextProcessEntry();
+  return entry != nullptr;
+}
+
+bool WaitForProcessesStopped(const wchar_t* executable) {
+  DCHECK(executable);
+  VLOG(1) << "Wait for processes '" << executable << "'.";
+
+  // Wait until the process is completely stopped.
+  for (unsigned int iteration = 0; iteration < kMaxProcessQueryIterations;
+       ++iteration) {
+    if (!IsProcessRunning(executable))
+      return true;
+    ::Sleep(kProcessQueryWaitTimeMs);
+  }
+
+  // The process didn't terminate.
+  LOG(ERROR) << "Cannot stop process '" << executable << "', timeout.";
+  return false;
+}
+
+// This sets up COM security to allow NetworkService, LocalService, and System
+// to call back into the process. It is largely inspired by
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa378987.aspx
+// static
+bool InitializeCOMSecurity() {
+  // Create the security descriptor explicitly as follows because
+  // CoInitializeSecurity() will not accept the relative security descriptors
+  // returned by ConvertStringSecurityDescriptorToSecurityDescriptor().
+  const size_t kSidCount = 5;
+  uint64_t* sids[kSidCount][(SECURITY_MAX_SID_SIZE + sizeof(uint64_t) - 1) /
+                            sizeof(uint64_t)] = {
+      {}, {}, {}, {}, {},
+  };
+
+  // These are ordered by most interesting ones to try first.
+  WELL_KNOWN_SID_TYPE sid_types[kSidCount] = {
+      WinBuiltinAdministratorsSid,  // administrator group security identifier
+      WinLocalServiceSid,           // local service security identifier
+      WinNetworkServiceSid,         // network service security identifier
+      WinSelfSid,                   // personal account security identifier
+      WinLocalSystemSid,            // local system security identifier
+  };
+
+  // This creates a security descriptor that is equivalent to the following
+  // security descriptor definition language (SDDL) string:
+  //   O:BAG:BAD:(A;;0x1;;;LS)(A;;0x1;;;NS)(A;;0x1;;;PS)
+  //   (A;;0x1;;;SY)(A;;0x1;;;BA)
+
+  // Initialize the security descriptor.
+  SECURITY_DESCRIPTOR security_desc = {};
+  if (!::InitializeSecurityDescriptor(&security_desc,
+                                      SECURITY_DESCRIPTOR_REVISION))
+    return false;
+
+  DCHECK_EQ(kSidCount, base::size(sids));
+  DCHECK_EQ(kSidCount, base::size(sid_types));
+  for (size_t i = 0; i < kSidCount; ++i) {
+    DWORD sid_bytes = sizeof(sids[i]);
+    if (!::CreateWellKnownSid(sid_types[i], nullptr, sids[i], &sid_bytes))
+      return false;
+  }
+
+  // Setup the access control entries (ACE) for COM. You may need to modify
+  // the access permissions for your application. COM_RIGHTS_EXECUTE and
+  // COM_RIGHTS_EXECUTE_LOCAL are the minimum access rights required.
+  EXPLICIT_ACCESS explicit_access[kSidCount] = {};
+  DCHECK_EQ(kSidCount, base::size(sids));
+  DCHECK_EQ(kSidCount, base::size(explicit_access));
+  for (size_t i = 0; i < kSidCount; ++i) {
+    explicit_access[i].grfAccessPermissions =
+        COM_RIGHTS_EXECUTE | COM_RIGHTS_EXECUTE_LOCAL;
+    explicit_access[i].grfAccessMode = SET_ACCESS;
+    explicit_access[i].grfInheritance = NO_INHERITANCE;
+    explicit_access[i].Trustee.pMultipleTrustee = nullptr;
+    explicit_access[i].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
+    explicit_access[i].Trustee.TrusteeForm = TRUSTEE_IS_SID;
+    explicit_access[i].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
+    explicit_access[i].Trustee.ptstrName = reinterpret_cast<LPTSTR>(sids[i]);
+  }
+
+  // Create an access control list (ACL) using this ACE list, if this succeeds
+  // make sure to ::LocalFree(acl).
+  ACL* acl = nullptr;
+  DWORD acl_result = ::SetEntriesInAcl(base::size(explicit_access),
+                                       explicit_access, nullptr, &acl);
+  if (acl_result != ERROR_SUCCESS || acl == nullptr)
+    return false;
+
+  HRESULT hr = E_FAIL;
+
+  // Set the security descriptor owner and group to Administrators and set the
+  // discretionary access control list (DACL) to the ACL.
+  if (::SetSecurityDescriptorOwner(&security_desc, sids[0], FALSE) &&
+      ::SetSecurityDescriptorGroup(&security_desc, sids[0], FALSE) &&
+      ::SetSecurityDescriptorDacl(&security_desc, TRUE, acl, FALSE)) {
+    // Initialize COM. You may need to modify the parameters of
+    // CoInitializeSecurity() for your application. Note that an
+    // explicit security descriptor is being passed down.
+    hr = ::CoInitializeSecurity(
+        &security_desc, -1, nullptr, nullptr, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
+        RPC_C_IMP_LEVEL_IDENTIFY, nullptr,
+        EOAC_DISABLE_AAA | EOAC_NO_CUSTOM_MARSHAL, nullptr);
+  }
+
+  ::LocalFree(acl);
+  return SUCCEEDED(hr);
+}
+
 }  // namespace updater
diff --git a/chrome/updater/win/util.h b/chrome/updater/win/util.h
index d30e10d9..257c677 100644
--- a/chrome/updater/win/util.h
+++ b/chrome/updater/win/util.h
@@ -27,6 +27,16 @@
                               static_cast<ULONG>(error));
 }
 
+// Checks whether a process is running with the image |executable|. Returns true
+// if a process is found.
+bool IsProcessRunning(const wchar_t* executable);
+
+// Waits until every running instance of |executable| is stopped.
+// Returns true if every running processes are stopped.
+bool WaitForProcessesStopped(const wchar_t* executable);
+
+bool InitializeCOMSecurity();
+
 }  // namespace updater
 
 #endif  // CHROME_UPDATER_WIN_UTIL_H_
diff --git a/chromeos/cryptohome/homedir_methods.cc b/chromeos/cryptohome/homedir_methods.cc
index 26c618a..a104315 100644
--- a/chromeos/cryptohome/homedir_methods.cc
+++ b/chromeos/cryptohome/homedir_methods.cc
@@ -70,6 +70,16 @@
                        weak_ptr_factory_.GetWeakPtr(), callback));
   }
 
+  void MassRemoveKeys(const Identification& id,
+                      const AuthorizationRequest& auth,
+                      const MassRemoveKeysRequest& request,
+                      const Callback& callback) override {
+    chromeos::CryptohomeClient::Get()->MassRemoveKeys(
+        CreateAccountIdentifierFromIdentification(id), auth, request,
+        base::BindOnce(&HomedirMethodsImpl::OnBaseReplyCallback,
+                       weak_ptr_factory_.GetWeakPtr(), callback));
+  }
+
  private:
   void OnBaseReplyCallback(const Callback& callback,
                            base::Optional<BaseReply> reply) {
diff --git a/chromeos/cryptohome/homedir_methods.h b/chromeos/cryptohome/homedir_methods.h
index 8959087..7afae59 100644
--- a/chromeos/cryptohome/homedir_methods.h
+++ b/chromeos/cryptohome/homedir_methods.h
@@ -62,6 +62,13 @@
                            const RemoveKeyRequest& request,
                            const Callback& callback) = 0;
 
+  // Asks cryptohomed to remove all keys except those whose labels are exempted
+  // in MassRemoveKeysRequest, for the user identified by |id| using |auth|.
+  virtual void MassRemoveKeys(const Identification& id,
+                              const AuthorizationRequest& auth,
+                              const MassRemoveKeysRequest& request,
+                              const Callback& callback) = 0;
+
   // Creates the global HomedirMethods instance.
   static void Initialize();
 
diff --git a/chromeos/dbus/cryptohome/cryptohome_client.cc b/chromeos/dbus/cryptohome/cryptohome_client.cc
index 70d0fe3..e4f9032 100644
--- a/chromeos/dbus/cryptohome/cryptohome_client.cc
+++ b/chromeos/dbus/cryptohome/cryptohome_client.cc
@@ -855,6 +855,22 @@
                        weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
   }
 
+  void AddDataRestoreKey(
+      const cryptohome::AccountIdentifier& id,
+      const cryptohome::AuthorizationRequest& auth,
+      DBusMethodCallback<cryptohome::BaseReply> callback) override {
+    const char* method_name = cryptohome::kCryptohomeAddDataRestoreKey;
+    dbus::MethodCall method_call(cryptohome::kCryptohomeInterface, method_name);
+    dbus::MessageWriter writer(&method_call);
+    writer.AppendProtoAsArrayOfBytes(id);
+    writer.AppendProtoAsArrayOfBytes(auth);
+
+    proxy_->CallMethod(
+        &method_call, kTpmDBusTimeoutMs,
+        base::BindOnce(&CryptohomeClientImpl::OnBaseReplyMethod,
+                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+  }
+
   void UpdateKeyEx(
       const cryptohome::AccountIdentifier& id,
       const cryptohome::AuthorizationRequest& auth,
@@ -891,6 +907,24 @@
                        weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
   }
 
+  void MassRemoveKeys(
+      const cryptohome::AccountIdentifier& id,
+      const cryptohome::AuthorizationRequest& auth,
+      const cryptohome::MassRemoveKeysRequest& request,
+      DBusMethodCallback<cryptohome::BaseReply> callback) override {
+    const char* method_name = cryptohome::kCryptohomeMassRemoveKeys;
+    dbus::MethodCall method_call(cryptohome::kCryptohomeInterface, method_name);
+    dbus::MessageWriter writer(&method_call);
+    writer.AppendProtoAsArrayOfBytes(id);
+    writer.AppendProtoAsArrayOfBytes(auth);
+    writer.AppendProtoAsArrayOfBytes(request);
+
+    proxy_->CallMethod(
+        &method_call, kTpmDBusTimeoutMs,
+        base::BindOnce(&CryptohomeClientImpl::OnBaseReplyMethod,
+                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+  }
+
   void GetBootAttribute(
       const cryptohome::GetBootAttributeRequest& request,
       DBusMethodCallback<cryptohome::BaseReply> callback) override {
diff --git a/chromeos/dbus/cryptohome/cryptohome_client.h b/chromeos/dbus/cryptohome/cryptohome_client.h
index 85a300b..5e06f76 100644
--- a/chromeos/dbus/cryptohome/cryptohome_client.h
+++ b/chromeos/dbus/cryptohome/cryptohome_client.h
@@ -30,6 +30,7 @@
 class GetSupportedKeyPoliciesRequest;
 class GetTpmStatusRequest;
 class LockToSingleUserMountUntilRebootRequest;
+class MassRemoveKeysRequest;
 class MigrateKeyRequest;
 class MigrateToDircryptoRequest;
 class MountGuestRequest;
@@ -533,6 +534,16 @@
                         const cryptohome::AddKeyRequest& request,
                         DBusMethodCallback<cryptohome::BaseReply> callback) = 0;
 
+  // Asynchronously calls AddDataRestoreKey method. |callback| is called after
+  // method call, and with reply protobuf.
+  // AddDataRestoreKey generates data_restore_key in OS and adds it to the
+  // given key set. The reply protobuf needs to be extended to
+  // AddDataRestoreKeyReply so that caller gets raw bytes of data_restore_key
+  virtual void AddDataRestoreKey(
+      const cryptohome::AccountIdentifier& id,
+      const cryptohome::AuthorizationRequest& auth,
+      DBusMethodCallback<cryptohome::BaseReply> callback) = 0;
+
   // Asynchronously calls UpdateKeyEx method. |callback| is called after method
   // call, and with reply protobuf. Reply will contain MountReply extension.
   // UpdateKeyEx replaces key used for authorization, without affecting any
@@ -553,6 +564,16 @@
       const cryptohome::RemoveKeyRequest& request,
       DBusMethodCallback<cryptohome::BaseReply> callback) = 0;
 
+  // Asynchronously calls MassRemoveKeys method. |callback| is called after
+  // method call, and with reply protobuf.
+  // MassRemoveKeys removes all keys except those whose labels are exempted
+  // in MassRemoveKeysRequest.
+  virtual void MassRemoveKeys(
+      const cryptohome::AccountIdentifier& id,
+      const cryptohome::AuthorizationRequest& auth,
+      const cryptohome::MassRemoveKeysRequest& request,
+      DBusMethodCallback<cryptohome::BaseReply> callback) = 0;
+
   // Asynchronously calls GetBootAttribute method. |callback| is called after
   // method call, and with reply protobuf.
   // GetBootAttribute gets the value of the specified boot attribute.
diff --git a/chromeos/dbus/cryptohome/fake_cryptohome_client.cc b/chromeos/dbus/cryptohome/fake_cryptohome_client.cc
index 7489035..500a38d 100644
--- a/chromeos/dbus/cryptohome/fake_cryptohome_client.cc
+++ b/chromeos/dbus/cryptohome/fake_cryptohome_client.cc
@@ -639,6 +639,13 @@
   ReturnProtobufMethodCallback(cryptohome::BaseReply(), std::move(callback));
 }
 
+void FakeCryptohomeClient::AddDataRestoreKey(
+    const cryptohome::AccountIdentifier& cryptohome_id,
+    const cryptohome::AuthorizationRequest& auth,
+    DBusMethodCallback<cryptohome::BaseReply> callback) {
+  ReturnProtobufMethodCallback(cryptohome::BaseReply(), std::move(callback));
+}
+
 void FakeCryptohomeClient::RemoveKeyEx(
     const cryptohome::AccountIdentifier& cryptohome_id,
     const cryptohome::AuthorizationRequest& auth,
@@ -661,6 +668,14 @@
   ReturnProtobufMethodCallback(cryptohome::BaseReply(), std::move(callback));
 }
 
+void FakeCryptohomeClient::MassRemoveKeys(
+    const cryptohome::AccountIdentifier& cryptohome_id,
+    const cryptohome::AuthorizationRequest& auth,
+    const cryptohome::MassRemoveKeysRequest& request,
+    DBusMethodCallback<cryptohome::BaseReply> callback) {
+  ReturnProtobufMethodCallback(cryptohome::BaseReply(), std::move(callback));
+}
+
 void FakeCryptohomeClient::GetBootAttribute(
     const cryptohome::GetBootAttributeRequest& request,
     DBusMethodCallback<cryptohome::BaseReply> callback) {
diff --git a/chromeos/dbus/cryptohome/fake_cryptohome_client.h b/chromeos/dbus/cryptohome/fake_cryptohome_client.h
index 74aa9104..25feced 100644
--- a/chromeos/dbus/cryptohome/fake_cryptohome_client.h
+++ b/chromeos/dbus/cryptohome/fake_cryptohome_client.h
@@ -194,6 +194,10 @@
                 const cryptohome::AuthorizationRequest& auth,
                 const cryptohome::AddKeyRequest& request,
                 DBusMethodCallback<cryptohome::BaseReply> callback) override;
+  void AddDataRestoreKey(
+      const cryptohome::AccountIdentifier& cryptohome_id,
+      const cryptohome::AuthorizationRequest& auth,
+      DBusMethodCallback<cryptohome::BaseReply> callback) override;
   void UpdateKeyEx(const cryptohome::AccountIdentifier& cryptohome_id,
                    const cryptohome::AuthorizationRequest& auth,
                    const cryptohome::UpdateKeyRequest& request,
@@ -202,6 +206,11 @@
                    const cryptohome::AuthorizationRequest& auth,
                    const cryptohome::RemoveKeyRequest& request,
                    DBusMethodCallback<cryptohome::BaseReply> callback) override;
+  void MassRemoveKeys(
+      const cryptohome::AccountIdentifier& cryptohome_id,
+      const cryptohome::AuthorizationRequest& auth,
+      const cryptohome::MassRemoveKeysRequest& request,
+      DBusMethodCallback<cryptohome::BaseReply> callback) override;
   void GetBootAttribute(
       const cryptohome::GetBootAttributeRequest& request,
       DBusMethodCallback<cryptohome::BaseReply> callback) override;
diff --git a/chromeos/network/BUILD.gn b/chromeos/network/BUILD.gn
index f14d80d2..48637684 100644
--- a/chromeos/network/BUILD.gn
+++ b/chromeos/network/BUILD.gn
@@ -21,6 +21,7 @@
     "//chromeos/services/network_config/public/mojom",
     "//components/account_id",
     "//components/certificate_matching",
+    "//components/crx_file",
     "//components/device_event_log",
     "//components/onc",
     "//components/pref_registry",
@@ -113,6 +114,8 @@
     "network_ui_data.h",
     "network_util.cc",
     "network_util.h",
+    "onc/certificate_scope.cc",
+    "onc/certificate_scope.h",
     "onc/onc_certificate_importer.h",
     "onc/onc_certificate_importer_impl.cc",
     "onc/onc_certificate_importer_impl.h",
diff --git a/chromeos/network/DEPS b/chromeos/network/DEPS
index d3e6536..50ad652 100644
--- a/chromeos/network/DEPS
+++ b/chromeos/network/DEPS
@@ -10,6 +10,7 @@
   "+chromeos/services/network_config/public",
   "+components/account_id",
   "+components/certificate_matching",
+  "+components/crx_file",
   "+components/device_event_log",
   "+components/onc",
   "+components/pref_registry",
diff --git a/chromeos/network/client_cert_resolver.cc b/chromeos/network/client_cert_resolver.cc
index 9a39df2c..430c82a 100644
--- a/chromeos/network/client_cert_resolver.cc
+++ b/chromeos/network/client_cert_resolver.cc
@@ -97,7 +97,7 @@
     std::string firstSANEmail;
     if (!names.empty())
       firstSANEmail = names[0];
-    substitutions[onc::substitutes::kCertSANEmail] = firstSANEmail;
+    substitutions[::onc::substitutes::kCertSANEmail] = firstSANEmail;
   }
 
   {
@@ -107,10 +107,10 @@
     std::string firstSANUPN;
     if (!names.empty())
       firstSANUPN = names[0];
-    substitutions[onc::substitutes::kCertSANUPN] = firstSANUPN;
+    substitutions[::onc::substitutes::kCertSANUPN] = firstSANUPN;
   }
 
-  substitutions[onc::substitutes::kCertSubjectCommonName] =
+  substitutions[::onc::substitutes::kCertSubjectCommonName] =
       certificate::GetCertAsciiSubjectCommonName(cert);
 
   return substitutions;
@@ -616,7 +616,7 @@
     if (network->profile_path().empty())
       continue;
 
-    onc::ONCSource onc_source = onc::ONC_SOURCE_NONE;
+    ::onc::ONCSource onc_source = ::onc::ONC_SOURCE_NONE;
     const base::DictionaryValue* policy =
         managed_network_config_handler_->FindPolicyByGuidAndProfile(
             network->guid(), network->profile_path(), &onc_source);
diff --git a/chromeos/network/managed_network_configuration_handler_impl.h b/chromeos/network/managed_network_configuration_handler_impl.h
index e9aa9c6..49a252f 100644
--- a/chromeos/network/managed_network_configuration_handler_impl.h
+++ b/chromeos/network/managed_network_configuration_handler_impl.h
@@ -82,7 +82,7 @@
       const base::Closure& callback,
       const network_handler::ErrorCallback& error_callback) const override;
 
-  void SetPolicy(onc::ONCSource onc_source,
+  void SetPolicy(::onc::ONCSource onc_source,
                  const std::string& userhash,
                  const base::ListValue& network_configs_onc,
                  const base::DictionaryValue& global_network_config) override;
@@ -92,7 +92,7 @@
   const base::DictionaryValue* FindPolicyByGUID(
       const std::string userhash,
       const std::string& guid,
-      onc::ONCSource* onc_source) const override;
+      ::onc::ONCSource* onc_source) const override;
 
   const GuidToPolicyMap* GetNetworkConfigsFromPolicy(
       const std::string& userhash) const override;
@@ -103,7 +103,7 @@
   const base::DictionaryValue* FindPolicyByGuidAndProfile(
       const std::string& guid,
       const std::string& profile_path,
-      onc::ONCSource* onc_source) const override;
+      ::onc::ONCSource* onc_source) const override;
 
   bool AllowOnlyPolicyNetworksToConnect() const override;
   bool AllowOnlyPolicyNetworksToConnectIfAvailable() const override;
diff --git a/chromeos/network/network_cert_loader.cc b/chromeos/network/network_cert_loader.cc
index 69318c9..1ae5fd63 100644
--- a/chromeos/network/network_cert_loader.cc
+++ b/chromeos/network/network_cert_loader.cc
@@ -18,6 +18,8 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/task/post_task.h"
 #include "chromeos/network/certificate_helper.h"
+#include "chromeos/network/onc/certificate_scope.h"
+#include "chromeos/network/policy_certificate_provider.h"
 #include "crypto/nss_util.h"
 #include "crypto/scoped_nss_types.h"
 #include "net/cert/cert_database.h"
@@ -45,8 +47,8 @@
   return NetworkCertType::kOther;
 }
 
-// Returns all authority certificats provided by |policy_certificate_provider|
-// as a list of NetworkCerts.
+// Returns all authority certificates with default (not restricted) scope
+// provided by |policy_certificate_provider| as a list of NetworkCerts.
 NetworkCertLoader::NetworkCertList GetPolicyProvidedAuthorities(
     const PolicyCertificateProvider* policy_certificate_provider,
     bool device_wide) {
@@ -54,7 +56,8 @@
   if (!policy_certificate_provider)
     return result;
   for (const auto& certificate :
-       policy_certificate_provider->GetAllAuthorityCertificates()) {
+       policy_certificate_provider->GetAllAuthorityCertificates(
+           chromeos::onc::CertificateScope::Default())) {
     net::ScopedCERTCertificate x509_cert =
         net::x509_util::CreateCERTCertificateFromX509Certificate(
             certificate.get());
diff --git a/chromeos/network/network_cert_loader_unittest.cc b/chromeos/network/network_cert_loader_unittest.cc
index ab54d71..56cb70a 100644
--- a/chromeos/network/network_cert_loader_unittest.cc
+++ b/chromeos/network/network_cert_loader_unittest.cc
@@ -13,6 +13,8 @@
 #include "base/files/file_util.h"
 #include "base/macros.h"
 #include "base/test/scoped_task_environment.h"
+#include "chromeos/network/onc/certificate_scope.h"
+#include "chromeos/network/policy_certificate_provider.h"
 #include "crypto/scoped_nss_types.h"
 #include "crypto/scoped_test_nss_db.h"
 #include "net/cert/nss_cert_database_chromeos.h"
@@ -35,28 +37,42 @@
     observer_list_.RemoveObserver(observer);
   }
 
-  net::CertificateList GetAllServerAndAuthorityCertificates() const override {
+  net::CertificateList GetAllServerAndAuthorityCertificates(
+      const chromeos::onc::CertificateScope& scope) const override {
     // NetworkCertLoader does not call this.
     NOTREACHED();
     return net::CertificateList();
   }
 
-  net::CertificateList GetAllAuthorityCertificates() const override {
+  net::CertificateList GetAllAuthorityCertificates(
+      const chromeos::onc::CertificateScope& scope) const override {
+    // NetworkCertLoader only retrieves profile-wide certificates.
+    EXPECT_EQ(chromeos::onc::CertificateScope::Default(), scope);
+
     return authority_certificates_;
   }
 
-  net::CertificateList GetWebTrustedCertificates() const override {
+  net::CertificateList GetWebTrustedCertificates(
+      const chromeos::onc::CertificateScope& scope) const override {
     // NetworkCertLoader does not call this.
     NOTREACHED();
     return net::CertificateList();
   }
 
-  net::CertificateList GetCertificatesWithoutWebTrust() const override {
+  net::CertificateList GetCertificatesWithoutWebTrust(
+      const chromeos::onc::CertificateScope& scope) const override {
     // NetworkCertLoader does not call this.
     NOTREACHED();
     return net::CertificateList();
   }
 
+  const std::set<std::string>& GetExtensionIdsWithPolicyCertificates()
+      const override {
+    // NetworkCertLoader does not call this.
+    NOTREACHED();
+    return kNoExtensions;
+  }
+
   void SetAuthorityCertificates(
       const net::CertificateList& authority_certificates) {
     authority_certificates_ = authority_certificates;
@@ -71,6 +87,7 @@
   base::ObserverList<PolicyCertificateProvider::Observer,
                      true /* check_empty */>::Unchecked observer_list_;
   net::CertificateList authority_certificates_;
+  const std::set<std::string> kNoExtensions = {};
 };
 
 bool IsCertInCertificateList(
diff --git a/chromeos/network/network_connection_handler_impl.cc b/chromeos/network/network_connection_handler_impl.cc
index 014c51d..167d178 100644
--- a/chromeos/network/network_connection_handler_impl.cc
+++ b/chromeos/network/network_connection_handler_impl.cc
@@ -465,7 +465,7 @@
   std::string profile;
   service_properties.GetStringWithoutPathExpansion(shill::kProfileProperty,
                                                    &profile);
-  ::onc::ONCSource onc_source = onc::ONC_SOURCE_NONE;
+  ::onc::ONCSource onc_source = ::onc::ONC_SOURCE_NONE;
   const base::DictionaryValue* policy =
       managed_configuration_handler_->FindPolicyByGuidAndProfile(guid, profile,
                                                                  &onc_source);
@@ -509,7 +509,7 @@
       // kL2tpIpsecClientCertIdProperty here (and also in VPNConfigView).
       if (!vpn_client_cert_id.empty() ||
           cert_config_from_policy.client_cert_type !=
-              onc::client_cert::kClientCertTypeNone) {
+              ::onc::client_cert::kClientCertTypeNone) {
         client_cert_type = client_cert::CONFIG_TYPE_IPSEC;
       }
     }
@@ -541,7 +541,7 @@
 
     // Check certificate properties from policy.
     if (cert_config_from_policy.client_cert_type ==
-        onc::client_cert::kPattern) {
+        ::onc::client_cert::kPattern) {
       if (!ClientCertResolver::ResolveClientCertificateSync(
               client_cert_type, cert_config_from_policy, &config_properties)) {
         NET_LOG(ERROR) << "Non matching certificate for: " << service_path;
diff --git a/chromeos/network/onc/certificate_scope.cc b/chromeos/network/onc/certificate_scope.cc
new file mode 100644
index 0000000..5da02e2
--- /dev/null
+++ b/chromeos/network/onc/certificate_scope.cc
@@ -0,0 +1,66 @@
+// Copyright 2019 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 "chromeos/network/onc/certificate_scope.h"
+
+#include <base/values.h>
+#include <tuple>
+
+#include "components/onc/onc_constants.h"
+
+namespace chromeos {
+namespace onc {
+
+CertificateScope::CertificateScope(const CertificateScope& other) = default;
+CertificateScope::CertificateScope(CertificateScope&& other) = default;
+CertificateScope::~CertificateScope() = default;
+
+CertificateScope::CertificateScope(const std::string& extension_id)
+    : extension_id_(extension_id) {}
+
+// static
+CertificateScope CertificateScope::ForExtension(
+    const std::string& extension_id) {
+  return CertificateScope(/*extension_id=*/extension_id);
+}
+
+// static
+CertificateScope CertificateScope::Default() {
+  return CertificateScope(/*extension_id=*/std::string());
+}
+
+// static
+base::Optional<CertificateScope> CertificateScope::ParseFromOncValue(
+    const base::Value& scope_dict) {
+  const std::string* scope_type_str =
+      scope_dict.FindStringKey(::onc::scope::kType);
+  const std::string* scope_id_str = scope_dict.FindStringKey(::onc::scope::kId);
+
+  if (!scope_type_str || !scope_id_str)
+    return base::nullopt;
+
+  if (*scope_type_str == ::onc::scope::kDefault)
+    return Default();
+  if (*scope_type_str == ::onc::scope::kExtension)
+    return ForExtension(*scope_id_str);
+
+  return base::nullopt;
+}
+
+CertificateScope& CertificateScope::operator=(const CertificateScope& other) =
+    default;
+
+bool CertificateScope::operator<(const CertificateScope& other) const {
+  return extension_id_ < other.extension_id_;
+}
+bool CertificateScope::operator==(const CertificateScope& other) const {
+  return extension_id_ == other.extension_id_;
+}
+
+bool CertificateScope::operator!=(const CertificateScope& other) const {
+  return !(*this == other);
+}
+
+}  // namespace onc
+}  // namespace chromeos
diff --git a/chromeos/network/onc/certificate_scope.h b/chromeos/network/onc/certificate_scope.h
new file mode 100644
index 0000000..8654954
--- /dev/null
+++ b/chromeos/network/onc/certificate_scope.h
@@ -0,0 +1,67 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_NETWORK_ONC_CERTIFICATE_SCOPE_H_
+#define CHROMEOS_NETWORK_ONC_CERTIFICATE_SCOPE_H_
+
+#include <string>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/optional.h"
+
+namespace base {
+class Value;
+}
+
+namespace chromeos {
+namespace onc {
+
+// Describes the scope a policy-provided certificate should be applied in.
+class COMPONENT_EXPORT(CHROMEOS_NETWORK) CertificateScope {
+ public:
+  CertificateScope(const CertificateScope& other);
+  CertificateScope(CertificateScope&& other);
+  ~CertificateScope();
+
+  // Creates a CertificateScope for a chrome extension with the id
+  // |extension_id|.
+  static CertificateScope ForExtension(const std::string& extension_id);
+
+  // Creates a CertificateScope for certificates that should apply in the
+  // default scope.
+  // For Chrome OS user ONC policy, this means that they apply in the whole user
+  // Profile.
+  // For Chrome OS device ONC policy, this means that they apply in the context
+  // of the sign-in webview and all sign-in screen extensions (however, only
+  // certificates without trust are respected as default-scoped device ONC
+  // policy specified certificates).
+  static CertificateScope Default();
+
+  // Parses a CertificateScope from |scope_dict|, which should be a dictionary
+  // containing the ONC "Scope" object.
+  static base::Optional<CertificateScope> ParseFromOncValue(
+      const base::Value& scope_dict);
+
+  CertificateScope& operator=(const CertificateScope& other);
+  bool operator<(const CertificateScope& other) const;
+  bool operator==(const CertificateScope& other) const;
+  bool operator!=(const CertificateScope& other) const;
+
+  bool is_extension_scoped() const { return !extension_id_.empty(); }
+  const std::string& extension_id() const { return extension_id_; }
+
+ private:
+  // If |extension_id| is empty, it means that the scope should not be
+  // restricted.
+  CertificateScope(const std::string& extension_id);
+
+  // If empty, it means that the scope should not be restricted to an extension.
+  std::string extension_id_;
+};
+
+}  // namespace onc
+}  // namespace chromeos
+
+#endif  // CHROMEOS_NETWORK_ONC_CERTIFICATE_SCOPE_H_
diff --git a/chromeos/network/onc/onc_parsed_certificates.cc b/chromeos/network/onc/onc_parsed_certificates.cc
index 67605dc..3457489c 100644
--- a/chromeos/network/onc/onc_parsed_certificates.cc
+++ b/chromeos/network/onc/onc_parsed_certificates.cc
@@ -22,6 +22,19 @@
 
 enum class CertificateType { kServer, kAuthority, kClient };
 
+// Parses the "Scope" of a policy-provided certificate.
+// If a Scope element is not present, returns CertificateScope::Default().
+// If a Scope element is present but malformed, returns an empty base::Optional.
+base::Optional<CertificateScope> ParseCertScope(
+    const base::Value& onc_certificate) {
+  const base::Value* scope_dict = onc_certificate.FindKeyOfType(
+      ::onc::certificate::kScope, base::Value::Type::DICTIONARY);
+  if (!scope_dict)
+    return CertificateScope::Default();
+
+  return CertificateScope::ParseFromOncValue(*scope_dict);
+}
+
 // Returns true if the certificate described by |onc_certificate| requests web
 // trust.
 bool HasWebTrustFlag(const base::Value& onc_certificate) {
@@ -74,11 +87,13 @@
 
 OncParsedCertificates::ServerOrAuthorityCertificate::
     ServerOrAuthorityCertificate(
+        CertificateScope scope,
         Type type,
         const std::string& guid,
         const scoped_refptr<net::X509Certificate>& certificate,
         bool web_trust_requested)
-    : type_(type),
+    : scope_(scope),
+      type_(type),
       guid_(guid),
       certificate_(certificate),
       web_trust_requested_(web_trust_requested) {}
@@ -100,6 +115,9 @@
 
 bool OncParsedCertificates::ServerOrAuthorityCertificate::operator==(
     const ServerOrAuthorityCertificate& other) const {
+  if (scope() != other.scope())
+    return false;
+
   if (type() != other.type())
     return false;
 
@@ -217,6 +235,12 @@
     ServerOrAuthorityCertificate::Type type,
     const std::string& guid,
     const base::Value& onc_certificate) {
+  base::Optional<CertificateScope> scope = ParseCertScope(onc_certificate);
+  if (!scope) {
+    LOG(ERROR) << "Certificate has malformed 'Scope'";
+    return false;
+  }
+
   bool web_trust_requested = HasWebTrustFlag(onc_certificate);
   const base::Value* x509_data_key = onc_certificate.FindKeyOfType(
       ::onc::certificate::kX509, base::Value::Type::STRING);
@@ -241,7 +265,7 @@
   }
 
   server_or_authority_certificates_.push_back(ServerOrAuthorityCertificate(
-      type, guid, certificate, web_trust_requested));
+      scope.value(), type, guid, certificate, web_trust_requested));
   return true;
 }
 
diff --git a/chromeos/network/onc/onc_parsed_certificates.h b/chromeos/network/onc/onc_parsed_certificates.h
index 7f4337e2..606aaca77 100644
--- a/chromeos/network/onc/onc_parsed_certificates.h
+++ b/chromeos/network/onc/onc_parsed_certificates.h
@@ -11,6 +11,7 @@
 #include "base/component_export.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "chromeos/network/onc/certificate_scope.h"
 
 namespace base {
 class Value;
@@ -33,6 +34,7 @@
     enum class Type { kServer, kAuthority };
 
     ServerOrAuthorityCertificate(
+        CertificateScope scope,
         Type type,
         const std::string& guid,
         const scoped_refptr<net::X509Certificate>& certificate,
@@ -47,6 +49,8 @@
     bool operator==(const ServerOrAuthorityCertificate& other) const;
     bool operator!=(const ServerOrAuthorityCertificate& other) const;
 
+    CertificateScope scope() const { return scope_; }
+
     Type type() const { return type_; }
 
     const std::string& guid() const { return guid_; }
@@ -58,6 +62,7 @@
     bool web_trust_requested() const { return web_trust_requested_; }
 
    private:
+    CertificateScope scope_;
     Type type_;
     std::string guid_;
     scoped_refptr<net::X509Certificate> certificate_;
diff --git a/chromeos/network/onc/onc_parsed_certificates_unittest.cc b/chromeos/network/onc/onc_parsed_certificates_unittest.cc
index 9d5f426..2473fed 100644
--- a/chromeos/network/onc/onc_parsed_certificates_unittest.cc
+++ b/chromeos/network/onc/onc_parsed_certificates_unittest.cc
@@ -175,6 +175,7 @@
   EXPECT_EQ(
       OncParsedCertificates::ServerOrAuthorityCertificate::Type::kAuthority,
       trusted_authority_cert.type());
+  EXPECT_EQ(CertificateScope::Default(), trusted_authority_cert.scope());
   EXPECT_EQ("{trusted-cert}", trusted_authority_cert.guid());
   EXPECT_TRUE(trusted_authority_cert.web_trust_requested());
   EXPECT_EQ("Test Root CA",
@@ -186,12 +187,65 @@
   EXPECT_EQ(
       OncParsedCertificates::ServerOrAuthorityCertificate::Type::kAuthority,
       trusted_authority_cert.type());
+  EXPECT_EQ(CertificateScope::Default(), trusted_authority_cert.scope());
   EXPECT_EQ("{untrusted-cert}", untrusted_authority_cert.guid());
   EXPECT_FALSE(untrusted_authority_cert.web_trust_requested());
   EXPECT_EQ("127.0.0.1",
             untrusted_authority_cert.certificate()->subject().common_name);
 }
 
+TEST_F(OncParsedCertificatesTest, AuthorityCertsScope) {
+  const char onc_certificates_json[] = R"(
+      [
+        { "GUID": "{extension-scoped-cert}",
+          "Type": "Authority",
+          "TrustBits": [
+             "Web"
+          ],
+          "Scope": {
+            "Type": "Extension",
+            "Id": "fake-extension-id"
+          },
+          "X509": "-----BEGIN CERTIFICATE-----\n
+      MIIC8zCCAdugAwIBAgIJALF9qhLor0+aMA0GCSqGSIb3DQEBBQUAMBcxFTATBgNV\n
+      BAMMDFRlc3QgUm9vdCBDQTAeFw0xNDA4MTQwMzA1MjlaFw0yNDA4MTEwMzA1Mjla\n
+      MBcxFTATBgNVBAMMDFRlc3QgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP\n
+      ADCCAQoCggEBALZJQeNCAVGofzx6cdP7zZE1F4QajvY2x9FwHfqG8267dm/oMi43\n
+      /TiSPWjkin1CMxRGG9wE9pFuVEDECgn97C1i4l7huiycwbFgTNrH+CJcgiBlQh5W\n
+      d3VP65AsSupXDiKNbJWsEerM1+72cA0J3aY1YV3Jdm2w8h6/MIbYd1I2lZcO0UbF\n
+      7YE9G7DyYZU8wUA4719dumGf7yucn4WJdHBj1XboNX7OAeHzERGQHA31/Y3OEGyt\n
+      fFUaIW/XLfR4FeovOL2RnjwdB0b1Q8GCi68SU2UZimlpZgay2gv6KgChKhWESfEB\n
+      v5swBtAVoB+dUZFH4VNf717swmF5whSfxOMCAwEAAaNCMEAwDwYDVR0TAQH/BAUw\n
+      AwEB/zAdBgNVHQ4EFgQUvPcw0TzA8nn675/JbFyT84poq4MwDgYDVR0PAQH/BAQD\n
+      AgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBXByn7f+j/sObYWGrDkKE4HLTzaLHs6Ikj\n
+      JNeo8iHDYOSkSVwAv9/HgniAKxj3rd3QYl6nsMzwqrTOcBJZZWd2BQAYmv/EKhfj\n
+      8VXYvlxe68rLU4cQ1QkyNqdeQfRT2n5WYNJ+TpqlCF9ddennMMsi6e8ZSYOlI6H4\n
+      YEzlNtU5eBjxXr/OqgtTgSx4qQpr2xMQIRR/G3A9iRpAigYsXVAZYvnHRYnyPWYF\n
+      PX11W1UegEJyoZp8bQp09u6mIWw6mPt3gl/ya1bm3ZuOUPDGrv3qpgUHqSYGVrOy\n
+      2bI3oCE+eQYfuVG+9LFJTZC1M+UOx15bQMVqBNFDepRqpE9h/ILg\n
+      -----END CERTIFICATE-----" }
+      ])";
+
+  std::unique_ptr<OncParsedCertificates> onc_parsed_certificates;
+  ASSERT_TRUE(ReadFromJSON(onc_certificates_json, &onc_parsed_certificates));
+
+  EXPECT_FALSE(onc_parsed_certificates->has_error());
+  ASSERT_EQ(1u,
+            onc_parsed_certificates->server_or_authority_certificates().size());
+
+  const OncParsedCertificates::ServerOrAuthorityCertificate& authority_cert =
+      onc_parsed_certificates->server_or_authority_certificates()[0];
+  EXPECT_EQ(
+      OncParsedCertificates::ServerOrAuthorityCertificate::Type::kAuthority,
+      authority_cert.type());
+  EXPECT_EQ(CertificateScope::ForExtension("fake-extension-id"),
+            authority_cert.scope());
+  EXPECT_EQ("{extension-scoped-cert}", authority_cert.guid());
+  EXPECT_TRUE(authority_cert.web_trust_requested());
+  EXPECT_EQ("Test Root CA",
+            authority_cert.certificate()->subject().common_name);
+}
+
 TEST_F(OncParsedCertificatesTest, UnknownTrustBitsIgnored) {
   const char onc_certificates_json[] =R"(
       [
diff --git a/chromeos/network/onc/onc_signature.cc b/chromeos/network/onc/onc_signature.cc
index 58576d8e..475d9c8 100644
--- a/chromeos/network/onc/onc_signature.cc
+++ b/chromeos/network/onc/onc_signature.cc
@@ -362,6 +362,7 @@
 
 const OncFieldSignature certificate_fields[] = {
     {::onc::certificate::kGUID, &kStringSignature},
+    {::onc::certificate::kScope, &kScopeSignature},
     {::onc::certificate::kPKCS12, &kStringSignature},
     {::onc::kRemove, &kBoolSignature},
     {::onc::certificate::kTrustBits, &kStringListSignature},
@@ -369,6 +370,11 @@
     {::onc::certificate::kX509, &kStringSignature},
     {NULL}};
 
+const OncFieldSignature scope_fields[] = {
+    {::onc::scope::kType, &kStringSignature},
+    {::onc::scope::kId, &kStringSignature},
+    {nullptr}};
+
 const OncFieldSignature toplevel_configuration_fields[] = {
     {::onc::toplevel_config::kCertificates, &kCertificateListSignature},
     {::onc::toplevel_config::kNetworkConfigurations,
@@ -430,6 +436,8 @@
                                           wifi_fields, NULL};
 const OncValueSignature kCertificateSignature = {base::Value::Type::DICTIONARY,
                                                  certificate_fields, NULL};
+const OncValueSignature kScopeSignature = {base::Value::Type::DICTIONARY,
+                                           scope_fields, nullptr};
 const OncValueSignature kNetworkConfigurationSignature = {
     base::Value::Type::DICTIONARY, network_configuration_fields, NULL};
 const OncValueSignature kGlobalNetworkConfigurationSignature = {
diff --git a/chromeos/network/onc/onc_signature.h b/chromeos/network/onc/onc_signature.h
index c900920..5693c8d 100644
--- a/chromeos/network/onc/onc_signature.h
+++ b/chromeos/network/onc/onc_signature.h
@@ -80,6 +80,8 @@
 COMPONENT_EXPORT(CHROMEOS_NETWORK)
 extern const OncValueSignature kCertificateSignature;
 COMPONENT_EXPORT(CHROMEOS_NETWORK)
+extern const OncValueSignature kScopeSignature;
+COMPONENT_EXPORT(CHROMEOS_NETWORK)
 extern const OncValueSignature kNetworkConfigurationSignature;
 COMPONENT_EXPORT(CHROMEOS_NETWORK)
 extern const OncValueSignature kGlobalNetworkConfigurationSignature;
diff --git a/chromeos/network/onc/onc_validator.cc b/chromeos/network/onc/onc_validator.cc
index 3dd6f07..b8da2d6 100644
--- a/chromeos/network/onc/onc_validator.cc
+++ b/chromeos/network/onc/onc_validator.cc
@@ -19,6 +19,7 @@
 #include "base/strings/string_util.h"
 #include "base/values.h"
 #include "chromeos/network/onc/onc_signature.h"
+#include "components/crx_file/id_util.h"
 
 namespace chromeos {
 namespace onc {
@@ -162,6 +163,8 @@
       valid = ValidateEAP(repaired.get());
     } else if (&signature == &kCertificateSignature) {
       valid = ValidateCertificate(repaired.get());
+    } else if (&signature == &kScopeSignature) {
+      valid = ValidateScope(repaired.get());
     } else if (&signature == &kTetherWithStateSignature) {
       valid = ValidateTether(repaired.get());
     }
@@ -1117,6 +1120,33 @@
   return !error_on_missing_field_ || all_required_exist;
 }
 
+bool Validator::ValidateScope(base::DictionaryValue* result) {
+  using namespace ::onc::scope;
+
+  const char* const kValidTypes[] = {kDefault, kExtension};
+  const std::vector<const char*> valid_types(toVector(kValidTypes));
+  if (FieldExistsAndHasNoValidValue(*result, kType, valid_types) ||
+      FieldExistsAndIsEmpty(*result, kId)) {
+    return false;
+  }
+
+  bool all_required_exist = RequireField(*result, kType);
+  const std::string* type_string = result->FindStringKey(kType);
+  if (type_string && *type_string == kExtension) {
+    all_required_exist &= RequireField(*result, kId);
+    // Check Id validity for type 'Extension'.
+    const std::string* id_string = result->FindStringKey(kId);
+    if (id_string && !crx_file::id_util::IdIsValid(*id_string)) {
+      std::ostringstream msg;
+      msg << "Field '" << kId << "' is not a valid extension id.";
+      AddValidationIssue(false /* is_error */, msg.str());
+      return false;
+    }
+  }
+
+  return !error_on_missing_field_ || all_required_exist;
+}
+
 bool Validator::ValidateTether(base::DictionaryValue* result) {
   using namespace ::onc::tether;
 
diff --git a/chromeos/network/onc/onc_validator.h b/chromeos/network/onc/onc_validator.h
index 1588226a..beadc85 100644
--- a/chromeos/network/onc/onc_validator.h
+++ b/chromeos/network/onc/onc_validator.h
@@ -191,6 +191,7 @@
   bool ValidateProxyLocation(base::DictionaryValue* result);
   bool ValidateEAP(base::DictionaryValue* result);
   bool ValidateCertificate(base::DictionaryValue* result);
+  bool ValidateScope(base::DictionaryValue* result);
   bool ValidateTether(base::DictionaryValue* result);
 
   bool IsValidValue(const std::string& field_value,
diff --git a/chromeos/network/onc/onc_validator_unittest.cc b/chromeos/network/onc/onc_validator_unittest.cc
index 7ac37b1..40ad0e4 100644
--- a/chromeos/network/onc/onc_validator_unittest.cc
+++ b/chromeos/network/onc/onc_validator_unittest.cc
@@ -234,7 +234,11 @@
                   &kNetworkConfigurationSignature,
                   false),
         OncParams("arc_vpn.onc", &kNetworkConfigurationSignature, false),
-        OncParams("tether.onc", &kNetworkWithStateSignature, false)));
+        OncParams("tether.onc", &kNetworkWithStateSignature, false),
+        OncParams("cert_with_valid_scope.onc", &kCertificateSignature, false),
+        OncParams("cert_with_explicit_default_scope.onc",
+                  &kCertificateSignature,
+                  false)));
 
 namespace {
 
@@ -575,7 +579,28 @@
         std::make_pair(OncParams("tether-signal-strength-over-100",
                                  &kNetworkWithStateSignature,
                                  true),
-                       ExpectBothNotValid("", ""))));
+                       ExpectBothNotValid("", "")),
+        std::make_pair(
+            OncParams("invalid-scope-due-to-type", &kScopeSignature, true),
+            ExpectBothNotValid("", "")),
+        std::make_pair(OncParams("invalid-scope-due-to-missing-id",
+                                 &kScopeSignature,
+                                 true),
+                       ExpectBothNotValid("",
+                                          "invalid-scope-due-to-missing-id")),
+        std::make_pair(OncParams("invalid-scope-due-to-invalid-id-length",
+                                 &kScopeSignature,
+                                 true),
+                       ExpectBothNotValid("", "")),
+        std::make_pair(OncParams("invalid-scope-due-to-invalid-id-character",
+                                 &kScopeSignature,
+                                 true),
+                       ExpectBothNotValid("", "")),
+        std::make_pair(
+            OncParams("invalid-scope-due-to-missing-type",
+                      &kScopeSignature,
+                      true),
+            ExpectBothNotValid("", "invalid-scope-due-to-missing-type"))));
 
 }  // namespace onc
 }  // namespace chromeos
diff --git a/chromeos/network/policy_certificate_provider.h b/chromeos/network/policy_certificate_provider.h
index e03998b..fd49d7e 100644
--- a/chromeos/network/policy_certificate_provider.h
+++ b/chromeos/network/policy_certificate_provider.h
@@ -5,10 +5,13 @@
 #ifndef CHROMEOS_NETWORK_POLICY_CERTIFICATE_PROVIDER_H_
 #define CHROMEOS_NETWORK_POLICY_CERTIFICATE_PROVIDER_H_
 
+#include <set>
+#include <string>
 #include <vector>
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "chromeos/network/onc/certificate_scope.h"
 
 namespace net {
 class X509Certificate;
@@ -38,25 +41,34 @@
 
   // Returns all server and authority certificates successfully parsed from ONC,
   // independent of their trust bits.
-  virtual net::CertificateList GetAllServerAndAuthorityCertificates() const = 0;
+  virtual net::CertificateList GetAllServerAndAuthorityCertificates(
+      const chromeos::onc::CertificateScope& scope) const = 0;
 
   // Returns all authority certificates successfully parsed from ONC,
   // independent of their trust bits.
-  virtual net::CertificateList GetAllAuthorityCertificates() const = 0;
+  virtual net::CertificateList GetAllAuthorityCertificates(
+      const chromeos::onc::CertificateScope& scope) const = 0;
 
   // Returns the server and authority certificates which were successfully
   // parsed from ONC and were granted web trust. This means that the
   // certificates had the "Web" trust bit set, and this
   // UserNetworkConfigurationUpdater instance was created with
   // |allow_trusted_certs_from_policy| = true.
-  virtual net::CertificateList GetWebTrustedCertificates() const = 0;
+  virtual net::CertificateList GetWebTrustedCertificates(
+      const chromeos::onc::CertificateScope& scope) const = 0;
 
   // Returns the server and authority certificates which were successfully
   // parsed from ONC and did not request or were not granted web trust.
   // This is equivalent to calling |GetAllServerAndAuthorityCertificates| and
   // then removing all certificates returned by |GetWebTrustedCertificates| from
   // the result.
-  virtual net::CertificateList GetCertificatesWithoutWebTrust() const = 0;
+  virtual net::CertificateList GetCertificatesWithoutWebTrust(
+      const chromeos::onc::CertificateScope& scope) const = 0;
+
+  // Lists extension IDs for which policy-provided certificates have been
+  // specified.
+  virtual const std::set<std::string>& GetExtensionIdsWithPolicyCertificates()
+      const = 0;
 };
 
 }  // namespace chromeos
diff --git a/chromeos/services/secure_channel/ble_scanner_impl_unittest.cc b/chromeos/services/secure_channel/ble_scanner_impl_unittest.cc
index 2a31d56..2b6550e 100644
--- a/chromeos/services/secure_channel/ble_scanner_impl_unittest.cc
+++ b/chromeos/services/secure_channel/ble_scanner_impl_unittest.cc
@@ -160,12 +160,12 @@
         service_data, expected_remote_device, is_background_advertisement);
 
     size_t num_results_before_call = results.size();
-    FakeBluetoothDevice* fake_bluetooth_device =
+    std::unique_ptr<FakeBluetoothDevice> fake_bluetooth_device =
         SimulateScanResult(service_data);
     EXPECT_EQ(num_results_before_call + 1u, results.size());
 
     EXPECT_EQ(expected_remote_device, std::get<0>(results.back()));
-    EXPECT_EQ(fake_bluetooth_device, std::get<1>(results.back()));
+    EXPECT_EQ(fake_bluetooth_device.get(), std::get<1>(results.back()));
     EXPECT_EQ(is_background_advertisement ? ConnectionRole::kListenerRole
                                           : ConnectionRole::kInitiatorRole,
               std::get<2>(results.back()));
@@ -209,7 +209,8 @@
   }
 
  private:
-  FakeBluetoothDevice* SimulateScanResult(const std::string& service_data) {
+  std::unique_ptr<FakeBluetoothDevice> SimulateScanResult(
+      const std::string& service_data) {
     static const int16_t kFakeRssi = -70;
     static const std::vector<uint8_t> kFakeEir;
 
@@ -228,7 +229,7 @@
                                            kFakeRssi, kFakeEir);
     }
 
-    return fake_bluetooth_device.get();
+    return fake_bluetooth_device;
   }
 
   const multidevice::RemoteDeviceRefList test_devices_;
diff --git a/chromeos/test/data/network/cert_with_explicit_default_scope.onc b/chromeos/test/data/network/cert_with_explicit_default_scope.onc
new file mode 100644
index 0000000..b18244e5
--- /dev/null
+++ b/chromeos/test/data/network/cert_with_explicit_default_scope.onc
@@ -0,0 +1,9 @@
+{
+      "GUID": "{f998f760-272b-6939-4c2beffe428697ab}",
+      "Scope": {
+        "Type": "Default"
+      },
+      "Type": "Authority",
+      "X509": "MIIDojCCAwugAwIBAgIJAKGvi5ZgEWDVMA0GCSqGSIb3DQEBBAUAMIGTMRUwEwYDVQQKEwxHb29nbGUsIEluYy4xETAPBgNVBAsTCENocm9tZU9TMSIwIAYJKoZIhvcNAQkBFhNnc3BlbmNlckBnb29nbGUuY29tMRowGAYDVQQHExFNb3VudGFpbiBWaWV3LCBDQTELMAkGA1UECBMCQ0ExCzAJBgNVBAYTAlVTMQ0wCwYDVQQDEwRsbWFvMB4XDTExMDMxNjIzNDcxMFoXDTEyMDMxNTIzNDcxMFowgZMxFTATBgNVBAoTDEdvb2dsZSwgSW5jLjERMA8GA1UECxMIQ2hyb21lT1MxIjAgBgkqhkiG9w0BCQEWE2dzcGVuY2VyQGdvb2dsZS5jb20xGjAYBgNVBAcTEU1vdW50YWluIFZpZXcsIENBMQswCQYDVQQIEwJDQTELMAkGA1UEBhMCVVMxDTALBgNVBAMTBGxtYW8wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMDX6BQz2JUzIAVjetiXxDznd2wdqVqVHfNkbSRW+xBywgqUaIXmFEGUol7VzPfmeFV8o8ok/eFlQB0h6ycqgwwMd0KjtJs2ys/k0F5GuN0G7fsgr+NRnhVgxj21yF6gYTN/8a9kscla/svdmp8ekexbALFnghbLBx3CgcqUxT+tAgMBAAGjgfswgfgwDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQUbYygbSkl4kpjCNuxoezFGupA97UwgcgGA1UdIwSBwDCBvYAUbYygbSkl4kpjCNuxoezFGupA97WhgZmkgZYwgZMxFTATBgNVBAoTDEdvb2dsZSwgSW5jLjERMA8GA1UECxMIQ2hyb21lT1MxIjAgBgkqhkiG9w0BCQEWE2dzcGVuY2VyQGdvb2dsZS5jb20xGjAYBgNVBAcTEU1vdW50YWluIFZpZXcsIENBMQswCQYDVQQIEwJDQTELMAkGA1UEBhMCVVMxDTALBgNVBAMTBGxtYW+CCQChr4uWYBFg1TANBgkqhkiG9w0BAQQFAAOBgQCDq9wiQ4uVuf1CQU3sXfXCy1yqi5m8AsO9FxHvah5/SVFNwKllqTfedpCaWEswJ55YAojW9e+pY2Fh3Fo/Y9YkF88KCtLuBjjqDKCRLxF4LycjHODKyQQ7mN/t5AtP9yKOsNvWF+M4IfReg51kohau6FauQx87by5NIRPdkNPvkQ=="
+    }
+
diff --git a/chromeos/test/data/network/cert_with_valid_scope.onc b/chromeos/test/data/network/cert_with_valid_scope.onc
new file mode 100644
index 0000000..fcb30cb
--- /dev/null
+++ b/chromeos/test/data/network/cert_with_valid_scope.onc
@@ -0,0 +1,9 @@
+{
+      "GUID": "{f998f760-272b-6939-4c2beffe428697ab}",
+      "Scope": {
+        "Type": "Extension",
+	"Id": "ngjobkbdodapjbbncmagbccommkggmnj"
+      },
+      "Type": "Authority",
+      "X509": "MIIDojCCAwugAwIBAgIJAKGvi5ZgEWDVMA0GCSqGSIb3DQEBBAUAMIGTMRUwEwYDVQQKEwxHb29nbGUsIEluYy4xETAPBgNVBAsTCENocm9tZU9TMSIwIAYJKoZIhvcNAQkBFhNnc3BlbmNlckBnb29nbGUuY29tMRowGAYDVQQHExFNb3VudGFpbiBWaWV3LCBDQTELMAkGA1UECBMCQ0ExCzAJBgNVBAYTAlVTMQ0wCwYDVQQDEwRsbWFvMB4XDTExMDMxNjIzNDcxMFoXDTEyMDMxNTIzNDcxMFowgZMxFTATBgNVBAoTDEdvb2dsZSwgSW5jLjERMA8GA1UECxMIQ2hyb21lT1MxIjAgBgkqhkiG9w0BCQEWE2dzcGVuY2VyQGdvb2dsZS5jb20xGjAYBgNVBAcTEU1vdW50YWluIFZpZXcsIENBMQswCQYDVQQIEwJDQTELMAkGA1UEBhMCVVMxDTALBgNVBAMTBGxtYW8wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMDX6BQz2JUzIAVjetiXxDznd2wdqVqVHfNkbSRW+xBywgqUaIXmFEGUol7VzPfmeFV8o8ok/eFlQB0h6ycqgwwMd0KjtJs2ys/k0F5GuN0G7fsgr+NRnhVgxj21yF6gYTN/8a9kscla/svdmp8ekexbALFnghbLBx3CgcqUxT+tAgMBAAGjgfswgfgwDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQUbYygbSkl4kpjCNuxoezFGupA97UwgcgGA1UdIwSBwDCBvYAUbYygbSkl4kpjCNuxoezFGupA97WhgZmkgZYwgZMxFTATBgNVBAoTDEdvb2dsZSwgSW5jLjERMA8GA1UECxMIQ2hyb21lT1MxIjAgBgkqhkiG9w0BCQEWE2dzcGVuY2VyQGdvb2dsZS5jb20xGjAYBgNVBAcTEU1vdW50YWluIFZpZXcsIENBMQswCQYDVQQIEwJDQTELMAkGA1UEBhMCVVMxDTALBgNVBAMTBGxtYW+CCQChr4uWYBFg1TANBgkqhkiG9w0BAQQFAAOBgQCDq9wiQ4uVuf1CQU3sXfXCy1yqi5m8AsO9FxHvah5/SVFNwKllqTfedpCaWEswJ55YAojW9e+pY2Fh3Fo/Y9YkF88KCtLuBjjqDKCRLxF4LycjHODKyQQ7mN/t5AtP9yKOsNvWF+M4IfReg51kohau6FauQx87by5NIRPdkNPvkQ=="
+    }
diff --git a/chromeos/test/data/network/invalid_settings_with_repairs.json b/chromeos/test/data/network/invalid_settings_with_repairs.json
index a3c19bfc..e42ece4 100644
--- a/chromeos/test/data/network/invalid_settings_with_repairs.json
+++ b/chromeos/test/data/network/invalid_settings_with_repairs.json
@@ -582,5 +582,23 @@
       "Certificates": [],
       "Type": "UnencryptedConfiguration",
       "UnknownField3": [],
+    },
+    "invalid-scope-due-to-type": {
+      "Type": "Bla",
+      "Id": "ngjobkbdodapjbbncmagbccommkggmnj"
+    },
+    "invalid-scope-due-to-missing-id": {
+      "Type": "Extension",
+    },
+    "invalid-scope-due-to-invalid-id-length": {
+      "Type": "Extension",
+      "Id": "blabla"
+    },
+    "invalid-scope-due-to-invalid-id-character": {
+      "Type": "Extension",
+      "Id": "9gjobkbdodapjbbncmagbccommkggmnj"
+    },
+    "invalid-scope-due-to-missing-type": {
+      "Id": "ngjobkbdodapjbbncmagbccommkggmnj"
     }
 }
diff --git a/components/autofill/core/browser/payments/local_card_migration_manager.cc b/components/autofill/core/browser/payments/local_card_migration_manager.cc
index 3fb4f87..f3dae8c54 100644
--- a/components/autofill/core/browser/payments/local_card_migration_manager.cc
+++ b/components/autofill/core/browser/payments/local_card_migration_manager.cc
@@ -389,7 +389,7 @@
   // Pops up a larger, modal dialog showing the local cards to be uploaded.
   client_->ConfirmMigrateLocalCardToCloud(
       std::move(legal_message_),
-      client_->GetIdentityManager()->GetPrimaryAccountInfo().email,
+      personal_data_manager_->GetAccountInfoForPaymentsServer().email,
       migratable_credit_cards_,
       base::BindOnce(
           &LocalCardMigrationManager::OnUserAcceptedMainMigrationDialog,
diff --git a/components/feature_engagement/public/feature_constants.cc b/components/feature_engagement/public/feature_constants.cc
index 988ea45..c97ddfc 100644
--- a/components/feature_engagement/public/feature_constants.cc
+++ b/components/feature_engagement/public/feature_constants.cc
@@ -105,7 +105,7 @@
 const base::Feature kIPHNewIncognitoTabTipFeature{
     "IPH_NewIncognitoTabTip", base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kIPHBadgedReadingListFeature{
-    "IPH_BadgedReadingList", base::FEATURE_ENABLED_BY_DEFAULT};
+    "IPH_BadgedReadingList", base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kIPHBadgedTranslateManualTriggerFeature{
     "IPH_BadgedTranslateManualTrigger", base::FEATURE_DISABLED_BY_DEFAULT};
 #endif  // defined(OS_IOS)
diff --git a/components/infobars/core/infobar_delegate.cc b/components/infobars/core/infobar_delegate.cc
index 59ae71e..52e5e42 100644
--- a/components/infobars/core/infobar_delegate.cc
+++ b/components/infobars/core/infobar_delegate.cc
@@ -84,38 +84,15 @@
   return nullptr;
 }
 
-InsecureContentInfoBarDelegate*
-    InfoBarDelegate::AsInsecureContentInfoBarDelegate() {
-  return nullptr;
-}
-
-NativeAppInfoBarDelegate* InfoBarDelegate::AsNativeAppInfoBarDelegate() {
-  return nullptr;
-}
-
 PopupBlockedInfoBarDelegate* InfoBarDelegate::AsPopupBlockedInfoBarDelegate() {
   return nullptr;
 }
 
-RegisterProtocolHandlerInfoBarDelegate*
-    InfoBarDelegate::AsRegisterProtocolHandlerInfoBarDelegate() {
-  return nullptr;
-}
-
-ScreenCaptureInfoBarDelegate*
-    InfoBarDelegate::AsScreenCaptureInfoBarDelegate() {
-  return nullptr;
-}
-
 ThemeInstalledInfoBarDelegate*
     InfoBarDelegate::AsThemePreviewInfobarDelegate() {
   return nullptr;
 }
 
-ThreeDAPIInfoBarDelegate* InfoBarDelegate::AsThreeDAPIInfoBarDelegate() {
-  return nullptr;
-}
-
 translate::TranslateInfoBarDelegate*
     InfoBarDelegate::AsTranslateInfoBarDelegate() {
   return nullptr;
diff --git a/components/infobars/core/infobar_delegate.h b/components/infobars/core/infobar_delegate.h
index d0a528d8..a4d6f445 100644
--- a/components/infobars/core/infobar_delegate.h
+++ b/components/infobars/core/infobar_delegate.h
@@ -12,13 +12,8 @@
 
 class ConfirmInfoBarDelegate;
 class HungRendererInfoBarDelegate;
-class InsecureContentInfoBarDelegate;
-class NativeAppInfoBarDelegate;
 class PopupBlockedInfoBarDelegate;
-class RegisterProtocolHandlerInfoBarDelegate;
-class ScreenCaptureInfoBarDelegate;
 class ThemeInstalledInfoBarDelegate;
-class ThreeDAPIInfoBarDelegate;
 
 #if defined(OS_ANDROID)
 namespace offline_pages {
@@ -232,14 +227,8 @@
   // Type-checking downcast routines:
   virtual ConfirmInfoBarDelegate* AsConfirmInfoBarDelegate();
   virtual HungRendererInfoBarDelegate* AsHungRendererInfoBarDelegate();
-  virtual InsecureContentInfoBarDelegate* AsInsecureContentInfoBarDelegate();
-  virtual NativeAppInfoBarDelegate* AsNativeAppInfoBarDelegate();
   virtual PopupBlockedInfoBarDelegate* AsPopupBlockedInfoBarDelegate();
-  virtual RegisterProtocolHandlerInfoBarDelegate*
-      AsRegisterProtocolHandlerInfoBarDelegate();
-  virtual ScreenCaptureInfoBarDelegate* AsScreenCaptureInfoBarDelegate();
   virtual ThemeInstalledInfoBarDelegate* AsThemePreviewInfobarDelegate();
-  virtual ThreeDAPIInfoBarDelegate* AsThreeDAPIInfoBarDelegate();
   virtual translate::TranslateInfoBarDelegate* AsTranslateInfoBarDelegate();
 #if defined(OS_ANDROID)
   virtual offline_pages::OfflinePageInfoBarDelegate*
diff --git a/components/keyed_service/content/browser_context_keyed_service_factory.h b/components/keyed_service/content/browser_context_keyed_service_factory.h
index 1df7c684..5a3b2ccf 100644
--- a/components/keyed_service/content/browser_context_keyed_service_factory.h
+++ b/components/keyed_service/content/browser_context_keyed_service_factory.h
@@ -110,7 +110,7 @@
   // and the default implementation removes it from |mapping_| and deletes
   // the pointer.
   virtual void BrowserContextShutdown(content::BrowserContext* context);
-  virtual void BrowserContextDestroyed(content::BrowserContext* context);
+  void BrowserContextDestroyed(content::BrowserContext* context);
 
  private:
   friend class BrowserContextDependencyManagerUnittests;
diff --git a/components/omnibox/browser/autocomplete_match.cc b/components/omnibox/browser/autocomplete_match.cc
index 3a6d677..313bac8 100644
--- a/components/omnibox/browser/autocomplete_match.cc
+++ b/components/omnibox/browser/autocomplete_match.cc
@@ -388,13 +388,57 @@
 }
 
 // static
-bool AutocompleteMatch::MoreRelevant(const AutocompleteMatch& elem1,
-                                     const AutocompleteMatch& elem2) {
+bool AutocompleteMatch::MoreRelevant(const AutocompleteMatch& match1,
+                                     const AutocompleteMatch& match2) {
   // For equal-relevance matches, we sort alphabetically, so that providers
   // who return multiple elements at the same priority get a "stable" sort
   // across multiple updates.
-  return (elem1.relevance == elem2.relevance) ?
-      (elem1.contents < elem2.contents) : (elem1.relevance > elem2.relevance);
+  return (match1.relevance == match2.relevance)
+             ? (match1.contents < match2.contents)
+             : (match1.relevance > match2.relevance);
+}
+
+// static
+bool AutocompleteMatch::BetterDuplicate(const AutocompleteMatch& match1,
+                                        const AutocompleteMatch& match2) {
+  // Prefer the Entity Match over the non-entity match, if they have the same
+  // |fill_into_edit| value.
+  if (match1.type == AutocompleteMatchType::SEARCH_SUGGEST_ENTITY &&
+      match2.type != AutocompleteMatchType::SEARCH_SUGGEST_ENTITY &&
+      match1.fill_into_edit == match2.fill_into_edit) {
+    return true;
+  }
+  if (match1.type != AutocompleteMatchType::SEARCH_SUGGEST_ENTITY &&
+      match2.type == AutocompleteMatchType::SEARCH_SUGGEST_ENTITY &&
+      match1.fill_into_edit == match2.fill_into_edit) {
+    return false;
+  }
+
+  // Prefer matches allowed to be the default match.
+  if (match1.allowed_to_be_default_match && !match2.allowed_to_be_default_match)
+    return true;
+  if (!match1.allowed_to_be_default_match && match2.allowed_to_be_default_match)
+    return false;
+
+  // Prefer document suggestions.
+  if (match1.type == AutocompleteMatchType::DOCUMENT_SUGGESTION &&
+      match2.type != AutocompleteMatchType::DOCUMENT_SUGGESTION) {
+    return true;
+  }
+  if (match1.type != AutocompleteMatchType::DOCUMENT_SUGGESTION &&
+      match2.type == AutocompleteMatchType::DOCUMENT_SUGGESTION) {
+    return false;
+  }
+
+  // By default, simply prefer the more relevant match.
+  return MoreRelevant(match1, match2);
+}
+
+// static
+bool AutocompleteMatch::BetterDuplicateByIterator(
+    const std::vector<AutocompleteMatch>::const_iterator it1,
+    const std::vector<AutocompleteMatch>::const_iterator it2) {
+  return BetterDuplicate(*it1, *it2);
 }
 
 // static
@@ -995,6 +1039,25 @@
   return ShouldShowTabMatch();
 }
 
+void AutocompleteMatch::UpgradeMatchWithPropertiesFrom(
+    const AutocompleteMatch& duplicate_match) {
+  // For Entity Matches, absorb the duplicate match's |allowed_to_be_default|
+  // and |inline_autocomplete| properties.
+  if (type == AutocompleteMatchType::SEARCH_SUGGEST_ENTITY &&
+      fill_into_edit == duplicate_match.fill_into_edit &&
+      duplicate_match.allowed_to_be_default_match) {
+    allowed_to_be_default_match = true;
+    if (inline_autocompletion.empty())
+      inline_autocompletion = duplicate_match.inline_autocompletion;
+  }
+
+  // And always absorb the higher relevance score of duplicates.
+  if (duplicate_match.relevance > relevance) {
+    RecordAdditionalInfo(kACMatchPropertyScoreBoostedFrom, relevance);
+    relevance = duplicate_match.relevance;
+  }
+}
+
 #if DCHECK_IS_ON()
 void AutocompleteMatch::Validate() const {
   ValidateClassifications(contents, contents_class);
diff --git a/components/omnibox/browser/autocomplete_match.h b/components/omnibox/browser/autocomplete_match.h
index 6c471d4..210451c0 100644
--- a/components/omnibox/browser/autocomplete_match.h
+++ b/components/omnibox/browser/autocomplete_match.h
@@ -170,8 +170,16 @@
 
   // Comparison function for determining whether the first match is better than
   // the second.
-  static bool MoreRelevant(const AutocompleteMatch& elem1,
-                           const AutocompleteMatch& elem2);
+  static bool MoreRelevant(const AutocompleteMatch& match1,
+                           const AutocompleteMatch& match2);
+
+  // Comparison functions for determining whether the first match is preferred
+  // over the second when choosing between candidate duplicates.
+  static bool BetterDuplicate(const AutocompleteMatch& match1,
+                              const AutocompleteMatch& match2);
+  static bool BetterDuplicateByIterator(
+      const std::vector<AutocompleteMatch>::const_iterator it1,
+      const std::vector<AutocompleteMatch>::const_iterator it2);
 
   // Helper functions for classes creating matches:
   // Fills in the classifications for |text|, using |style| as the base style
@@ -424,6 +432,11 @@
   // Returns true if the suggestion should show a tab match button or pedal.
   bool ShouldShowButton() const;
 
+  // Upgrades this match by absorbing the best properties from
+  // |duplicate_match|. For instance: if |duplicate_match| has a higher
+  // relevance score, this match's own relevance score will be upgraded.
+  void UpgradeMatchWithPropertiesFrom(const AutocompleteMatch& duplicate_match);
+
   // The provider of this match, used to remember which provider the user had
   // selected when the input changes. This may be NULL, in which case there is
   // no provider (or memory of the user's selection).
@@ -575,8 +588,11 @@
   // property and associated value and which is presented in chrome://omnibox.
   AdditionalInfo additional_info;
 
-  // A list of matches culled during de-duplication process, retained to
-  // ensure if a match is deleted, the duplicates are deleted as well.
+  // A vector of matches culled during de-duplication process, sorted from
+  // second-best to worst according to the de-duplication preference criteria.
+  // This vector is retained so that if the user deletes a match, all the
+  // duplicates are deleted as well. This is also used for re-duping Search
+  // Entity vs. plain Search suggestions.
   std::vector<AutocompleteMatch> duplicate_matches;
 
   // So users of AutocompleteMatch can use the same ellipsis that it uses.
diff --git a/components/omnibox/browser/autocomplete_result.cc b/components/omnibox/browser/autocomplete_result.cc
index 5be1c28..36dc87e 100644
--- a/components/omnibox/browser/autocomplete_result.cc
+++ b/components/omnibox/browser/autocomplete_result.cc
@@ -9,6 +9,7 @@
 #include <iterator>
 #include <string>
 #include <unordered_set>
+#include <vector>
 
 #include "base/command_line.h"
 #include "base/logging.h"
@@ -175,7 +176,7 @@
     MaybeCullTailSuggestions(&matches_);
   }
 #endif
-  SortAndDedupMatches(input.current_page_classification(), &matches_);
+  DeduplicateMatches(input.current_page_classification(), &matches_);
 
   DemoteOnDeviceSearchSuggestions();
 
@@ -565,11 +566,11 @@
              : GURL();
 }
 
-void AutocompleteResult::SortAndDedupMatches(
+void AutocompleteResult::DeduplicateMatches(
     metrics::OmniboxEventProto::PageClassification page_classification,
     ACMatches* matches) {
   // Group matches by stripped URL and whether it's a calculator suggestion.
-  std::unordered_map<std::pair<GURL, bool>, std::list<ACMatches::iterator>,
+  std::unordered_map<std::pair<GURL, bool>, std::vector<ACMatches::iterator>,
                      MatchGURLHash>
       url_to_matches;
   for (auto i = matches->begin(); i != matches->end(); ++i) {
@@ -581,35 +582,39 @@
   for (auto& group : url_to_matches) {
     const auto& key = group.first;
     const GURL& gurl = key.first;
-    // The list of matches whose URL are equivalent.
-    std::list<ACMatches::iterator>& duplicate_matches = group.second;
+    // The vector of matches whose URL are equivalent.
+    std::vector<ACMatches::iterator>& duplicate_matches = group.second;
     if (gurl.is_empty() || duplicate_matches.size() == 1)
       continue;
 
-    // Find the best match.
-    auto best_match = duplicate_matches.begin();
-    for (auto i = std::next(best_match); i != duplicate_matches.end(); ++i) {
-      best_match = BetterDuplicate(i, best_match);
-    }
+    // Sort the matches best to worst, according to the deduplication criteria.
+    std::sort(duplicate_matches.begin(), duplicate_matches.end(),
+              &AutocompleteMatch::BetterDuplicateByIterator);
+    AutocompleteMatch& best_match = **duplicate_matches.begin();
 
-    // Rotate the chosen match to be first, if necessary, so we know to keep it.
-    if (best_match != duplicate_matches.begin()) {
-      duplicate_matches.splice(duplicate_matches.begin(), duplicate_matches,
-                               best_match);
-    }
+    // Process all the duplicate matches (from second-best to worst).
+    std::vector<AutocompleteMatch> duplicates_of_duplicates;
+    for (auto i = std::next(duplicate_matches.begin());
+         i != duplicate_matches.end(); ++i) {
+      AutocompleteMatch& duplicate_match = **i;
 
-    // For each duplicate match, append its duplicates to that of the best
-    // match, then append it, before we erase it.
-    for (auto i = std::next(best_match); i != duplicate_matches.end(); ++i) {
-      auto& match = **i;
-      for (auto& dup_match : match.duplicate_matches)
-        (*best_match)->duplicate_matches.push_back(std::move(dup_match));
-      // Erase the duplicates before copying it. We don't need them any more.
-      match.duplicate_matches.erase(match.duplicate_matches.begin(),
-                                    match.duplicate_matches.end());
-      // Copy, don't move, because we need these below.
-      (*best_match)->duplicate_matches.push_back(match);
+      // Each duplicate match may also have its own duplicates. Move those to
+      // a temporary list, which will be eventually added to the end of
+      // |best_match.duplicate_matches|. Clear out the original list too.
+      std::move(duplicate_match.duplicate_matches.begin(),
+                duplicate_match.duplicate_matches.end(),
+                std::back_inserter(duplicates_of_duplicates));
+      duplicate_match.duplicate_matches.clear();
+
+      best_match.UpgradeMatchWithPropertiesFrom(duplicate_match);
+
+      // This should be a copy, not a move, since we don't erase duplicate
+      // matches from the master list until the very end.
+      DCHECK(duplicate_match.duplicate_matches.empty());  // Should be cleared.
+      best_match.duplicate_matches.push_back(duplicate_match);
     }
+    std::move(duplicates_of_duplicates.begin(), duplicates_of_duplicates.end(),
+              std::back_inserter(best_match.duplicate_matches));
   }
 
   // Erase duplicate matches.
@@ -651,91 +656,6 @@
 }
 
 // static
-std::list<ACMatches::iterator>::iterator AutocompleteResult::BetterDuplicate(
-    std::list<ACMatches::iterator>::iterator first,
-    std::list<ACMatches::iterator>::iterator second) {
-  std::list<ACMatches::iterator>::iterator preferred_match;
-  std::list<ACMatches::iterator>::iterator non_preferred_match;
-  // The following logic enforces constraints we care about regarding the
-  // the characteristics of the candidate matches. In order of priority:
-  //
-  // Entity suggestions:
-  //   Entity suggestions are always preferred over non-entity suggestions,
-  //   assuming both candidates have the same fill_into_edit value. In these
-  //   cases, because the fill_into_edit value is the same in both and the
-  //   selection of the entity suggestion appears to the user as simply a
-  //   "promotion" of an equivalent suggestion by adding additional decoration,
-  //   the entity suggestion is allowed to inherit the
-  //   allowed_to_be_default_match and inline_autocompletion values from the
-  //   other suggestion.
-  //
-  // allowed_to_be_default_match:
-  //   A suggestion that is allowed to be the default match is always preferred
-  //   over one that is not.
-  //
-  // Note that together these two constraints enforce an overall constraint,
-  // that if either candidate has allowed_to_be_default_match = true, the match
-  // which is preferred will always have allowed_to_be_default_match = true.
-  //
-  // Document suggestions:
-  //   The icon and display of document suggestions are preferred over
-  //   history, bookmark, etc. items. The actual URLs may be different, but
-  //   logically dedupe to the same entity to which we'll navigate.
-  if ((*first)->type == ACMatchType::SEARCH_SUGGEST_ENTITY &&
-      (*second)->type != ACMatchType::SEARCH_SUGGEST_ENTITY &&
-      (*first)->fill_into_edit == (*second)->fill_into_edit) {
-    preferred_match = first;
-    non_preferred_match = second;
-    if ((*non_preferred_match)->allowed_to_be_default_match) {
-      (*preferred_match)->allowed_to_be_default_match = true;
-      (*preferred_match)->inline_autocompletion =
-          (*non_preferred_match)->inline_autocompletion;
-    }
-  } else if ((*first)->type != ACMatchType::SEARCH_SUGGEST_ENTITY &&
-             (*second)->type == ACMatchType::SEARCH_SUGGEST_ENTITY &&
-             (*first)->fill_into_edit == (*second)->fill_into_edit) {
-    preferred_match = second;
-    non_preferred_match = first;
-    if ((*non_preferred_match)->allowed_to_be_default_match) {
-      (*preferred_match)->allowed_to_be_default_match = true;
-      (*preferred_match)->inline_autocompletion =
-          (*non_preferred_match)->inline_autocompletion;
-    }
-  } else if ((*first)->allowed_to_be_default_match &&
-             !(*second)->allowed_to_be_default_match) {
-    preferred_match = first;
-    non_preferred_match = second;
-  } else if ((*second)->allowed_to_be_default_match &&
-             !(*first)->allowed_to_be_default_match) {
-    preferred_match = second;
-    non_preferred_match = first;
-  } else if ((*first)->type == ACMatchType::DOCUMENT_SUGGESTION &&
-             (*second)->type != ACMatchType::DOCUMENT_SUGGESTION) {
-    preferred_match = first;
-    non_preferred_match = second;
-  } else if ((*first)->type != ACMatchType::DOCUMENT_SUGGESTION &&
-             (*second)->type == ACMatchType::DOCUMENT_SUGGESTION) {
-    preferred_match = second;
-    non_preferred_match = first;
-  } else {
-    // By default, simply prefer the match with the higher relevance. Note that
-    // we do not apply type-based demotion here (CompareWithDemoteByType)
-    // because we only apply demotion when ordering the final set of matches.
-    return (*first)->relevance >= (*second)->relevance ? first : second;
-  }
-
-  // If a match is preferred despite having a lower score, boost its score
-  // to that of the other match.
-  if ((*non_preferred_match)->relevance > (*preferred_match)->relevance) {
-    (*preferred_match)
-        ->RecordAdditionalInfo(kACMatchPropertyScoreBoostedFrom,
-                               (*preferred_match)->relevance);
-    (*preferred_match)->relevance = (*non_preferred_match)->relevance;
-  }
-  return preferred_match;
-}
-
-// static
 bool AutocompleteResult::HasMatchByDestination(const AutocompleteMatch& match,
                                                const ACMatches& matches) {
   for (auto i(matches.begin()); i != matches.end(); ++i) {
diff --git a/components/omnibox/browser/autocomplete_result.h b/components/omnibox/browser/autocomplete_result.h
index b2fe7e7..2595cb5 100644
--- a/components/omnibox/browser/autocomplete_result.h
+++ b/components/omnibox/browser/autocomplete_result.h
@@ -7,7 +7,6 @@
 
 #include <stddef.h>
 
-#include <list>
 #include <map>
 
 #include "base/macros.h"
@@ -155,23 +154,13 @@
   typedef ACMatches::iterator::difference_type matches_difference_type;
 #endif
 
-  // Sort |matches| by destination, taking into account demotions based on
-  // |page_classification| when resolving ties about which of several
-  // duplicates to keep.  The matches are also deduplicated. Duplicate matches
-  // are stored in the |duplicate_matches| vector of the corresponding
-  // AutocompleteMatch.
-  static void SortAndDedupMatches(
+  // Modifies |matches| such that any duplicate matches are coalesced into
+  // representative "best" matches. The erased matches are moved into the
+  // |duplicate_matches| members of their representative matches.
+  static void DeduplicateMatches(
       metrics::OmniboxEventProto::PageClassification page_classification,
       ACMatches* matches);
 
-  // Examines |first| and |second| and returns the match that is preferred when
-  // choosing between candidate duplicates. Note that this may modify the
-  // relevance, allowed_to_be_default_match, or inline_autocompletion values of
-  // the returned match.
-  static std::list<ACMatches::iterator>::iterator BetterDuplicate(
-      std::list<ACMatches::iterator>::iterator first,
-      std::list<ACMatches::iterator>::iterator second);
-
   // Returns true if |matches| contains a match with the same destination as
   // |match|.
   static bool HasMatchByDestination(const AutocompleteMatch& match,
diff --git a/components/omnibox/browser/autocomplete_result_unittest.cc b/components/omnibox/browser/autocomplete_result_unittest.cc
index 3106e18f..56b7886a 100644
--- a/components/omnibox/browser/autocomplete_result_unittest.cc
+++ b/components/omnibox/browser/autocomplete_result_unittest.cc
@@ -635,15 +635,15 @@
   // Expect 3 unique results after SortAndCull().
   ASSERT_EQ(3U, result.size());
 
-  // Check that 3rd and 4th result got added to the first result as dups
+  // Check that 3rd and 4th result got added to the first result as duplicates
   // and also duplicates of the 4th match got copied.
   ASSERT_EQ(4U, result.match_at(0)->duplicate_matches.size());
   const AutocompleteMatch* first_match = result.match_at(0);
   EXPECT_EQ(matches[2].destination_url,
             first_match->duplicate_matches.at(1).destination_url);
-  EXPECT_EQ(dup_match.destination_url,
-            first_match->duplicate_matches.at(2).destination_url);
   EXPECT_EQ(matches[3].destination_url,
+            first_match->duplicate_matches.at(2).destination_url);
+  EXPECT_EQ(dup_match.destination_url,
             first_match->duplicate_matches.at(3).destination_url);
 
   // Check that 6th result started a new list of dups for the second result.
@@ -1765,8 +1765,8 @@
 
   FakeAutocompleteProviderClient client;
   result.AppendDedicatedPedalMatches(&client, input);
-  result.SortAndDedupMatches(metrics::OmniboxEventProto::OTHER,
-                             &result.matches_);
+  result.DeduplicateMatches(metrics::OmniboxEventProto::OTHER,
+                            &result.matches_);
 
   // Exactly 2 (not 3) unique Pedals should be added with relevance close to max
   // of the triggering suggestions.
@@ -1781,8 +1781,8 @@
   // no duplicates are added, but the existing Pedal suggestion is updated.
   result.match_at(3)->contents = base::UTF8ToUTF16("open incognito tab");
   result.AppendDedicatedPedalMatches(&client, input);
-  result.SortAndDedupMatches(metrics::OmniboxEventProto::OTHER,
-                             &result.matches_);
+  result.DeduplicateMatches(metrics::OmniboxEventProto::OTHER,
+                            &result.matches_);
   EXPECT_EQ(result.size(), 6u);
   EXPECT_NE(result.match_at(4)->pedal, nullptr);
   EXPECT_NE(result.match_at(5)->pedal, nullptr);
diff --git a/components/omnibox/browser/history_url_provider_unittest.cc b/components/omnibox/browser/history_url_provider_unittest.cc
index d8b9d2810..70a17f0 100644
--- a/components/omnibox/browser/history_url_provider_unittest.cc
+++ b/components/omnibox/browser/history_url_provider_unittest.cc
@@ -327,8 +327,8 @@
     for (auto i = matches_.begin(); i != matches_.end(); ++i) {
       i->ComputeStrippedDestinationURL(input, service);
     }
-    AutocompleteResult::SortAndDedupMatches(input.current_page_classification(),
-                                            &matches_);
+    AutocompleteResult::DeduplicateMatches(input.current_page_classification(),
+                                           &matches_);
     std::sort(matches_.begin(), matches_.end(),
               &AutocompleteMatch::MoreRelevant);
   }
diff --git a/components/omnibox/browser/match_compare.h b/components/omnibox/browser/match_compare.h
index 7cb6b5f8..c7f54fd9 100644
--- a/components/omnibox/browser/match_compare.h
+++ b/components/omnibox/browser/match_compare.h
@@ -6,22 +6,23 @@
 #define COMPONENTS_OMNIBOX_BROWSER_MATCH_COMPARE_H_
 
 #include "components/omnibox/browser/omnibox_field_trial.h"
+#include "third_party/metrics_proto/omnibox_event.pb.h"
+
+using PageClassification = metrics::OmniboxEventProto::PageClassification;
 
 // This class implements a special version of AutocompleteMatch::MoreRelevant
 // that allows matches of particular types to be demoted in AutocompleteResult.
 template <class Match>
 class CompareWithDemoteByType {
  public:
-  CompareWithDemoteByType(
-      metrics::OmniboxEventProto::PageClassification page_classification) {
+  CompareWithDemoteByType(PageClassification page_classification) {
     OmniboxFieldTrial::GetDemotionsByType(page_classification, &demotions_);
   }
 
   // Returns the relevance score of |match| demoted appropriately by
   // |demotions_by_type_|.
   int GetDemotedRelevance(const Match& match) const {
-    OmniboxFieldTrial::DemotionMultipliers::const_iterator demotion_it =
-        demotions_.find(match.type);
+    auto demotion_it = demotions_.find(match.type);
     return (demotion_it == demotions_.end())
                ? match.relevance
                : (match.relevance * demotion_it->second);
@@ -54,8 +55,7 @@
 template <class Match>
 class DestinationSort {
  public:
-  DestinationSort(
-      metrics::OmniboxEventProto::PageClassification page_classification)
+  DestinationSort(PageClassification page_classification)
       : demote_by_type_(page_classification) {}
   bool operator()(const Match& elem1, const Match& elem2) {
     // Sort identical destination_urls together.
diff --git a/components/omnibox/common/omnibox_features.cc b/components/omnibox/common/omnibox_features.cc
index 9b0a2a4..b0ce734 100644
--- a/components/omnibox/common/omnibox_features.cc
+++ b/components/omnibox/common/omnibox_features.cc
@@ -246,7 +246,7 @@
 // are exceptions in this regard and this experiment makes this more consistent.
 const base::Feature kUIExperimentShowPlaceholderWhenCaretShowing{
     "OmniboxUIExperimentShowPlaceholderWhenCaretShowing",
-    base::FEATURE_ENABLED_BY_DEFAULT};
+    base::FEATURE_DISABLED_BY_DEFAULT};
 
 // Feature used to enable speculatively starting a service worker associated
 // with the destination of the default match when the user's input looks like a
diff --git a/components/onc/docs/onc_spec.md b/components/onc/docs/onc_spec.md
index 08c92219..fde3afbe 100644
--- a/components/onc/docs/onc_spec.md
+++ b/components/onc/docs/onc_spec.md
@@ -1647,6 +1647,11 @@
     * If *true*, remove this certificate (only GUID
       should be set).
 
+* **Scope**
+    * (optional, default Scope if missing) - [Scope](#Scope-type)
+    * If this is given, it specifies the scope in which the certificate should
+      be applied.
+
 * **TrustBits**
     * (optional if **Type**
         is *Server*
@@ -1688,6 +1693,21 @@
     results are undefined, so this configuration should be prohibited by the
     configuration editor.
 
+### Scope type
+* **Id**
+    * (required if **Type** is *Extension*, otherwise ignored) - **string**
+    * If *Type* is *Extension*, this is the ID of the chrome extension for which
+      the certificate should be applied.
+* **Type**
+    * (required) - **string**
+    * Allowed values are:
+        * *Extension*
+        * *Default*
+    * *Extension* indicates that the certificate should only be applied in the
+      scope of a chrome extension.
+      *Default* indicates that the scope the certificate applies in should not
+      be restricted.
+
 
 ## Encrypted Configuration
 
diff --git a/components/onc/onc_constants.cc b/components/onc/onc_constants.cc
index 9fda651..38e0e00d 100644
--- a/components/onc/onc_constants.cc
+++ b/components/onc/onc_constants.cc
@@ -271,6 +271,7 @@
 const char kClient[] = "Client";
 const char kGUID[] = "GUID";
 const char kPKCS12[] = "PKCS12";
+const char kScope[] = "Scope";
 const char kServer[] = "Server";
 const char kTrustBits[] = "TrustBits";
 const char kType[] = "Type";
@@ -278,6 +279,13 @@
 const char kX509[] = "X509";
 }  // namespace certificate
 
+namespace scope {
+const char kDefault[] = "Default";
+const char kExtension[] = "Extension";
+const char kId[] = "Id";
+const char kType[] = "Type";
+}  // namespace scope
+
 namespace encrypted {
 const char kAES256[] = "AES256";
 const char kCipher[] = "Cipher";
diff --git a/components/onc/onc_constants.h b/components/onc/onc_constants.h
index bea11275..868df30 100644
--- a/components/onc/onc_constants.h
+++ b/components/onc/onc_constants.h
@@ -283,6 +283,7 @@
 ONC_EXPORT extern const char kClient[];
 ONC_EXPORT extern const char kGUID[];
 ONC_EXPORT extern const char kPKCS12[];
+ONC_EXPORT extern const char kScope[];
 ONC_EXPORT extern const char kServer[];
 ONC_EXPORT extern const char kTrustBits[];
 ONC_EXPORT extern const char kType[];
@@ -290,6 +291,13 @@
 ONC_EXPORT extern const char kX509[];
 }  // namespace certificate
 
+namespace scope {
+ONC_EXPORT extern const char kDefault[];
+ONC_EXPORT extern const char kExtension[];
+ONC_EXPORT extern const char kId[];
+ONC_EXPORT extern const char kType[];
+}  // namespace scope
+
 namespace encrypted {
 ONC_EXPORT extern const char kAES256[];
 ONC_EXPORT extern const char kCipher[];
diff --git a/components/optimization_guide/hints_fetcher.h b/components/optimization_guide/hints_fetcher.h
index f8bca07..e7a05f5f 100644
--- a/components/optimization_guide/hints_fetcher.h
+++ b/components/optimization_guide/hints_fetcher.h
@@ -24,6 +24,12 @@
 
 namespace optimization_guide {
 
+// Callback to inform the caller that the remote hints have been fetched and
+// to pass back the fetched hints response from the remote Optimization Guide
+// Service.
+using HintsFetchedCallback = base::OnceCallback<void(
+    base::Optional<std::unique_ptr<proto::GetHintsResponse>>)>;
+
 // A class to handle requests for optimization hints from a remote Optimization
 // Guide Service.
 //
@@ -31,12 +37,6 @@
 // Owner must ensure that |hint_cache| remains alive for the lifetime of
 // |HintsFetcher|.
 class HintsFetcher {
-  // Callback to inform the caller that the remote hints have been fetched and
-  // to pass back the fetched hints response from the remote Optimization Guide
-  // Service.
-  using HintsFetchedCallback = base::OnceCallback<void(
-      base::Optional<std::unique_ptr<proto::GetHintsResponse>>)>;
-
  public:
   HintsFetcher(
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
diff --git a/components/password_manager/core/browser/leak_detection/encryption_utils.h b/components/password_manager/core/browser/leak_detection/encryption_utils.h
index 9360163..88b1d53 100644
--- a/components/password_manager/core/browser/leak_detection/encryption_utils.h
+++ b/components/password_manager/core/browser/leak_detection/encryption_utils.h
@@ -24,7 +24,7 @@
 std::string HashUsername(base::StringPiece canonicalized_username);
 
 // Bucketizes |canonicalized_username| by hashing it and returning a prefix of
-// 24 bits.
+// |kUsernameHashPrefixLength| bits.
 std::string BucketizeUsername(base::StringPiece canonicalized_username);
 
 // Produces the username/password pair hash using scrypt algorithm.
diff --git a/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.cc b/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.cc
index 4afb6d3..a58fbe71 100644
--- a/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.cc
+++ b/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.cc
@@ -8,15 +8,30 @@
 
 #include "base/containers/span.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/task/post_task.h"
 #include "components/password_manager/core/browser/leak_detection/encryption_utils.h"
 #include "components/password_manager/core/browser/leak_detection/leak_detection_api.pb.h"
 #include "components/password_manager/core/browser/leak_detection/single_lookup_response.h"
 
 namespace password_manager {
+namespace {
 
 using google::internal::identity::passwords::leak::check::v1::
     LookupSingleLeakRequest;
 
+// Despite the function is short, it executes long. That's why it should be done
+// asynchronously.
+LookupSingleLeakData PrepareLookupSingleLeakData(const std::string& username,
+                                                 const std::string& password) {
+  LookupSingleLeakData data;
+  data.username_hash_prefix = BucketizeUsername(CanonicalizeUsername(username));
+  data.encrypted_payload = CipherEncrypt(
+      ScryptHashUsernameAndPassword(username, password), &data.encryption_key);
+  return data;
+}
+
+}  // namespace
+
 LookupSingleLeakRequest MakeLookupSingleLeakRequest(
     base::StringPiece username,
     base::StringPiece password) {
@@ -38,6 +53,17 @@
   return request;
 }
 
+void PrepareSingleLeakRequestData(const std::string& username,
+                                  const std::string& password,
+                                  SingleLeakRequestDataCallback callback) {
+  base::PostTaskAndReplyWithResult(
+      FROM_HERE,
+      {base::ThreadPool(), base::TaskPriority::USER_VISIBLE,
+       base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+      base::BindOnce(&PrepareLookupSingleLeakData, username, password),
+      std::move(callback));
+}
+
 bool ParseLookupSingleLeakResponse(const SingleLookupResponse& response) {
   // TODO(crbug.com/086298): Implement decrypting the response and checking
   // whether the credential was actually leaked.
diff --git a/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.h b/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.h
index 5cf9960..c44cb3e 100644
--- a/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.h
+++ b/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LEAK_DETECTION_LEAK_DETECTION_REQUEST_UTILS_H_
 #define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LEAK_DETECTION_LEAK_DETECTION_REQUEST_UTILS_H_
 
+#include "base/callback.h"
 #include "base/strings/string_piece_forward.h"
 
 namespace google {
@@ -27,12 +28,38 @@
 
 struct SingleLookupResponse;
 
+// Stores all the data needed for one credential lookup.
+struct LookupSingleLeakData {
+  LookupSingleLeakData() = default;
+  LookupSingleLeakData(LookupSingleLeakData&& other) = default;
+  LookupSingleLeakData& operator=(LookupSingleLeakData&& other) = default;
+  ~LookupSingleLeakData() = default;
+
+  LookupSingleLeakData(const LookupSingleLeakData&) = delete;
+  LookupSingleLeakData& operator=(const LookupSingleLeakData&) = delete;
+
+  std::string username_hash_prefix;
+  std::string encrypted_payload;
+
+  std::string encryption_key;
+};
+
+using SingleLeakRequestDataCallback =
+    base::OnceCallback<void(LookupSingleLeakData)>;
+
 // Constructs a LookupSingleLeakRequest from the provided |username| and
 // |password|.
 google::internal::identity::passwords::leak::check::v1::LookupSingleLeakRequest
 MakeLookupSingleLeakRequest(base::StringPiece username,
                             base::StringPiece password);
 
+// Asynchronously creates a data payload for single credential check.
+// Callback is invoked on the calling thread with the protobuf and the
+// encryption key used.
+void PrepareSingleLeakRequestData(const std::string& username,
+                                  const std::string& password,
+                                  SingleLeakRequestDataCallback callback);
+
 // Processes the provided |response| and returns whether the relevant credential
 // was leaked.
 bool ParseLookupSingleLeakResponse(const SingleLookupResponse& response);
diff --git a/components/password_manager/core/browser/leak_detection/leak_detection_request_utils_unittest.cc b/components/password_manager/core/browser/leak_detection/leak_detection_request_utils_unittest.cc
index 209903b..979f05be 100644
--- a/components/password_manager/core/browser/leak_detection/leak_detection_request_utils_unittest.cc
+++ b/components/password_manager/core/browser/leak_detection/leak_detection_request_utils_unittest.cc
@@ -5,12 +5,17 @@
 #include "components/password_manager/core/browser/leak_detection/leak_detection_request_utils.h"
 
 #include "base/strings/string_piece.h"
+#include "base/test/mock_callback.h"
+#include "base/test/scoped_task_environment.h"
 #include "components/password_manager/core/browser/leak_detection/leak_detection_api.pb.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace password_manager {
 
+using ::testing::ElementsAre;
+using ::testing::Field;
+
 TEST(LeakDetectionRequestUtils, MakeLookupSingleLeakRequest) {
   // Derived from test case used by the server-side implementation:
   // go/passwords-leak-test
@@ -19,4 +24,19 @@
               ::testing::ElementsAreArray({0x3D, 0x70, 0xD3}));
 }
 
+TEST(LeakDetectionRequestUtils, PrepareSingleLeakRequestData) {
+  base::test::ScopedTaskEnvironment task_env;
+  base::MockCallback<SingleLeakRequestDataCallback> callback;
+
+  PrepareSingleLeakRequestData("jonsnow", "1234", callback.Get());
+  EXPECT_CALL(
+      callback,
+      Run(AllOf(
+          Field(&LookupSingleLeakData::username_hash_prefix,
+                ElementsAre(61, 112, -45)),
+          Field(&LookupSingleLeakData::encrypted_payload, testing::Ne("")),
+          Field(&LookupSingleLeakData::encryption_key, testing::Ne("")))));
+  task_env.RunUntilIdle();
+}
+
 }  // namespace password_manager
diff --git a/components/previews/content/previews_optimization_guide_unittest.cc b/components/previews/content/previews_optimization_guide_unittest.cc
index 6f7a58c..3c2b106 100644
--- a/components/previews/content/previews_optimization_guide_unittest.cc
+++ b/components/previews/content/previews_optimization_guide_unittest.cc
@@ -5,6 +5,7 @@
 #include "components/previews/content/previews_optimization_guide.h"
 
 #include <memory>
+#include <utility>
 
 #include "base/base64.h"
 #include "base/bind.h"
@@ -120,11 +121,6 @@
 // A mock class implementation of HintsFetcher for unittesting
 // previews_optimization_guide.
 class TestHintsFetcher : public optimization_guide::HintsFetcher {
-  using HintsFetchedCallback = base::OnceCallback<void(
-      base::Optional<
-          std::unique_ptr<optimization_guide::proto::GetHintsResponse>>)>;
-  using HintsFetcher::FetchOptimizationGuideServiceHints;
-
  public:
   TestHintsFetcher(
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
@@ -135,7 +131,8 @@
 
   bool FetchOptimizationGuideServiceHints(
       const std::vector<std::string>& hosts,
-      HintsFetchedCallback hints_fetched_callback) override {
+      optimization_guide::HintsFetchedCallback hints_fetched_callback)
+      override {
     switch (fetch_state_) {
       case HintsFetcherEndState::kFetchFailed:
         std::move(hints_fetched_callback).Run(base::nullopt);
diff --git a/components/resources/OWNERS b/components/resources/OWNERS
index 7038831..697f205 100644
--- a/components/resources/OWNERS
+++ b/components/resources/OWNERS
@@ -23,6 +23,5 @@
 per-file proximity_auth*=tengs@chromium.org
 per-file printing_resources.grdp=file://printing/OWNERS
 per-file security_interstitials_resources.grdp=file://components/security_interstitials/OWNERS
-per-file supervised_user_error_page_resources.grdp=file://components/supervised_user_error_page/OWNERS
 per-file sync_driver_resources.grdp=file://components/sync/OWNERS
 per-file version_ui*=file://ui/webui/PLATFORM_OWNERS
diff --git a/components/search_engines/prepopulated_engines.json b/components/search_engines/prepopulated_engines.json
index d834782..18bdc1f3 100644
--- a/components/search_engines/prepopulated_engines.json
+++ b/components/search_engines/prepopulated_engines.json
@@ -34,20 +34,16 @@
   // The following engines are included in country lists and are added to the
   // list of search engines on the first run depending on user's country.
   "elements": {
-    // Ask and Ask UK have suggestion URLs reachable over HTTPS, but they
-    // throw a certificate error, so those will remain as HTTP for now.
     "ask": {
       "name": "Ask",
       "keyword": "ask.com",
       "favicon_url": "https://sp.ask.com/sh/i/a16/favicon/favicon.ico",
       "search_url": "https://www.ask.com/web?q={searchTerms}",
-      "suggest_url": "http://ss.ask.com/query?q={searchTerms}&li=ff",
+      "suggest_url": "https://lss.sse-iacapps.com/query?q={searchTerms}&li=ff",
       "type": "SEARCH_ENGINE_ASK",
       "id": 4
     },
 
-    // Baidu's suggestion URL is not reachable over HTTPS, so it remains as
-    // HTTP for now.
     "baidu": {
       "name": "\u767e\u5ea6",
       "keyword": "baidu.com",
@@ -58,7 +54,7 @@
         "https://www.baidu.com/s?ie={inputEncoding}&word={searchTerms}",
         "https://www.baidu.com/{google:pathWildcard}/s?ie={inputEncoding}&word={searchTerms}"
       ],
-      "suggest_url": "http://suggestion.baidu.com/su?wd={searchTerms}&action=opensearch&ie={inputEncoding}",
+      "suggest_url": "https://suggestion.baidu.com/su?wd={searchTerms}&action=opensearch&ie={inputEncoding}",
       "type": "SEARCH_ENGINE_BAIDU",
       "id": 21
     },
diff --git a/components/sync/engine/net/http_bridge.cc b/components/sync/engine/net/http_bridge.cc
index 22e4655..e0dab5a 100644
--- a/components/sync/engine/net/http_bridge.cc
+++ b/components/sync/engine/net/http_bridge.cc
@@ -267,8 +267,8 @@
   resource_request->url = url_for_request_;
   resource_request->method = "POST";
   resource_request->load_flags =
-      net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE |
-      net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES;
+      net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE;
+  resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
 
   if (!extra_headers_.empty())
     resource_request->headers.AddHeadersFromString(extra_headers_);
diff --git a/components/translate/core/browser/translate_script_unittest.cc b/components/translate/core/browser/translate_script_unittest.cc
index f5cedd00..1ef1e10 100644
--- a/components/translate/core/browser/translate_script_unittest.cc
+++ b/components/translate/core/browser/translate_script_unittest.cc
@@ -94,11 +94,8 @@
   EXPECT_EQ(expected_url.GetOrigin().spec(), url.GetOrigin().spec());
   EXPECT_EQ(expected_url.path(), url.path());
 
-  int load_flags = last_resource_request.load_flags;
-  EXPECT_EQ(net::LOAD_DO_NOT_SEND_COOKIES,
-            load_flags & net::LOAD_DO_NOT_SEND_COOKIES);
-  EXPECT_EQ(net::LOAD_DO_NOT_SAVE_COOKIES,
-            load_flags & net::LOAD_DO_NOT_SAVE_COOKIES);
+  EXPECT_EQ(network::mojom::CredentialsMode::kOmit,
+            last_resource_request.credentials_mode);
 
   std::string expected_extra_headers =
       base::StringPrintf("%s\r\n\r\n", TranslateScript::kRequestHeader);
diff --git a/components/translate/core/browser/translate_url_fetcher.cc b/components/translate/core/browser/translate_url_fetcher.cc
index f98f41a..c3cbb8f 100644
--- a/components/translate/core/browser/translate_url_fetcher.cc
+++ b/components/translate/core/browser/translate_url_fetcher.cc
@@ -95,8 +95,7 @@
   // Create and initialize URL loader.
   auto resource_request = std::make_unique<network::ResourceRequest>();
   resource_request->url = url_;
-  resource_request->load_flags =
-      net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES;
+  resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
   if (!extra_request_header_.empty())
     resource_request->headers.AddHeaderFromString(extra_request_header_);
 
diff --git a/components/translate/ios/browser/translate_controller.mm b/components/translate/ios/browser/translate_controller.mm
index 677e096..b433524 100644
--- a/components/translate/ios/browser/translate_controller.mm
+++ b/components/translate/ios/browser/translate_controller.mm
@@ -226,8 +226,7 @@
   auto request = std::make_unique<network::ResourceRequest>();
   request->method = method;
   request->url = GURL(url);
-  request->load_flags =
-      net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES;
+  request->credentials_mode = network::mojom::CredentialsMode::kOmit;
   auto fetcher = network::SimpleURLLoader::Create(std::move(request),
                                                   NO_TRAFFIC_ANNOTATION_YET);
   fetcher->AttachStringForUpload(body, "application/x-www-form-urlencoded");
diff --git a/components/update_client/net/network_impl.cc b/components/update_client/net/network_impl.cc
index c78853e..1e241a6 100644
--- a/components/update_client/net/network_impl.cc
+++ b/components/update_client/net/network_impl.cc
@@ -106,9 +106,8 @@
   auto resource_request = std::make_unique<network::ResourceRequest>();
   resource_request->url = url;
   resource_request->method = "POST";
-  resource_request->load_flags = net::LOAD_DO_NOT_SEND_COOKIES |
-                                 net::LOAD_DO_NOT_SAVE_COOKIES |
-                                 net::LOAD_DISABLE_CACHE;
+  resource_request->load_flags = net::LOAD_DISABLE_CACHE;
+  resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
   for (const auto& header : post_additional_headers)
     resource_request->headers.SetHeader(header.first, header.second);
   simple_url_loader_ = network::SimpleURLLoader::Create(
@@ -149,9 +148,8 @@
   auto resource_request = std::make_unique<network::ResourceRequest>();
   resource_request->url = url;
   resource_request->method = "GET";
-  resource_request->load_flags = net::LOAD_DO_NOT_SEND_COOKIES |
-                                 net::LOAD_DO_NOT_SAVE_COOKIES |
-                                 net::LOAD_DISABLE_CACHE;
+  resource_request->load_flags = net::LOAD_DISABLE_CACHE;
+  resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
   simple_url_loader_ = network::SimpleURLLoader::Create(
       std::move(resource_request), traffic_annotation);
   simple_url_loader_->SetRetryOptions(
diff --git a/components/web_resource/web_resource_service.cc b/components/web_resource/web_resource_service.cc
index e5eec285..d1c0d4e 100644
--- a/components/web_resource/web_resource_service.cc
+++ b/components/web_resource/web_resource_service.cc
@@ -154,9 +154,8 @@
   resource_request->url = web_resource_server;
   // Do not let url fetcher affect existing state in system context
   // (by setting cookies, for example).
-  resource_request->load_flags = net::LOAD_DISABLE_CACHE |
-                                 net::LOAD_DO_NOT_SEND_COOKIES |
-                                 net::LOAD_DO_NOT_SAVE_COOKIES;
+  resource_request->load_flags = net::LOAD_DISABLE_CACHE;
+  resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
   simple_url_loader_ = network::SimpleURLLoader::Create(
       std::move(resource_request), traffic_annotation_);
   simple_url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc
index 947d466..c18971eb 100644
--- a/content/app/content_main_runner_impl.cc
+++ b/content/app/content_main_runner_impl.cc
@@ -909,10 +909,10 @@
       StartBrowserThreadPool();
     }
 
-    tracing::InitTracingPostThreadPoolStart();
-
     BrowserTaskExecutor::PostFeatureListSetup();
 
+    tracing::InitTracingPostThreadPoolStartAndFeatureList();
+
     delegate_->PostTaskSchedulerStart();
 
     if (should_start_service_manager_only)
diff --git a/content/browser/background_fetch/background_fetch_service_impl.cc b/content/browser/background_fetch/background_fetch_service_impl.cc
index 9a8c1ef..1635f42 100644
--- a/content/browser/background_fetch/background_fetch_service_impl.cc
+++ b/content/browser/background_fetch/background_fetch_service_impl.cc
@@ -35,10 +35,14 @@
 
 // static
 void BackgroundFetchServiceImpl::CreateForWorker(
-    blink::mojom::BackgroundFetchServiceRequest request,
-    RenderProcessHost* render_process_host,
-    const url::Origin& origin) {
+    const ServiceWorkerRunningInfo& info,
+    mojo::PendingReceiver<blink::mojom::BackgroundFetchService> receiver) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  RenderProcessHost* render_process_host =
+      RenderProcessHost::FromID(info.process_id);
+
+  if (!render_process_host)
+    return;
 
   base::PostTask(
       FROM_HERE, {BrowserThread::IO},
@@ -47,21 +51,19 @@
           WrapRefCounted(static_cast<StoragePartitionImpl*>(
                              render_process_host->GetStoragePartition())
                              ->GetBackgroundFetchContext()),
-          origin, /* render_frame_tree_node_id= */ 0,
-          /* wc_getter= */ base::NullCallback(), std::move(request)));
+          url::Origin::Create(info.script_url),
+          /* render_frame_tree_node_id= */ 0,
+          /* wc_getter= */ base::NullCallback(), std::move(receiver)));
 }
 
 // static
 void BackgroundFetchServiceImpl::CreateForFrame(
-    RenderProcessHost* render_process_host,
-    int render_frame_id,
-    blink::mojom::BackgroundFetchServiceRequest request) {
+    RenderFrameHost* render_frame_host,
+    mojo::PendingReceiver<blink::mojom::BackgroundFetchService> receiver) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  DCHECK(render_process_host);
-  auto* render_frame_host =
-      RenderFrameHost::FromID(render_process_host->GetID(), render_frame_id);
   DCHECK(render_frame_host);
+  RenderProcessHost* render_process_host = render_frame_host->GetProcess();
+  DCHECK(render_process_host);
 
   WebContents::Getter wc_getter = base::NullCallback();
 
@@ -81,7 +83,7 @@
                              ->GetBackgroundFetchContext()),
           render_frame_host->GetLastCommittedOrigin(),
           render_frame_host->GetFrameTreeNodeId(), std::move(wc_getter),
-          std::move(request)));
+          std::move(receiver)));
 }
 
 // static
diff --git a/content/browser/background_fetch/background_fetch_service_impl.h b/content/browser/background_fetch/background_fetch_service_impl.h
index 42aa62f..9269874d 100644
--- a/content/browser/background_fetch/background_fetch_service_impl.h
+++ b/content/browser/background_fetch/background_fetch_service_impl.h
@@ -20,7 +20,6 @@
 namespace content {
 
 class BackgroundFetchContext;
-class RenderProcessHost;
 
 class CONTENT_EXPORT BackgroundFetchServiceImpl
     : public blink::mojom::BackgroundFetchService {
@@ -33,14 +32,12 @@
   ~BackgroundFetchServiceImpl() override;
 
   static void CreateForWorker(
-      blink::mojom::BackgroundFetchServiceRequest request,
-      RenderProcessHost* render_process_host,
-      const url::Origin& origin);
+      const ServiceWorkerRunningInfo& info,
+      mojo::PendingReceiver<blink::mojom::BackgroundFetchService> receiver);
 
   static void CreateForFrame(
-      RenderProcessHost* render_process_host,
-      int render_frame_id,
-      blink::mojom::BackgroundFetchServiceRequest request);
+      RenderFrameHost* render_frame_host,
+      mojo::PendingReceiver<blink::mojom::BackgroundFetchService> receiver);
 
   // blink::mojom::BackgroundFetchService implementation.
   void Fetch(int64_t service_worker_registration_id,
diff --git a/content/browser/browser_interface_binders.cc b/content/browser/browser_interface_binders.cc
index 167aabf..dfcd97c 100644
--- a/content/browser/browser_interface_binders.cc
+++ b/content/browser/browser_interface_binders.cc
@@ -3,8 +3,10 @@
 // found in the LICENSE file.
 
 #include "content/browser/browser_interface_binders.h"
+#include "content/browser/background_fetch/background_fetch_service_impl.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
+#include "content/browser/service_worker/service_worker_provider_host.h"
 #include "content/browser/worker_host/dedicated_worker_host.h"
 #include "content/browser/worker_host/shared_worker_host.h"
 #include "content/browser/worker_host/shared_worker_instance.h"
@@ -13,67 +15,100 @@
 namespace content {
 namespace internal {
 
-void PopulateFrameBinders(RenderFrameHostImpl* rfhi,
+// Documents/frames
+void PopulateFrameBinders(RenderFrameHostImpl* host,
                           service_manager::BinderMap* map) {
   map->Add<blink::mojom::AudioContextManager>(base::BindRepeating(
-      &RenderFrameHostImpl::GetAudioContextManager, base::Unretained(rfhi)));
+      &RenderFrameHostImpl::GetAudioContextManager, base::Unretained(host)));
 
   map->Add<blink::mojom::FileSystemManager>(base::BindRepeating(
-      &RenderFrameHostImpl::GetFileSystemManager, base::Unretained(rfhi)));
+      &RenderFrameHostImpl::GetFileSystemManager, base::Unretained(host)));
 }
 
 void PopulateBinderMapWithContext(
-    RenderFrameHostImpl* rfhi,
-    service_manager::BinderMapWithContext<RenderFrameHost*>* map) {}
+    RenderFrameHostImpl* host,
+    service_manager::BinderMapWithContext<RenderFrameHost*>* map) {
+  map->Add<blink::mojom::BackgroundFetchService>(
+      base::BindRepeating(&BackgroundFetchServiceImpl::CreateForFrame));
+}
 
-void PopulateBinderMap(RenderFrameHostImpl* rfhi,
+void PopulateBinderMap(RenderFrameHostImpl* host,
                        service_manager::BinderMap* map) {
-  PopulateFrameBinders(rfhi, map);
+  PopulateFrameBinders(host, map);
 }
 
-RenderFrameHost* GetContextForHost(RenderFrameHostImpl* rfhi) {
-  return rfhi;
+RenderFrameHost* GetContextForHost(RenderFrameHostImpl* host) {
+  return host;
 }
 
-void PopulateDedicatedWorkerBinders(DedicatedWorkerHost* dwh,
+// Dedicated workers
+const url::Origin& GetContextForHost(DedicatedWorkerHost* host) {
+  return host->GetOrigin();
+}
+
+void PopulateDedicatedWorkerBinders(DedicatedWorkerHost* host,
                                     service_manager::BinderMap* map) {}
 
-const url::Origin& GetContextForHost(DedicatedWorkerHost* dwh) {
-  return dwh->GetOrigin();
-}
-
 void PopulateBinderMapWithContext(
-    DedicatedWorkerHost* dwh,
+    DedicatedWorkerHost* host,
     service_manager::BinderMapWithContext<const url::Origin&>* map) {
   // TODO(https://crbug.com/873661): Pass origin to FileSystemManager.
   map->Add<blink::mojom::FileSystemManager>(
       base::BindRepeating(&RenderProcessHost::BindFileSystemManager,
-                          base::Unretained(dwh->GetProcessHost())));
+                          base::Unretained(host->GetProcessHost())));
 }
 
-void PopulateBinderMap(DedicatedWorkerHost* dwh,
+void PopulateBinderMap(DedicatedWorkerHost* host,
                        service_manager::BinderMap* map) {
-  PopulateDedicatedWorkerBinders(dwh, map);
+  PopulateDedicatedWorkerBinders(host, map);
 }
 
-url::Origin GetContextForHost(SharedWorkerHost* swh) {
-  return url::Origin::Create(swh->instance()->url());
+// Shared workers
+url::Origin GetContextForHost(SharedWorkerHost* host) {
+  return url::Origin::Create(host->instance()->url());
 }
 
-void PopulateSharedWorkerBinders(SharedWorkerHost* swh,
+void PopulateSharedWorkerBinders(SharedWorkerHost* host,
                                  service_manager::BinderMap* map) {}
 
 void PopulateBinderMapWithContext(
-    SharedWorkerHost* swh,
+    SharedWorkerHost* host,
     service_manager::BinderMapWithContext<const url::Origin&>* map) {
   // TODO(https://crbug.com/873661): Pass origin to FileSystemManager.
   map->Add<blink::mojom::FileSystemManager>(
       base::BindRepeating(&RenderProcessHost::BindFileSystemManager,
-                          base::Unretained(swh->GetProcessHost())));
+                          base::Unretained(host->GetProcessHost())));
 }
 
-void PopulateBinderMap(SharedWorkerHost* swh, service_manager::BinderMap* map) {
-  PopulateSharedWorkerBinders(swh, map);
+void PopulateBinderMap(SharedWorkerHost* host,
+                       service_manager::BinderMap* map) {
+  PopulateSharedWorkerBinders(host, map);
+}
+
+// Service workers
+ServiceWorkerRunningInfo GetContextForHost(ServiceWorkerProviderHost* host) {
+  // TODO(crbug.com/993409): pass Origin instead of GURL
+  return {host->running_hosted_version()->script_origin().GetURL(),
+          host->running_hosted_version()->version_id(), host->process_id()};
+}
+
+void PopulateServiceWorkerBinders(ServiceWorkerProviderHost* host,
+                                  service_manager::BinderMap* map) {}
+
+void PopulateBinderMapWithContext(
+    ServiceWorkerProviderHost* host,
+    service_manager::BinderMapWithContext<const ServiceWorkerRunningInfo&>*
+        map) {
+  // Using a task runner since ServiceWorkerProviderHost lives on the IO thread,
+  // and CreateForWorker() needs to be called on the UI thread.
+  map->Add<blink::mojom::BackgroundFetchService>(
+      base::BindRepeating(&BackgroundFetchServiceImpl::CreateForWorker),
+      base::CreateSingleThreadTaskRunnerWithTraits(BrowserThread::UI));
+}
+
+void PopulateBinderMap(ServiceWorkerProviderHost* host,
+                       service_manager::BinderMap* map) {
+  PopulateServiceWorkerBinders(host, map);
 }
 
 }  // namespace internal
diff --git a/content/browser/browser_interface_binders.h b/content/browser/browser_interface_binders.h
index a6476c1a..4715337 100644
--- a/content/browser/browser_interface_binders.h
+++ b/content/browser/browser_interface_binders.h
@@ -5,6 +5,7 @@
 #ifndef CONTENT_BROWSER_BROWSER_INTERFACE_BINDERS_H_
 #define CONTENT_BROWSER_BROWSER_INTERFACE_BINDERS_H_
 
+#include "content/public/browser/service_worker_running_info.h"
 #include "services/service_manager/public/cpp/binder_map.h"
 #include "url/origin.h"
 
@@ -14,6 +15,7 @@
 class RenderFrameHostImpl;
 class DedicatedWorkerHost;
 class SharedWorkerHost;
+class ServiceWorkerProviderHost;
 
 namespace internal {
 
@@ -27,27 +29,36 @@
 // handling InterfaceProvider's GetInterface() calls (see crbug.com/718652).
 
 // Registers the handlers for interfaces requested by frames.
-void PopulateBinderMap(RenderFrameHostImpl* rfhi,
+void PopulateBinderMap(RenderFrameHostImpl* host,
                        service_manager::BinderMap* map);
 void PopulateBinderMapWithContext(
-    RenderFrameHostImpl* rfhi,
+    RenderFrameHostImpl* host,
     service_manager::BinderMapWithContext<RenderFrameHost*>* map);
-RenderFrameHost* GetContextForHost(RenderFrameHostImpl* rfhi);
+RenderFrameHost* GetContextForHost(RenderFrameHostImpl* host);
 
 // Registers the handlers for interfaces requested by dedicated workers.
-void PopulateBinderMap(DedicatedWorkerHost* dwh,
+void PopulateBinderMap(DedicatedWorkerHost* host,
                        service_manager::BinderMap* map);
 void PopulateBinderMapWithContext(
-    DedicatedWorkerHost* dwh,
+    DedicatedWorkerHost* host,
     service_manager::BinderMapWithContext<const url::Origin&>* map);
-const url::Origin& GetContextForHost(DedicatedWorkerHost* dwh);
+const url::Origin& GetContextForHost(DedicatedWorkerHost* host);
 
 // Registers the handlers for interfaces requested by shared workers.
-void PopulateBinderMap(SharedWorkerHost* swh, service_manager::BinderMap* map);
+void PopulateBinderMap(SharedWorkerHost* host, service_manager::BinderMap* map);
 void PopulateBinderMapWithContext(
-    SharedWorkerHost* swh,
+    SharedWorkerHost* host,
     service_manager::BinderMapWithContext<const url::Origin&>* map);
-url::Origin GetContextForHost(SharedWorkerHost* swh);
+url::Origin GetContextForHost(SharedWorkerHost* host);
+
+// Registers the handlers for interfaces requested by service workers.
+void PopulateBinderMap(ServiceWorkerProviderHost* host,
+                       service_manager::BinderMap* map);
+void PopulateBinderMapWithContext(
+    ServiceWorkerProviderHost* host,
+    service_manager::BinderMapWithContext<const ServiceWorkerRunningInfo&>*
+        map);
+ServiceWorkerRunningInfo GetContextForHost(ServiceWorkerProviderHost* host);
 
 }  // namespace internal
 }  // namespace content
diff --git a/content/browser/devtools/protocol/network_handler.h b/content/browser/devtools/protocol/network_handler.h
index 6c11c0c1..6c0d4f8 100644
--- a/content/browser/devtools/protocol/network_handler.h
+++ b/content/browser/devtools/protocol/network_handler.h
@@ -202,10 +202,6 @@
       const network::ResourceRequest& request,
       const std::string& cookie_line);
 
-  void WillSendNavigationRequest(net::HttpRequestHeaders* headers,
-                                 bool* skip_service_worker,
-                                 bool* disable_cache);
-
  private:
   void RequestIntercepted(std::unique_ptr<InterceptedRequestInfo> request_info);
   void SetNetworkConditions(network::mojom::NetworkConditionsPtr conditions);
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 7f08c89..34bdc77 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -36,7 +36,6 @@
 #include "content/browser/accessibility/browser_accessibility_manager.h"
 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
 #include "content/browser/appcache/appcache_navigation_handle.h"
-#include "content/browser/background_fetch/background_fetch_service_impl.h"
 #include "content/browser/bluetooth/web_bluetooth_service_impl.h"
 #include "content/browser/browser_main_loop.h"
 #include "content/browser/child_process_security_policy_impl.h"
@@ -4344,9 +4343,6 @@
       GetProcess()->GetStoragePartition()->GetFileSystemContext(),
       ChromeBlobStorageContext::GetFor(GetProcess()->GetBrowserContext())));
 
-  registry_->AddInterface(base::BindRepeating(
-      &BackgroundFetchServiceImpl::CreateForFrame, GetProcess(), routing_id_));
-
   registry_->AddInterface(base::BindRepeating(&ContactsManagerImpl::Create,
                                               base::Unretained(this)));
 
diff --git a/content/browser/frame_host/render_frame_host_impl_browsertest.cc b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
index f12b1960..abccdad4 100644
--- a/content/browser/frame_host/render_frame_host_impl_browsertest.cc
+++ b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
@@ -36,6 +36,7 @@
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
 #include "content/public/test/navigation_handle_observer.h"
+#include "content/public/test/simple_url_loader_test_helper.h"
 #include "content/public/test/test_frame_navigation_observer.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "content/public/test/test_utils.h"
@@ -45,13 +46,20 @@
 #include "content/test/did_commit_navigation_interceptor.h"
 #include "content/test/frame_host_test_interface.mojom.h"
 #include "content/test/test_content_browser_client.h"
+#include "net/base/net_errors.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/controllable_http_response.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
 #include "services/network/test/test_url_loader_factory.h"
 #include "services/service_manager/public/mojom/interface_provider.mojom-test-utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
+#include "url/gurl.h"
+#include "url/origin.h"
 
 #if defined(OS_ANDROID)
 #include "base/android/build_info.h"
@@ -247,6 +255,33 @@
   SetBrowserClientForTesting(old_client);
 }
 
+// Check that the URLLoaderFactories created by RenderFrameHosts for renderers
+// are not trusted.
+IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
+                       URLLoaderFactoryNotTrusted) {
+  EXPECT_TRUE(NavigateToURL(shell(), embedded_test_server()->GetURL("/echo")));
+  network::mojom::URLLoaderFactoryPtr url_loader_factory;
+  shell()->web_contents()->GetMainFrame()->CreateNetworkServiceDefaultFactory(
+      mojo::MakeRequest(&url_loader_factory));
+
+  std::unique_ptr<network::ResourceRequest> request =
+      std::make_unique<network::ResourceRequest>();
+  request->url = embedded_test_server()->GetURL("/echo");
+  request->request_initiator =
+      url::Origin::Create(embedded_test_server()->base_url());
+  request->trusted_params = network::ResourceRequest::TrustedParams();
+
+  content::SimpleURLLoaderTestHelper simple_loader_helper;
+  std::unique_ptr<network::SimpleURLLoader> simple_loader =
+      network::SimpleURLLoader::Create(std::move(request),
+                                       TRAFFIC_ANNOTATION_FOR_TESTS);
+  simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
+      url_loader_factory.get(), simple_loader_helper.GetCallback());
+  simple_loader_helper.WaitForCallback();
+  EXPECT_FALSE(simple_loader_helper.response_body());
+  EXPECT_EQ(net::ERR_INVALID_ARGUMENT, simple_loader->NetError());
+}
+
 namespace {
 
 class TestJavaScriptDialogManager : public JavaScriptDialogManager,
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index d547331..5174402 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -174,14 +174,16 @@
   new_request->method = request_info->common_params->method;
   new_request->url = request_info->common_params->url;
   new_request->site_for_cookies = request_info->site_for_cookies;
-  new_request->trusted_network_isolation_key =
+  new_request->trusted_params = network::ResourceRequest::TrustedParams();
+  new_request->trusted_params->network_isolation_key =
       request_info->network_isolation_key;
 
   if (request_info->is_main_frame) {
-    new_request->update_network_isolation_key_on_redirect = network::mojom::
-        UpdateNetworkIsolationKeyOnRedirect::kUpdateTopFrameAndFrameOrigin;
+    new_request->trusted_params->update_network_isolation_key_on_redirect =
+        network::mojom::UpdateNetworkIsolationKeyOnRedirect::
+            kUpdateTopFrameAndFrameOrigin;
   } else {
-    new_request->update_network_isolation_key_on_redirect =
+    new_request->trusted_params->update_network_isolation_key_on_redirect =
         network::mojom::UpdateNetworkIsolationKeyOnRedirect::kUpdateFrameOrigin;
   }
 
@@ -330,7 +332,6 @@
     return options;
   }
 
-  // This can be called on the UI or IO thread.
   void Start(std::unique_ptr<network::SharedURLLoaderFactoryInfo>
                  network_loader_factory_info,
              ServiceWorkerNavigationHandle*
@@ -736,16 +737,17 @@
     if (resource_request_->resource_type ==
         static_cast<int>(ResourceType::kMainFrame)) {
       url::Origin origin = url::Origin::Create(resource_request_->url);
-      resource_request_->trusted_network_isolation_key =
+      resource_request_->trusted_params->network_isolation_key =
           net::NetworkIsolationKey(origin, origin);
     } else {
       DCHECK_EQ(static_cast<int>(ResourceType::kSubFrame),
                 resource_request_->resource_type);
       url::Origin subframe_origin = url::Origin::Create(resource_request_->url);
       base::Optional<url::Origin> top_frame_origin =
-          resource_request_->trusted_network_isolation_key.GetTopFrameOrigin();
+          resource_request_->trusted_params->network_isolation_key
+              .GetTopFrameOrigin();
       DCHECK(top_frame_origin);
-      resource_request_->trusted_network_isolation_key =
+      resource_request_->trusted_params->network_isolation_key =
           net::NetworkIsolationKey(top_frame_origin.value(), subframe_origin);
     }
 
@@ -1435,6 +1437,7 @@
       network::mojom::URLLoaderFactoryParams::New();
   params->header_client = std::move(header_client);
   params->process_id = network::mojom::kBrowserProcessId;
+  params->is_trusted = true;
   params->is_corb_enabled = false;
   params->disable_web_security =
       base::CommandLine::ForCurrentProcess()->HasSwitch(
diff --git a/content/browser/loader/navigation_url_loader_impl_unittest.cc b/content/browser/loader/navigation_url_loader_impl_unittest.cc
index 10b8267f..2aad945 100644
--- a/content/browser/loader/navigation_url_loader_impl_unittest.cc
+++ b/content/browser/loader/navigation_url_loader_impl_unittest.cc
@@ -329,8 +329,10 @@
   delegate.WaitForRequestStarted();
 
   ASSERT_TRUE(most_recent_resource_request_);
-  EXPECT_EQ(net::NetworkIsolationKey(origin, origin),
-            most_recent_resource_request_->trusted_network_isolation_key);
+  ASSERT_TRUE(most_recent_resource_request_->trusted_params);
+  EXPECT_EQ(
+      net::NetworkIsolationKey(origin, origin),
+      most_recent_resource_request_->trusted_params->network_isolation_key);
 }
 
 TEST_F(NavigationURLLoaderImplTest,
@@ -343,8 +345,10 @@
 
   HTTPRedirectOriginHeaderTest(url, "GET", "GET", url.GetOrigin().spec());
 
-  EXPECT_EQ(net::NetworkIsolationKey(origin, origin),
-            most_recent_resource_request_->trusted_network_isolation_key);
+  ASSERT_TRUE(most_recent_resource_request_->trusted_params);
+  EXPECT_EQ(
+      net::NetworkIsolationKey(origin, origin),
+      most_recent_resource_request_->trusted_params->network_isolation_key);
 }
 
 TEST_F(NavigationURLLoaderImplTest, Redirect301Tests) {
diff --git a/content/browser/media/url_provision_fetcher.cc b/content/browser/media/url_provision_fetcher.cc
index e72f880..0c61dbb 100644
--- a/content/browser/media/url_provision_fetcher.cc
+++ b/content/browser/media/url_provision_fetcher.cc
@@ -77,8 +77,7 @@
         })");
   auto resource_request = std::make_unique<network::ResourceRequest>();
   resource_request->url = GURL(request_string);
-  resource_request->load_flags =
-      net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES;
+  resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
   resource_request->method = "POST";
   resource_request->headers.SetHeader("User-Agent", "Widevine CDM v1.0");
   simple_url_loader_ = network::SimpleURLLoader::Create(
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc
index fd1c4542..98576f6c 100644
--- a/content/browser/navigation_browsertest.cc
+++ b/content/browser/navigation_browsertest.cc
@@ -290,11 +290,14 @@
     URLLoaderInterceptor interceptor(base::BindLambdaForTesting(
         [&](URLLoaderInterceptor::RequestParams* params) -> bool {
           base::AutoLock top_frame_origins_lock(lock);
-          (*network_isolation_keys)[params->url_request.url] =
-              params->url_request.trusted_network_isolation_key;
-          (*update_network_isolation_key_on_redirects)[params->url_request
-                                                           .url] =
-              params->url_request.update_network_isolation_key_on_redirect;
+          if (params->url_request.trusted_params) {
+            (*network_isolation_keys)[params->url_request.url] =
+                params->url_request.trusted_params->network_isolation_key;
+            (*update_network_isolation_key_on_redirects)[params->url_request
+                                                             .url] =
+                params->url_request.trusted_params
+                    ->update_network_isolation_key_on_redirect;
+          }
 
           if (params->url_request.url == final_resource)
             run_loop.Quit();
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm
index 66edee6..cb1bf72 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -343,8 +343,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 // RenderWidgetHostViewMac, RenderWidgetHostView implementation:
 
-void RenderWidgetHostViewMac::InitAsChild(
-    gfx::NativeView parent_view) {
+void RenderWidgetHostViewMac::InitAsChild(gfx::NativeView parent_view) {
   DCHECK_EQ(widget_type_, WidgetType::kFrame);
 }
 
@@ -375,15 +374,15 @@
 }
 
 RenderWidgetHostViewBase*
-    RenderWidgetHostViewMac::GetFocusedViewForTextSelection() {
+RenderWidgetHostViewMac::GetFocusedViewForTextSelection() {
   // We obtain the TextSelection from focused RWH which is obtained from the
   // frame tree. BrowserPlugin-based guests' RWH is not part of the frame tree
   // and the focused RWH will be that of the embedder which is incorrect. In
   // this case we should use TextSelection for |this| since RWHV for guest
   // forwards text selection information to its platform view.
-  return is_guest_view_hack_ ? this : GetFocusedWidget()
-                                          ? GetFocusedWidget()->GetView()
-                                          : nullptr;
+  return is_guest_view_hack_
+             ? this
+             : GetFocusedWidget() ? GetFocusedWidget()->GetView() : nullptr;
 }
 
 RenderWidgetHostDelegate*
@@ -441,8 +440,6 @@
   is_visible_ = true;
   ns_view_->SetVisible(is_visible_);
   browser_compositor_->SetViewVisible(is_visible_);
-  browser_compositor_->SetRenderWidgetHostIsHidden(false);
-
   WasUnOccluded();
 }
 
@@ -450,11 +447,13 @@
   is_visible_ = false;
   ns_view_->SetVisible(is_visible_);
   browser_compositor_->SetViewVisible(is_visible_);
-  host()->WasHidden();
-  browser_compositor_->SetRenderWidgetHostIsHidden(true);
+  WasOccluded();
 }
 
 void RenderWidgetHostViewMac::WasUnOccluded() {
+  if (!host()->is_hidden())
+    return;
+
   browser_compositor_->SetRenderWidgetHostIsHidden(false);
 
   DelegatedFrameHost* delegated_frame_host =
@@ -483,6 +482,9 @@
 }
 
 void RenderWidgetHostViewMac::WasOccluded() {
+  if (host()->is_hidden())
+    return;
+
   host()->WasHidden();
   browser_compositor_->SetRenderWidgetHostIsHidden(true);
 }
@@ -636,8 +638,8 @@
   // the same as the caret position if the selection is collapsed. That's
   // what we want to try to keep centered on-screen if possible.
   gfx::Rect gfx_caret_rect(region->focus.edge_top_rounded().x(),
-                           region->focus.edge_top_rounded().y(),
-                           1, region->focus.GetHeight());
+                           region->focus.edge_top_rounded().y(), 1,
+                           region->focus.GetHeight());
   gfx_caret_rect += view_bounds_in_window_dip_.OffsetFromOrigin();
   gfx_caret_rect += window_frame_in_screen_dip_.OffsetFromOrigin();
 
diff --git a/content/browser/renderer_interface_binders.cc b/content/browser/renderer_interface_binders.cc
index 95bed38..6edb128 100644
--- a/content/browser/renderer_interface_binders.cc
+++ b/content/browser/renderer_interface_binders.cc
@@ -10,7 +10,6 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/no_destructor.h"
-#include "content/browser/background_fetch/background_fetch_service_impl.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/content_index/content_index_service_impl.h"
 #include "content/browser/cookie_store/cookie_store_context.h"
@@ -204,8 +203,6 @@
             ->CreateService(origin, std::move(request));
       }));
   parameterized_binder_registry_.AddInterface(
-      base::BindRepeating(&BackgroundFetchServiceImpl::CreateForWorker));
-  parameterized_binder_registry_.AddInterface(
       base::BindRepeating(&QuotaDispatcherHost::CreateForWorker));
   parameterized_binder_registry_.AddInterface(base::BindRepeating(
       [](blink::mojom::CookieStoreRequest request, RenderProcessHost* host,
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc
index 4d1a3938..03fba97 100644
--- a/content/browser/service_worker/embedded_worker_instance.cc
+++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -794,7 +794,9 @@
 
   // The host must be alive as long as |params->provider_info| is alive.
   owner_version_->provider_host()->CompleteStartWorkerPreparation(
-      process_id(), MakeRequest(&params->provider_info->interface_provider));
+      process_id(), MakeRequest(&params->provider_info->interface_provider),
+      params->provider_info->browser_interface_broker
+          .InitWithNewPipeAndPassReceiver());
   client_->StartWorker(std::move(params));
 
   starting_phase_ = is_script_streaming ? SCRIPT_STREAMING : SENT_START_WORKER;
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc
index 75ad35ed..510d586 100644
--- a/content/browser/service_worker/service_worker_provider_host.cc
+++ b/content/browser/service_worker/service_worker_provider_host.cc
@@ -664,8 +664,9 @@
 
 void ServiceWorkerProviderHost::CompleteStartWorkerPreparation(
     int process_id,
-    service_manager::mojom::InterfaceProviderRequest
-        interface_provider_request) {
+    service_manager::mojom::InterfaceProviderRequest interface_provider_request,
+    mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker>
+        broker_receiver) {
   DCHECK(context_);
   DCHECK_EQ(ChildProcessHost::kInvalidUniqueID, render_process_id_);
   DCHECK_NE(ChildProcessHost::kInvalidUniqueID, process_id);
@@ -676,6 +677,8 @@
   interface_provider_binding_.Bind(FilterRendererExposedInterfaces(
       blink::mojom::kNavigation_ServiceWorkerSpec, process_id,
       std::move(interface_provider_request)));
+
+  broker_receiver_.Bind(std::move(broker_receiver));
 }
 
 void ServiceWorkerProviderHost::CompleteWebWorkerPreparation() {
diff --git a/content/browser/service_worker/service_worker_provider_host.h b/content/browser/service_worker/service_worker_provider_host.h
index 66ac098..425da59d 100644
--- a/content/browser/service_worker/service_worker_provider_host.h
+++ b/content/browser/service_worker/service_worker_provider_host.h
@@ -20,6 +20,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "base/unguessable_token.h"
+#include "content/browser/browser_interface_broker_impl.h"
 #include "content/browser/service_worker/service_worker_object_host.h"
 #include "content/browser/service_worker/service_worker_registration.h"
 #include "content/common/content_export.h"
@@ -324,7 +325,9 @@
   void CompleteStartWorkerPreparation(
       int process_id,
       service_manager::mojom::InterfaceProviderRequest
-          interface_provider_request);
+          interface_provider_request,
+      mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker>
+          broker_receiver);
 
   // Called when the web worker main script resource has finished loading.
   // After this is called, is_response_committed() and is_execution_ready()
@@ -685,6 +688,11 @@
   // For service worker execution contexts.
   mojo::Binding<service_manager::mojom::InterfaceProvider>
       interface_provider_binding_;
+  BrowserInterfaceBrokerImpl<ServiceWorkerProviderHost,
+                             const ServiceWorkerRunningInfo&>
+      broker_{this};
+  mojo::Receiver<blink::mojom::BrowserInterfaceBroker> broker_receiver_{
+      &broker_};
 
   // For service worker clients.
   ClientPhase client_phase_ = ClientPhase::kInitial;
diff --git a/content/browser/service_worker/service_worker_single_script_update_checker.cc b/content/browser/service_worker/service_worker_single_script_update_checker.cc
index 74c9892..f5a2f0ec 100644
--- a/content/browser/service_worker/service_worker_single_script_update_checker.cc
+++ b/content/browser/service_worker/service_worker_single_script_update_checker.cc
@@ -132,7 +132,8 @@
 
   // This key is used to isolate requests from different contexts in accessing
   // shared network resources like the http cache.
-  resource_request.trusted_network_isolation_key =
+  resource_request.trusted_params = network::ResourceRequest::TrustedParams();
+  resource_request.trusted_params->network_isolation_key =
       net::NetworkIsolationKey(origin, origin);
 
   if (is_main_script_) {
diff --git a/content/browser/service_worker/service_worker_test_utils.cc b/content/browser/service_worker/service_worker_test_utils.cc
index 9fe2eaa..f34b104 100644
--- a/content/browser/service_worker/service_worker_test_utils.cc
+++ b/content/browser/service_worker/service_worker_test_utils.cc
@@ -307,7 +307,8 @@
           &provider_info);
 
   host->CompleteStartWorkerPreparation(
-      process_id, mojo::MakeRequest(&provider_info->interface_provider));
+      process_id, mojo::MakeRequest(&provider_info->interface_provider),
+      provider_info->browser_interface_broker.InitWithNewPipeAndPassReceiver());
   output_endpoint->BindForServiceWorker(std::move(provider_info));
   return host;
 }
diff --git a/content/browser/sms/sms_browsertest.cc b/content/browser/sms/sms_browsertest.cc
index b4be6b6..1a9e7411 100644
--- a/content/browser/sms/sms_browsertest.cc
+++ b/content/browser/sms/sms_browsertest.cc
@@ -72,20 +72,19 @@
 
   auto* dialog = new NiceMock<MockSmsDialog>();
 
-  base::OnceClosure on_confirm_callback;
+  SmsDialog::EventHandler hdl;
 
   EXPECT_CALL(delegate_, CreateSmsDialog(_))
       .WillOnce(Return(ByMove(base::WrapUnique(dialog))));
 
-  EXPECT_CALL(*dialog, Open(_, _, _))
-      .WillOnce(Invoke([&on_confirm_callback](content::RenderFrameHost*,
-                                              base::OnceClosure on_confirm,
-                                              base::OnceClosure on_cancel) {
-        on_confirm_callback = std::move(on_confirm);
-      }));
+  EXPECT_CALL(*dialog, Open(_, _))
+      .WillOnce(
+          Invoke([&hdl](RenderFrameHost*, SmsDialog::EventHandler handler) {
+            hdl = std::move(handler);
+          }));
 
-  EXPECT_CALL(*dialog, SmsReceived()).WillOnce(Invoke([&on_confirm_callback]() {
-    std::move(on_confirm_callback).Run();
+  EXPECT_CALL(*dialog, SmsReceived()).WillOnce(Invoke([&hdl]() {
+    std::move(hdl).Run(SmsDialog::Event::kConfirm);
   }));
 
   auto* provider = new NiceMock<MockSmsProvider>();
@@ -117,20 +116,19 @@
 
   auto* dialog = new NiceMock<MockSmsDialog>();
 
-  base::OnceClosure on_confirm_callback;
+  SmsDialog::EventHandler hdl;
 
   EXPECT_CALL(delegate_, CreateSmsDialog(_))
       .WillOnce(Return(ByMove(base::WrapUnique(dialog))));
 
-  EXPECT_CALL(*dialog, Open(_, _, _))
-      .WillOnce(Invoke([&on_confirm_callback](content::RenderFrameHost*,
-                                              base::OnceClosure on_confirm,
-                                              base::OnceClosure on_cancel) {
-        on_confirm_callback = std::move(on_confirm);
-      }));
+  EXPECT_CALL(*dialog, Open(_, _))
+      .WillOnce(
+          Invoke([&hdl](RenderFrameHost*, SmsDialog::EventHandler handler) {
+            hdl = std::move(handler);
+          }));
 
-  EXPECT_CALL(*dialog, SmsReceived()).WillOnce(Invoke([&on_confirm_callback]() {
-    std::move(on_confirm_callback).Run();
+  EXPECT_CALL(*dialog, SmsReceived()).WillOnce(Invoke([&hdl]() {
+    std::move(hdl).Run(SmsDialog::Event::kConfirm);
   }));
 
   auto* provider = new NiceMock<MockSmsProvider>();
@@ -244,7 +242,8 @@
     true
   )";
 
-  base::OnceClosure on_confirm1, on_confirm2;
+  SmsDialog::EventHandler hdl_1;
+  SmsDialog::EventHandler hdl_2;
 
   {
     base::RunLoop loop;
@@ -260,12 +259,11 @@
       loop.Quit();
     }));
 
-    EXPECT_CALL(*dialog, Open(_, _, _))
-        .WillOnce(Invoke([&on_confirm1](content::RenderFrameHost*,
-                                        base::OnceClosure on_confirm,
-                                        base::OnceClosure on_cancel) {
-          on_confirm1 = std::move(on_confirm);
-        }));
+    EXPECT_CALL(*dialog, Open(_, _))
+        .WillOnce(
+            Invoke([&hdl_1](RenderFrameHost*, SmsDialog::EventHandler handler) {
+              hdl_1 = std::move(handler);
+            }));
 
     // First tab registers an observer.
     EXPECT_EQ(true, EvalJs(tab1, script));
@@ -287,12 +285,11 @@
       loop.Quit();
     }));
 
-    EXPECT_CALL(*dialog, Open(_, _, _))
-        .WillOnce(Invoke([&on_confirm2](content::RenderFrameHost*,
-                                        base::OnceClosure on_confirm,
-                                        base::OnceClosure on_cancel) {
-          on_confirm2 = std::move(on_confirm);
-        }));
+    EXPECT_CALL(*dialog, Open(_, _))
+        .WillOnce(
+            Invoke([&hdl_2](RenderFrameHost*, SmsDialog::EventHandler handler) {
+              hdl_2 = std::move(handler);
+            }));
 
     // Second tab registers an observer.
     EXPECT_EQ(true, EvalJs(tab2, script));
@@ -304,7 +301,7 @@
 
   provider->NotifyReceive(url::Origin::Create(url), "hello1");
 
-  std::move(on_confirm1).Run();
+  std::move(hdl_1).Run(SmsDialog::Event::kConfirm);
 
   EXPECT_EQ("hello1", EvalJs(tab1, "sms"));
 
@@ -312,7 +309,7 @@
 
   provider->NotifyReceive(url::Origin::Create(url), "hello2");
 
-  std::move(on_confirm2).Run();
+  std::move(hdl_2).Run(SmsDialog::Event::kConfirm);
 
   EXPECT_EQ("hello2", EvalJs(tab2, "sms"));
 
@@ -356,26 +353,24 @@
   auto* dialog1 = new NiceMock<MockSmsDialog>();
   auto* dialog2 = new NiceMock<MockSmsDialog>();
 
-  base::OnceClosure on_confirm_callback1;
-  base::OnceClosure on_confirm_callback2;
+  SmsDialog::EventHandler hdl_1;
+  SmsDialog::EventHandler hdl_2;
 
   EXPECT_CALL(delegate_, CreateSmsDialog(_))
       .WillOnce(Return(ByMove(base::WrapUnique(dialog1))))
       .WillOnce(Return(ByMove(base::WrapUnique(dialog2))));
 
-  EXPECT_CALL(*dialog1, Open(_, _, _))
-      .WillOnce(Invoke([&on_confirm_callback1](content::RenderFrameHost*,
-                                               base::OnceClosure on_confirm,
-                                               base::OnceClosure on_cancel) {
-        on_confirm_callback1 = std::move(on_confirm);
-      }));
+  EXPECT_CALL(*dialog1, Open(_, _))
+      .WillOnce(
+          Invoke([&hdl_1](RenderFrameHost*, SmsDialog::EventHandler handler) {
+            hdl_1 = std::move(handler);
+          }));
 
-  EXPECT_CALL(*dialog2, Open(_, _, _))
-      .WillOnce(Invoke([&on_confirm_callback2](content::RenderFrameHost*,
-                                               base::OnceClosure on_confirm,
-                                               base::OnceClosure on_cancel) {
-        on_confirm_callback2 = std::move(on_confirm);
-      }));
+  EXPECT_CALL(*dialog2, Open(_, _))
+      .WillOnce(
+          Invoke([&hdl_2](RenderFrameHost*, SmsDialog::EventHandler handler) {
+            hdl_2 = std::move(handler);
+          }));
 
   EXPECT_EQ(true, EvalJs(tab1, script));
   EXPECT_EQ(true, EvalJs(tab2, script));
@@ -386,7 +381,7 @@
 
   provider->NotifyReceive(url::Origin::Create(url1), "hello1");
 
-  std::move(on_confirm_callback1).Run();
+  std::move(hdl_1).Run(SmsDialog::Event::kConfirm);
 
   EXPECT_EQ("hello1", EvalJs(tab1, "sms"));
 
@@ -394,7 +389,7 @@
 
   provider->NotifyReceive(url::Origin::Create(url2), "hello2");
 
-  std::move(on_confirm_callback2).Run();
+  std::move(hdl_2).Run(SmsDialog::Event::kConfirm);
 
   EXPECT_EQ("hello2", EvalJs(tab2, "sms"));
 
@@ -446,13 +441,11 @@
   EXPECT_CALL(delegate, CreateSmsDialog(_))
       .WillOnce(Return(ByMove(base::WrapUnique(dialog))));
 
-  EXPECT_CALL(*dialog, Open(_, _, _))
-      .WillOnce(
-          Invoke([](content::RenderFrameHost*, base::OnceClosure on_confirm,
-                    base::OnceClosure on_cancel) {
-            // Simulates the user pressing "cancel".
-            std::move(on_cancel).Run();
-          }));
+  EXPECT_CALL(*dialog, Open(_, _))
+      .WillOnce(Invoke([](RenderFrameHost*, SmsDialog::EventHandler handler) {
+        // Simulates the user pressing "cancel".
+        std::move(handler).Run(SmsDialog::Event::kCancel);
+      }));
 
   EXPECT_CALL(*dialog, Close()).WillOnce(Return());
 
@@ -479,6 +472,23 @@
   BrowserMainLoop::GetInstance()->SetSmsProviderForTesting(
       base::WrapUnique(provider));
 
+  StrictMock<MockSmsWebContentsDelegate> delegate;
+  shell()->web_contents()->SetDelegate(&delegate);
+
+  auto* dialog = new StrictMock<MockSmsDialog>();
+
+  EXPECT_CALL(delegate, CreateSmsDialog(_))
+      .WillOnce(Return(ByMove(base::WrapUnique(dialog))));
+
+  EXPECT_CALL(*dialog, Open(_, _))
+      .WillOnce(Invoke([](content::RenderFrameHost*,
+                          content::SmsDialog::EventHandler event_handler) {
+        // Simulates the user pressing "Try again".
+        std::move(event_handler).Run(SmsDialog::Event::kTimeout);
+      }));
+
+  EXPECT_CALL(*dialog, Close()).WillOnce(Return());
+
   std::string script = R"(
     (async () => {
       try {
diff --git a/content/browser/sms/sms_service.cc b/content/browser/sms/sms_service.cc
index e3690f53..8141f78 100644
--- a/content/browser/sms/sms_service.cc
+++ b/content/browser/sms/sms_service.cc
@@ -10,6 +10,7 @@
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
+#include "base/logging.h"
 #include "base/optional.h"
 #include "content/browser/sms/sms_metrics.h"
 #include "content/public/browser/sms_dialog.h"
@@ -116,9 +117,7 @@
   DCHECK(callback_);
   DCHECK(!timer_.IsRunning());
 
-  std::move(callback_).Run(blink::mojom::SmsStatus::kTimeout, base::nullopt);
-
-  Dismiss();
+  prompt_->SmsTimeout();
 }
 
 void SmsService::OnConfirm() {
@@ -143,16 +142,36 @@
   Process(SmsStatus::kCancelled, base::nullopt);
 }
 
+void SmsService::OnTryAgain() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  Process(SmsStatus::kTimeout, base::nullopt);
+}
+
+void SmsService::OnEvent(SmsDialog::Event event_type) {
+  switch (event_type) {
+    case SmsDialog::Event::kConfirm:
+      OnConfirm();
+      return;
+    case SmsDialog::Event::kCancel:
+      OnCancel();
+      return;
+    case SmsDialog::Event::kTimeout:
+      OnTryAgain();
+      return;
+  }
+  DVLOG(1) << "Unsupported event type: " << event_type;
+  NOTREACHED();
+}
+
 void SmsService::Prompt() {
   WebContents* web_contents =
-      content::WebContents::FromRenderFrameHost(render_frame_host());
+      WebContents::FromRenderFrameHost(render_frame_host());
   const url::Origin origin = render_frame_host()->GetLastCommittedOrigin();
   prompt_ = web_contents->GetDelegate()->CreateSmsDialog(origin);
   if (prompt_) {
-    prompt_->Open(
-        render_frame_host(),
-        base::BindOnce(&SmsService::OnConfirm, base::Unretained(this)),
-        base::BindOnce(&SmsService::OnCancel, base::Unretained(this)));
+    prompt_->Open(render_frame_host(),
+                  base::BindOnce(&SmsService::OnEvent, base::Unretained(this)));
   }
 }
 
diff --git a/content/browser/sms/sms_service.h b/content/browser/sms/sms_service.h
index 5426cbe..2c7466ff 100644
--- a/content/browser/sms/sms_service.h
+++ b/content/browser/sms/sms_service.h
@@ -15,6 +15,7 @@
 #include "content/browser/sms/sms_provider.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/frame_service_base.h"
+#include "content/public/browser/sms_dialog.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "third_party/blink/public/mojom/sms/sms_receiver.mojom.h"
 #include "url/origin.h"
@@ -60,10 +61,15 @@
 
   // Callback when the |timer_| times out.
   void OnTimeout();
-  // Callback when the user manually clicks 'Confirm' button.
+  // Called when the user manually clicks 'Confirm' button.
   void OnConfirm();
-  // Callback when the user manually dismisses the dialog.
+  // Called when the user manually dismisses the dialog.
   void OnCancel();
+  // Callback when the user manually clicks 'Try again' button after a timeout.
+  void OnTryAgain();
+
+  // Handles the user's action.
+  void OnEvent(SmsDialog::Event event_type);
 
   // |sms_provider_| is safe because all instances of SmsProvider are owned
   // by a SmsKeyedService, which is owned by a Profile, which transitively
diff --git a/content/browser/sms/sms_service_unittest.cc b/content/browser/sms/sms_service_unittest.cc
index 25529c4..32e0f18 100644
--- a/content/browser/sms/sms_service_unittest.cc
+++ b/content/browser/sms/sms_service_unittest.cc
@@ -78,23 +78,22 @@
   NiceMock<MockSmsWebContentsDelegate>* delegate() { return &delegate_; }
   NiceMock<MockSmsProvider>* provider() { return &provider_; }
 
-  void SetupSmsDialog(content::RenderFrameHost* rfh) {
+  void SetupSmsDialog(RenderFrameHost* rfh) {
     auto* dialog = new NiceMock<MockSmsDialog>();
 
     EXPECT_CALL(*delegate(), CreateSmsDialog(_))
         .WillOnce(Return(ByMove(base::WrapUnique(dialog))));
 
-    EXPECT_CALL(*dialog, Open(rfh, _, _))
+    EXPECT_CALL(*dialog, Open(rfh, _))
         .WillOnce(
-            Invoke([&](content::RenderFrameHost*, base::OnceClosure on_confirm,
-                       base::OnceClosure on_cancel) {
-              on_confirm_callback_ = std::move(on_confirm);
+            Invoke([&](RenderFrameHost*, SmsDialog::EventHandler handler) {
+              handler_ = std::move(handler);
             }));
 
     EXPECT_CALL(*dialog, SmsReceived()).WillOnce(Invoke([&]() {
       // Simulates user clicking the "Confirm" button to verify received
       // sms.
-      std::move(on_confirm_callback_).Run();
+      std::move(handler_).Run(SmsDialog::Event::kConfirm);
     }));
 
     EXPECT_CALL(*dialog, Close()).WillOnce(Return());
@@ -113,7 +112,7 @@
   NiceMock<MockSmsProvider> provider_;
   blink::mojom::SmsReceiverPtr service_ptr_;
   std::unique_ptr<SmsService> service_;
-  base::OnceClosure on_confirm_callback_;
+  SmsDialog::EventHandler handler_;
 };
 
 class SmsServiceTest : public RenderViewHostTestHarness {
@@ -350,6 +349,18 @@
             loop.Quit();
           }));
 
+  auto* dialog = new NiceMock<MockSmsDialog>();
+
+  EXPECT_CALL(*service.delegate(), CreateSmsDialog(_))
+      .WillOnce(Return(ByMove(base::WrapUnique(dialog))));
+
+  EXPECT_CALL(*dialog, Open(main_rfh(), _))
+      .WillOnce(Invoke([](content::RenderFrameHost*,
+                          content::SmsDialog::EventHandler event_handler) {
+        // Simulates the user pressing "Try again".
+        std::move(event_handler).Run(SmsDialog::Event::kTimeout);
+      }));
+
   loop.Run();
 }
 
@@ -441,13 +452,11 @@
   EXPECT_CALL(*service.delegate(), CreateSmsDialog(_))
       .WillOnce(Return(ByMove(base::WrapUnique(dialog))));
 
-  EXPECT_CALL(*dialog, Open(main_rfh(), _, _))
-      .WillOnce(
-          Invoke([](content::RenderFrameHost*, base::OnceClosure on_confirm,
-                    base::OnceClosure on_cancel) {
-            // Simulates the user pressing "Cancel".
-            std::move(on_cancel).Run();
-          }));
+  EXPECT_CALL(*dialog, Open(main_rfh(), _))
+      .WillOnce(Invoke([](RenderFrameHost*, SmsDialog::EventHandler handler) {
+        // Simulates the user pressing "Cancel".
+        std::move(handler).Run(SmsDialog::Event::kCancel);
+      }));
 
   loop.Run();
 
@@ -479,7 +488,12 @@
 
   // Deliberately avoid calling the on_cancel callback, to simulate the
   // sms being timed out before the user cancels it.
-  EXPECT_CALL(*dialog, Open(main_rfh(), _, _)).WillOnce(Return());
+  EXPECT_CALL(*dialog, Open(main_rfh(), _))
+      .WillOnce(Invoke([](content::RenderFrameHost*,
+                          content::SmsDialog::EventHandler event_handler) {
+        // Simulates the user pressing "Try again".
+        std::move(event_handler).Run(SmsDialog::Event::kTimeout);
+      }));
 
   EXPECT_CALL(*dialog, Close()).WillOnce(Return());
 
@@ -496,24 +510,28 @@
   auto* dialog1 = new NiceMock<MockSmsDialog>();
   auto* dialog2 = new NiceMock<MockSmsDialog>();
 
-  base::OnceClosure on_confirm_callback;
+  SmsDialog::EventHandler hdl;
 
   EXPECT_CALL(*service.delegate(), CreateSmsDialog(_))
       .WillOnce(Return(ByMove(base::WrapUnique(dialog1))))
       .WillOnce(Return(ByMove(base::WrapUnique(dialog2))));
 
-  EXPECT_CALL(*dialog1, Open(main_rfh(), _, _))
-      .WillOnce(Invoke([&on_confirm_callback](content::RenderFrameHost*,
-                                              base::OnceClosure on_confirm,
-                                              base::OnceClosure on_cancel) {
-        on_confirm_callback = std::move(on_confirm);
+  EXPECT_CALL(*dialog1, Open(main_rfh(), _))
+      .WillOnce(
+          Invoke([&hdl](RenderFrameHost*, SmsDialog::EventHandler handler) {
+            hdl = std::move(handler);
+          }));
+
+  EXPECT_CALL(*dialog2, Open(main_rfh(), _))
+      .WillOnce(Invoke([](content::RenderFrameHost*,
+                          content::SmsDialog::EventHandler event_handler) {
+        // Simulates the user pressing "Try again".
+        std::move(event_handler).Run(SmsDialog::Event::kTimeout);
       }));
 
-  EXPECT_CALL(*dialog2, Open(main_rfh(), _, _)).Times(1);
-
-  EXPECT_CALL(*dialog1, SmsReceived())
-      .WillOnce(Invoke(
-          [&on_confirm_callback]() { std::move(on_confirm_callback).Run(); }));
+  EXPECT_CALL(*dialog1, SmsReceived()).WillOnce(Invoke([&hdl]() {
+    std::move(hdl).Run(SmsDialog::Event::kConfirm);
+  }));
 
   EXPECT_CALL(*service.provider(), Retrieve())
       .WillOnce(Invoke([&service]() {
@@ -601,13 +619,11 @@
     EXPECT_CALL(*service.delegate(), CreateSmsDialog(_))
         .WillOnce(Return(ByMove(base::WrapUnique(dialog))));
 
-    EXPECT_CALL(*dialog, Open(main_rfh(), _, _))
-        .WillOnce(
-            Invoke([](content::RenderFrameHost*, base::OnceClosure on_confirm,
-                      base::OnceClosure on_cancel) {
-              // Simulates the user pressing "Cancel".
-              std::move(on_cancel).Run();
-            }));
+    EXPECT_CALL(*dialog, Open(main_rfh(), _))
+        .WillOnce(Invoke([](RenderFrameHost*, SmsDialog::EventHandler handler) {
+          // Simulates the user pressing "Cancel".
+          std::move(handler).Run(SmsDialog::Event::kCancel);
+        }));
 
     loop.Run();
 
@@ -637,21 +653,20 @@
             }));
 
     auto* dialog = new NiceMock<MockSmsDialog>();
-    base::OnceClosure on_cancel_callback;
+    SmsDialog::EventHandler hdl;
 
     EXPECT_CALL(*service.delegate(), CreateSmsDialog(_))
         .WillOnce(Return(ByMove(base::WrapUnique(dialog))));
 
-    EXPECT_CALL(*dialog, Open(main_rfh(), _, _))
-        .WillOnce(Invoke([&on_cancel_callback](content::RenderFrameHost*,
-                                               base::OnceClosure on_confirm,
-                                               base::OnceClosure on_cancel) {
-          on_cancel_callback = std::move(on_cancel);
-        }));
+    EXPECT_CALL(*dialog, Open(main_rfh(), _))
+        .WillOnce(
+            Invoke([&hdl](RenderFrameHost*, SmsDialog::EventHandler handler) {
+              hdl = std::move(handler);
+            }));
 
     EXPECT_CALL(*dialog, SmsReceived()).WillOnce(Invoke([&]() {
       // Simulates user clicking the "Cancel" once the SMS has been received.
-      std::move(on_cancel_callback).Run();
+      std::move(hdl).Run(SmsDialog::Event::kCancel);
     }));
 
     loop.Run();
diff --git a/content/browser/sms/test/mock_sms_dialog.h b/content/browser/sms/test/mock_sms_dialog.h
index 8daf897..73024b4 100644
--- a/content/browser/sms/test/mock_sms_dialog.h
+++ b/content/browser/sms/test/mock_sms_dialog.h
@@ -16,10 +16,10 @@
   MockSmsDialog();
   ~MockSmsDialog() override;
 
-  MOCK_METHOD3(Open,
-               void(RenderFrameHost*, base::OnceClosure, base::OnceClosure));
+  MOCK_METHOD2(Open, void(RenderFrameHost*, EventHandler handler));
   MOCK_METHOD0(Close, void());
   MOCK_METHOD0(SmsReceived, void());
+  MOCK_METHOD0(SmsTimeout, void());
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockSmsDialog);
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index d5b4ce8..4fbc08e 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -1801,6 +1801,9 @@
       network::mojom::URLLoaderFactoryParams::New();
   params->process_id = network::mojom::kBrowserProcessId;
   params->is_corb_enabled = corb_enabled;
+  // Corb requests are likely made on behalf of untrusted renderers.
+  if (!corb_enabled)
+    params->is_trusted = true;
   params->disable_web_security =
       base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kDisableWebSecurity);
diff --git a/content/browser/url_loader_factory_getter.cc b/content/browser/url_loader_factory_getter.cc
index a30aac9..377ac68 100644
--- a/content/browser/url_loader_factory_getter.cc
+++ b/content/browser/url_loader_factory_getter.cc
@@ -285,6 +285,8 @@
     return;
   network::mojom::URLLoaderFactoryParamsPtr params =
       network::mojom::URLLoaderFactoryParams::New();
+  // The browser process is considered trusted.
+  params->is_trusted = true;
   params->process_id = network::mojom::kBrowserProcessId;
   params->is_corb_enabled = is_corb_enabled;
   params->disable_web_security =
diff --git a/content/browser/worker_host/worker_script_fetch_initiator.cc b/content/browser/worker_host/worker_script_fetch_initiator.cc
index 93d41527..98b244e 100644
--- a/content/browser/worker_host/worker_script_fetch_initiator.cc
+++ b/content/browser/worker_host/worker_script_fetch_initiator.cc
@@ -119,7 +119,8 @@
   resource_request = std::make_unique<network::ResourceRequest>();
   resource_request->url = script_url;
   resource_request->site_for_cookies = script_url;
-  resource_request->trusted_network_isolation_key =
+  resource_request->trusted_params = network::ResourceRequest::TrustedParams();
+  resource_request->trusted_params->network_isolation_key =
       trusted_network_isolation_key;
   resource_request->request_initiator = request_initiator;
   resource_request->referrer = sanitized_referrer.url,
diff --git a/content/child/child_process.cc b/content/child/child_process.cc
index 6b0532c..33de333 100644
--- a/content/child/child_process.cc
+++ b/content/child/child_process.cc
@@ -16,6 +16,7 @@
 #include "base/threading/thread_local.h"
 #include "build/build_config.h"
 #include "content/child/child_thread_impl.h"
+#include "services/tracing/public/cpp/trace_startup.h"
 #include "third_party/blink/public/common/features.h"
 
 namespace content {
@@ -51,6 +52,7 @@
     DCHECK(base::ThreadPoolInstance::Get());
     initialized_thread_pool_ = true;
   }
+  tracing::InitTracingPostThreadPoolStartAndFeatureList();
 
   // We can't recover from failing to start the IO thread.
   base::Thread::Options thread_options(base::MessagePumpType::IO, 0);
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn
index 0e2f82f..ab69d8e 100644
--- a/content/public/android/BUILD.gn
+++ b/content/public/android/BUILD.gn
@@ -364,6 +364,7 @@
     "//content/public/browser/browsing_data_remover.h",
     "//content/public/browser/invalidate_type.h",
     "//content/public/browser/navigation_controller.h",
+    "//content/public/browser/sms_dialog.h",
     "//content/public/common/browser_controls_state.h",
     "//content/public/common/console_message_level.h",
     "//content/public/common/screen_orientation_values.h",
diff --git a/content/public/app/content_browser_manifest.cc b/content/public/app/content_browser_manifest.cc
index 23d3741..c7fc99c0 100644
--- a/content/public/app/content_browser_manifest.cc
+++ b/content/public/app/content_browser_manifest.cc
@@ -197,7 +197,6 @@
           .ExposeInterfaceFilterCapability_Deprecated(
               "navigation:service_worker", "renderer",
               std::set<const char*>{
-                  "blink.mojom.BackgroundFetchService",
                   "blink.mojom.CacheStorage", "blink.mojom.CookieStore",
                   "blink.mojom.ContentIndexService", "blink.mojom.IDBFactory",
                   "blink.mojom.LockManager",
@@ -218,7 +217,6 @@
                   "autofill.mojom.AutofillDriver",
                   "autofill.mojom.PasswordManagerDriver",
                   "blink.mojom.AnchorElementMetricsHost",
-                  "blink.mojom.BackgroundFetchService",
                   "blink.mojom.CacheStorage",
                   "blink.mojom.ColorChooserFactory",
                   "blink.mojom.ContactsManager",
diff --git a/content/public/browser/sms_dialog.h b/content/public/browser/sms_dialog.h
index 464c75a0..87d1a2e 100644
--- a/content/public/browser/sms_dialog.h
+++ b/content/public/browser/sms_dialog.h
@@ -16,13 +16,25 @@
 // messages.
 class CONTENT_EXPORT SmsDialog {
  public:
+  // A Java counterpart will be generated for this enum.
+  // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.content_public.browser.sms
+  enum Event {
+    // User manually clicked the 'Confirm' button.
+    kConfirm = 0,
+    // User manually dismissed the SMS dialog.
+    kCancel = 1,
+    // User manually clicked 'Try again' button after a timeout.
+    kTimeout = 2,
+  };
+
+  using EventHandler = base::OnceCallback<void(Event)>;
+
   SmsDialog() = default;
   virtual ~SmsDialog() = default;
-  virtual void Open(content::RenderFrameHost* host,
-                    base::OnceClosure on_confirm,
-                    base::OnceClosure on_cancel) = 0;
+  virtual void Open(RenderFrameHost* host, EventHandler handler) = 0;
   virtual void Close() = 0;
   virtual void SmsReceived() = 0;
+  virtual void SmsTimeout() = 0;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(SmsDialog);
diff --git a/content/public/test/DEPS b/content/public/test/DEPS
index 40dcfe7..75250ec5 100644
--- a/content/public/test/DEPS
+++ b/content/public/test/DEPS
@@ -11,6 +11,7 @@
   "+services/audio/public/mojom",
   "+services/network",
   "+services/service_manager",
+  "+services/tracing/public/cpp",
   "+testing/android/native_test/native_browser_test_support.h",
   "+ui/ozone/public",
   "+ui/views/test",
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc
index 76c3dfa68..75b806a 100644
--- a/content/public/test/browser_test_base.cc
+++ b/content/public/test/browser_test_base.cc
@@ -62,6 +62,7 @@
 #include "services/network/public/mojom/network_service_test.mojom.h"
 #include "services/service_manager/embedder/switches.h"
 #include "services/service_manager/public/cpp/connector.h"
+#include "services/tracing/public/cpp/trace_startup.h"
 #include "ui/base/platform_window_defaults.h"
 #include "ui/compositor/compositor_switches.h"
 #include "ui/display/display_switches.h"
@@ -412,6 +413,7 @@
 
     StartBrowserThreadPool();
     BrowserTaskExecutor::PostFeatureListSetup();
+    tracing::InitTracingPostThreadPoolStartAndFeatureList();
     delegate->PostTaskSchedulerStart();
   }
 
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index f632b1e8c..195b893 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -180,16 +180,20 @@
     "media/audio/mojo_audio_output_ipc.h",
     "media/audio_decoder.cc",
     "media/audio_decoder.h",
+    "media/batching_media_log.cc",
+    "media/batching_media_log.h",
     "media/gpu/gpu_video_accelerator_factories_impl.cc",
     "media/gpu/gpu_video_accelerator_factories_impl.h",
+    "media/inspector_media_event_handler.cc",
+    "media/inspector_media_event_handler.h",
     "media/media_factory.cc",
     "media/media_factory.h",
     "media/media_permission_dispatcher.cc",
     "media/media_permission_dispatcher.h",
     "media/render_media_client.cc",
     "media/render_media_client.h",
-    "media/render_media_log.cc",
-    "media/render_media_log.h",
+    "media/render_media_event_handler.cc",
+    "media/render_media_event_handler.h",
     "media/renderer_webaudiodevice_impl.cc",
     "media/renderer_webaudiodevice_impl.h",
     "media/renderer_webmediaplayer_delegate.cc",
diff --git a/content/renderer/media/render_media_log.cc b/content/renderer/media/batching_media_log.cc
similarity index 83%
rename from content/renderer/media/render_media_log.cc
rename to content/renderer/media/batching_media_log.cc
index a47d0f1..3b593ca 100644
--- a/content/renderer/media/render_media_log.cc
+++ b/content/renderer/media/batching_media_log.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/renderer/media/render_media_log.h"
+#include "content/renderer/media/batching_media_log.h"
 
 #include <sstream>
 
@@ -12,7 +12,6 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/default_tick_clock.h"
-#include "content/common/view_messages.h"
 #include "content/public/common/content_client.h"
 #include "content/public/renderer/content_renderer_client.h"
 #include "content/public/renderer/render_thread.h"
@@ -36,22 +35,25 @@
 
 namespace content {
 
-RenderMediaLog::RenderMediaLog(
+BatchingMediaLog::BatchingMediaLog(
     const GURL& security_origin,
-    scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+    std::unique_ptr<EventHandler> event_handler)
     : security_origin_(security_origin),
       task_runner_(std::move(task_runner)),
+      event_handler_(std::move(event_handler)),
       tick_clock_(base::DefaultTickClock::GetInstance()),
       last_ipc_send_time_(tick_clock_->NowTicks()),
-      ipc_send_pending_(false) {
+      ipc_send_pending_(false),
+      weak_factory_(this) {
   DCHECK(RenderThread::Get())
-      << "RenderMediaLog must be constructed on the render thread";
+      << "BatchingMediaLog must be constructed on the render thread";
   // Pre-bind the WeakPtr on the right thread since we'll receive calls from
   // other threads and don't want races.
   weak_this_ = weak_factory_.GetWeakPtr();
 }
 
-RenderMediaLog::~RenderMediaLog() {
+BatchingMediaLog::~BatchingMediaLog() {
   DCHECK(task_runner_->BelongsToCurrentThread());
   // AddEvent() could be in-flight on some other thread.  Wait for it, and make
   // sure that nobody else calls it.
@@ -64,7 +66,7 @@
     SendQueuedMediaEvents();
 }
 
-void RenderMediaLog::AddEventLocked(
+void BatchingMediaLog::AddEventLocked(
     std::unique_ptr<media::MediaLogEvent> event) {
   Log(event.get());
 
@@ -109,7 +111,7 @@
   if (delay_for_next_ipc_send > base::TimeDelta()) {
     task_runner_->PostDelayedTask(
         FROM_HERE,
-        base::BindOnce(&RenderMediaLog::SendQueuedMediaEvents, weak_this_),
+        base::BindOnce(&BatchingMediaLog::SendQueuedMediaEvents, weak_this_),
         delay_for_next_ipc_send);
     return;
   }
@@ -121,10 +123,10 @@
   }
   task_runner_->PostTask(
       FROM_HERE,
-      base::BindOnce(&RenderMediaLog::SendQueuedMediaEvents, weak_this_));
+      base::BindOnce(&BatchingMediaLog::SendQueuedMediaEvents, weak_this_));
 }
 
-std::string RenderMediaLog::GetErrorMessageLocked() {
+std::string BatchingMediaLog::GetErrorMessageLocked() {
   // Keep message structure in sync with
   // HTMLMediaElement::BuildElementErrorMessage().
   std::stringstream result;
@@ -143,13 +145,13 @@
   return result.str();
 }
 
-void RenderMediaLog::RecordRapporWithSecurityOriginLocked(
+void BatchingMediaLog::RecordRapporWithSecurityOriginLocked(
     const std::string& metric) {
   if (!task_runner_->BelongsToCurrentThread()) {
     // Note that we don't post back to *Locked.
     task_runner_->PostTask(
         FROM_HERE,
-        base::BindOnce(&RenderMediaLog::RecordRapporWithSecurityOrigin,
+        base::BindOnce(&BatchingMediaLog::RecordRapporWithSecurityOrigin,
                        weak_this_, metric));
     return;
   }
@@ -157,7 +159,7 @@
   GetContentClient()->renderer()->RecordRapporURL(metric, security_origin_);
 }
 
-void RenderMediaLog::SendQueuedMediaEvents() {
+void BatchingMediaLog::SendQueuedMediaEvents() {
   DCHECK(task_runner_->BelongsToCurrentThread());
 
   std::vector<media::MediaLogEvent> events_to_send;
@@ -178,18 +180,14 @@
   if (events_to_send.empty())
     return;
 
-  RenderThread::Get()->Send(new ViewHostMsg_MediaLogEvents(events_to_send));
+  event_handler_->SendQueuedMediaEvents(std::move(events_to_send));
 }
 
-void RenderMediaLog::SetTickClockForTesting(const base::TickClock* tick_clock) {
+void BatchingMediaLog::SetTickClockForTesting(
+    const base::TickClock* tick_clock) {
   base::AutoLock auto_lock(lock_);
   tick_clock_ = tick_clock;
   last_ipc_send_time_ = tick_clock_->NowTicks();
 }
 
-void RenderMediaLog::SetTaskRunnerForTesting(
-    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
-  task_runner_ = task_runner;
-}
-
 }  // namespace content
diff --git a/content/renderer/media/render_media_log.h b/content/renderer/media/batching_media_log.h
similarity index 69%
rename from content/renderer/media/render_media_log.h
rename to content/renderer/media/batching_media_log.h
index 87d24161..6574934 100644
--- a/content/renderer/media/render_media_log.h
+++ b/content/renderer/media/batching_media_log.h
@@ -2,10 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_RENDERER_MEDIA_RENDER_MEDIA_LOG_H_
-#define CONTENT_RENDERER_MEDIA_RENDER_MEDIA_LOG_H_
+#ifndef CONTENT_RENDERER_MEDIA_BATCHING_MEDIA_LOG_H_
+#define CONTENT_RENDERER_MEDIA_BATCHING_MEDIA_LOG_H_
 
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/macros.h"
@@ -22,26 +23,27 @@
 
 namespace content {
 
-// RenderMediaLog is an implementation of MediaLog that forwards events to the
-// browser process, throttling as necessary.
-//
-// It also caches the last error events to support renderer-side reporting to
-// entities like HTMLMediaElement and devtools console.
-//
-// To minimize the number of events sent over the wire, only the latest event
-// added is sent for high frequency events (e.g., BUFFERED_EXTENTS_CHANGED).
+// BatchingMediaLog is an implementation of MediaLog that sends messages
+// grouped together in order to reduce IPC pressure.
+// In order to subclass it, a subclass of the BatchingMediaLog::EventHandler
+// should implement behavior when recieving a group of messages.
 //
 // It must be constructed on the render thread.
-class CONTENT_EXPORT RenderMediaLog : public media::MediaLog {
+class CONTENT_EXPORT BatchingMediaLog : public media::MediaLog {
  public:
-  RenderMediaLog(const GURL& security_origin,
-                 scoped_refptr<base::SingleThreadTaskRunner> task_runner);
-  ~RenderMediaLog() override;
+  class EventHandler {
+   public:
+    virtual ~EventHandler() = default;
+    virtual void SendQueuedMediaEvents(std::vector<media::MediaLogEvent>) = 0;
+  };
+
+  BatchingMediaLog(const GURL& security_origin,
+                   scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+                   std::unique_ptr<EventHandler> impl);
+  ~BatchingMediaLog() override;
 
   // Will reset |last_ipc_send_time_| with the value of NowTicks().
   void SetTickClockForTesting(const base::TickClock* tick_clock);
-  void SetTaskRunnerForTesting(
-      const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
 
  protected:
   // MediaLog implementation.
@@ -59,6 +61,9 @@
 
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
+  // impl for sending queued events.
+  std::unique_ptr<EventHandler> event_handler_;
+
   // |lock_| protects access to all of the following member variables.  It
   // allows any render process thread to AddEvent(), while preserving their
   // sequence for throttled send on |task_runner_| and coherent retrieval by
@@ -86,12 +91,12 @@
   // Holds a copy of the most recent PIPELINE_ERROR, if any.
   std::unique_ptr<media::MediaLogEvent> last_pipeline_error_;
 
-  base::WeakPtr<RenderMediaLog> weak_this_;
-  base::WeakPtrFactory<RenderMediaLog> weak_factory_{this};
+  base::WeakPtr<BatchingMediaLog> weak_this_;
+  base::WeakPtrFactory<BatchingMediaLog> weak_factory_;
 
-  DISALLOW_COPY_AND_ASSIGN(RenderMediaLog);
+  DISALLOW_COPY_AND_ASSIGN(BatchingMediaLog);
 };
 
 }  // namespace content
 
-#endif  // CONTENT_RENDERER_MEDIA_RENDER_MEDIA_LOG_H_
+#endif  // CONTENT_RENDERER_MEDIA_BATCHING_MEDIA_LOG_H_
diff --git a/content/renderer/media/render_media_log_unittest.cc b/content/renderer/media/batching_media_log_unittest.cc
similarity index 67%
rename from content/renderer/media/render_media_log_unittest.cc
rename to content/renderer/media/batching_media_log_unittest.cc
index ae362c89..2b36faa 100644
--- a/content/renderer/media/render_media_log_unittest.cc
+++ b/content/renderer/media/batching_media_log_unittest.cc
@@ -2,33 +2,41 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <tuple>
-
+#include "content/renderer/media/batching_media_log.h"
 #include "base/macros.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "base/test/test_mock_time_task_runner.h"
 #include "content/common/view_messages.h"
 #include "content/public/test/mock_render_thread.h"
-#include "content/renderer/media/render_media_log.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 
 namespace content {
 
-class RenderMediaLogTest : public testing::Test {
+class BatchingMediaLogTest;
+
+class TestEventHandler : public BatchingMediaLog::EventHandler {
  public:
-  RenderMediaLogTest()
-      : log_(GURL("http://foo.com"),
-             blink::scheduler::GetSingleThreadTaskRunnerForTesting()),
-        task_runner_(new base::TestMockTimeTaskRunner()) {
+  explicit TestEventHandler(BatchingMediaLogTest* test_cls)
+      : test_cls_(test_cls) {}
+  void SendQueuedMediaEvents(std::vector<media::MediaLogEvent> events) override;
+
+ private:
+  BatchingMediaLogTest* test_cls_;
+};
+
+class BatchingMediaLogTest : public testing::Test {
+ public:
+  BatchingMediaLogTest()
+      : task_runner_(new base::TestMockTimeTaskRunner()),
+        log_(GURL("http://foo.com"),
+             task_runner_,
+             std::make_unique<TestEventHandler>(this)) {
     log_.SetTickClockForTesting(&tick_clock_);
-    log_.SetTaskRunnerForTesting(task_runner_);
   }
 
-  ~RenderMediaLogTest() override {
-    task_runner_->ClearPendingTasks();
-  }
+  ~BatchingMediaLogTest() override { task_runner_->ClearPendingTasks(); }
 
   void AddEvent(media::MediaLogEvent::Type type) {
     log_.AddEvent(log_.CreateEvent(type));
@@ -41,32 +49,36 @@
     task_runner_->FastForwardBy(delta);
   }
 
-  int message_count() { return render_thread_.sink().message_count(); }
+  int message_count() { return add_events_count_; }
 
   std::vector<media::MediaLogEvent> GetMediaLogEvents() {
-    const IPC::Message* msg = render_thread_.sink().GetFirstMessageMatching(
-        ViewHostMsg_MediaLogEvents::ID);
-    if (!msg) {
-      ADD_FAILURE() << "Did not find ViewHostMsg_MediaLogEvents IPC message";
-      return std::vector<media::MediaLogEvent>();
-    }
-
-    std::tuple<std::vector<media::MediaLogEvent>> events;
-    ViewHostMsg_MediaLogEvents::Read(msg, &events);
-    return std::get<0>(events);
+    std::vector<media::MediaLogEvent> return_events = std::move(events_);
+    return return_events;
   }
 
  private:
+  friend class TestEventHandler;
+  void AddEventsForTesting(std::vector<media::MediaLogEvent> events) {
+    events_.insert(events_.end(), events.begin(), events.end());
+    add_events_count_++;
+  }
+  int add_events_count_ = 0;
+  std::vector<media::MediaLogEvent> events_;
   base::test::ScopedTaskEnvironment task_environment_;
   MockRenderThread render_thread_;
   base::SimpleTestTickClock tick_clock_;
-  RenderMediaLog log_;
   scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
+  BatchingMediaLog log_;
 
-  DISALLOW_COPY_AND_ASSIGN(RenderMediaLogTest);
+  DISALLOW_COPY_AND_ASSIGN(BatchingMediaLogTest);
 };
 
-TEST_F(RenderMediaLogTest, ThrottleSendingEvents) {
+void TestEventHandler::SendQueuedMediaEvents(
+    std::vector<media::MediaLogEvent> events) {
+  test_cls_->AddEventsForTesting(events);
+}
+
+TEST_F(BatchingMediaLogTest, ThrottleSendingEvents) {
   AddEvent(media::MediaLogEvent::LOAD);
   EXPECT_EQ(0, message_count());
 
@@ -90,7 +102,7 @@
   EXPECT_EQ(1, message_count());
 }
 
-TEST_F(RenderMediaLogTest, EventSentWithoutDelayAfterIpcInterval) {
+TEST_F(BatchingMediaLogTest, EventSentWithoutDelayAfterIpcInterval) {
   AddEvent(media::MediaLogEvent::LOAD);
   Advance(base::TimeDelta::FromMilliseconds(1000));
   EXPECT_EQ(1, message_count());
@@ -102,7 +114,7 @@
   EXPECT_EQ(2, message_count());
 }
 
-TEST_F(RenderMediaLogTest, DurationChanged) {
+TEST_F(BatchingMediaLogTest, DurationChanged) {
   AddEvent(media::MediaLogEvent::LOAD);
   AddEvent(media::MediaLogEvent::SEEK);
 
diff --git a/content/renderer/media/inspector_media_event_handler.cc b/content/renderer/media/inspector_media_event_handler.cc
new file mode 100644
index 0000000..700146cd
--- /dev/null
+++ b/content/renderer/media/inspector_media_event_handler.cc
@@ -0,0 +1,72 @@
+// Copyright 2019 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 "content/renderer/media/inspector_media_event_handler.h"
+
+#include <string>
+#include <utility>
+
+#include "base/json/json_writer.h"
+
+namespace content {
+
+namespace {
+
+blink::WebString ToString(const base::Value& value) {
+  if (value.is_string()) {
+    return blink::WebString::FromUTF8(value.GetString());
+  }
+  std::string output_str;
+  base::JSONWriter::Write(value, &output_str);
+  return blink::WebString::FromUTF8(output_str);
+}
+
+}  // namespace
+
+InspectorMediaEventHandler::InspectorMediaEventHandler(
+    blink::MediaInspectorContext* inspector_context)
+    : inspector_context_(inspector_context),
+      player_id_(inspector_context_->CreatePlayer()) {}
+
+// TODO(tmathmeyer) It would be wonderful if the definition for MediaLogEvent
+// and InspectorPlayerEvent / InspectorPlayerProperty could be unified so that
+// this method is no longer needed. Refactor MediaLogEvent at some point.
+void InspectorMediaEventHandler::SendQueuedMediaEvents(
+    std::vector<media::MediaLogEvent> events_to_send) {
+  blink::InspectorPlayerEvents events;
+  blink::InspectorPlayerProperties properties;
+
+  for (media::MediaLogEvent event : events_to_send) {
+    if (event.type == media::MediaLogEvent::PROPERTY_CHANGE) {
+      for (auto&& itr : event.params.DictItems()) {
+        blink::InspectorPlayerProperty prop = {
+            blink::WebString::FromUTF8(itr.first), ToString(itr.second)};
+        properties.emplace_back(prop);
+      }
+    } else {
+      blink::InspectorPlayerEvent::InspectorPlayerEventType event_type =
+          blink::InspectorPlayerEvent::SYSTEM_EVENT;
+
+      if (event.type == media::MediaLogEvent::MEDIA_ERROR_LOG_ENTRY ||
+          event.type == media::MediaLogEvent::MEDIA_WARNING_LOG_ENTRY ||
+          event.type == media::MediaLogEvent::MEDIA_INFO_LOG_ENTRY ||
+          event.type == media::MediaLogEvent::MEDIA_DEBUG_LOG_ENTRY) {
+        event_type = blink::InspectorPlayerEvent::MESSAGE_EVENT;
+      }
+      for (auto&& itr : event.params.DictItems()) {
+        blink::InspectorPlayerEvent ev = {event_type, event.time,
+                                          blink::WebString::FromUTF8(itr.first),
+                                          ToString(itr.second)};
+        events.emplace_back(ev);
+      }
+    }
+  }
+  if (!events.empty())
+    inspector_context_->NotifyPlayerEvents(player_id_, events);
+
+  if (!properties.empty())
+    inspector_context_->SetPlayerProperties(player_id_, properties);
+}
+
+}  // namespace content
diff --git a/content/renderer/media/inspector_media_event_handler.h b/content/renderer/media/inspector_media_event_handler.h
new file mode 100644
index 0000000..95b7cb7d6
--- /dev/null
+++ b/content/renderer/media/inspector_media_event_handler.h
@@ -0,0 +1,32 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_MEDIA_INSPECTOR_MEDIA_EVENT_HANDLER_H_
+#define CONTENT_RENDERER_MEDIA_INSPECTOR_MEDIA_EVENT_HANDLER_H_
+
+#include <vector>
+
+#include "content/renderer/media/batching_media_log.h"
+#include "third_party/blink/public/web/web_media_inspector.h"
+
+namespace content {
+
+// InspectorMediaEventHandler is an implementation of
+// BatchingMediaLog::EventHandler that reformats events and sends them to
+// the devtools inspector.
+class CONTENT_EXPORT InspectorMediaEventHandler
+    : public BatchingMediaLog::EventHandler {
+ public:
+  explicit InspectorMediaEventHandler(blink::MediaInspectorContext*);
+  ~InspectorMediaEventHandler() override = default;
+  void SendQueuedMediaEvents(std::vector<media::MediaLogEvent>) override;
+
+ private:
+  blink::MediaInspectorContext* inspector_context_;
+  blink::WebString player_id_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_MEDIA_INSPECTOR_MEDIA_EVENT_HANDLER_H_
diff --git a/content/renderer/media/inspector_media_event_handler_unittest.cc b/content/renderer/media/inspector_media_event_handler_unittest.cc
new file mode 100644
index 0000000..2564f99
--- /dev/null
+++ b/content/renderer/media/inspector_media_event_handler_unittest.cc
@@ -0,0 +1,206 @@
+// Copyright 2019 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 <memory>
+#include <string>
+#include <utility>
+
+#include "content/renderer/media/inspector_media_event_handler.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/web/web_media_inspector.h"
+
+using ::testing::_;
+
+namespace content {
+
+class MockMediaInspectorContext : public blink::MediaInspectorContext {
+ public:
+  MockMediaInspectorContext() = default;
+  virtual ~MockMediaInspectorContext() = default;
+
+  blink::WebString CreatePlayer() override { return "TestPlayer"; }
+
+  void NotifyPlayerEvents(blink::WebString id,
+                          blink::InspectorPlayerEvents events) override {
+    MockNotifyPlayerEvents(events);
+  }
+
+  void SetPlayerProperties(blink::WebString id,
+                           blink::InspectorPlayerProperties props) override {
+    MockSetPlayerProperties(props);
+  }
+
+  MOCK_METHOD1(MockNotifyPlayerEvents, void(blink::InspectorPlayerEvents));
+  MOCK_METHOD1(MockSetPlayerProperties, void(blink::InspectorPlayerProperties));
+};
+
+class InspectorMediaEventHandlerTest : public testing::Test {
+ public:
+  InspectorMediaEventHandlerTest() {
+    mock_context_ = std::make_unique<MockMediaInspectorContext>();
+    handler_ =
+        std::make_unique<InspectorMediaEventHandler>(mock_context_.get());
+  }
+
+ protected:
+  std::unique_ptr<InspectorMediaEventHandler> handler_;
+  std::unique_ptr<MockMediaInspectorContext> mock_context_;
+
+  media::MediaLogEvent CreateEvent(media::MediaLogEvent::Type type) {
+    media::MediaLogEvent event;
+    event.id = 0;
+    event.type = type;
+    event.time = base::TimeTicks();
+    return event;
+  }
+
+  media::MediaLogEvent CreatePropChangeEvent(
+      std::vector<std::pair<std::string, std::string>> props) {
+    auto event = CreateEvent(media::MediaLogEvent::PROPERTY_CHANGE);
+    for (auto p : props) {
+      event.params.SetString(std::get<0>(p), std::get<1>(p));
+    }
+    return event;
+  }
+
+  media::MediaLogEvent CreateLogEvent(std::string msg) {
+    auto event = CreateEvent(media::MediaLogEvent::MEDIA_WARNING_LOG_ENTRY);
+    event.params.SetString("warning", msg);
+    return event;
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(InspectorMediaEventHandlerTest);
+};
+
+bool operator==(const blink::InspectorPlayerProperty& lhs,
+                const blink::InspectorPlayerProperty& rhs) {
+  return lhs.name == rhs.name && lhs.value == rhs.value;
+}
+
+bool operator!=(const blink::InspectorPlayerProperty& lhs,
+                const blink::InspectorPlayerProperty& rhs) {
+  return !(lhs == rhs);
+}
+
+bool operator==(const blink::InspectorPlayerEvent& lhs,
+                const blink::InspectorPlayerEvent& rhs) {
+  return lhs.type == rhs.type && lhs.timestamp == rhs.timestamp &&
+         lhs.key == rhs.key && lhs.value == rhs.value;
+}
+
+bool operator!=(const blink::InspectorPlayerEvent& lhs,
+                const blink::InspectorPlayerEvent& rhs) {
+  return !(lhs == rhs);
+}
+
+MATCHER_P(PropertiesEqualTo, props, "") {
+  if (props.size() != arg.size())
+    return false;
+  for (size_t i = 0; i < props.size(); i++)
+    if (props[i] != arg[i])
+      return false;
+  return true;
+}
+
+MATCHER_P(EventsEqualTo, events, "") {
+  if (events.size() != arg.size())
+    return false;
+  for (size_t i = 0; i < events.size(); i++)
+    if (events[i] != arg[i])
+      return false;
+  return true;
+}
+
+TEST_F(InspectorMediaEventHandlerTest, ConvertsProperties) {
+  std::vector<media::MediaLogEvent> events = {
+      CreatePropChangeEvent({{"test_key", "test_value"}})};
+
+  blink::InspectorPlayerProperties expected;
+  blink::InspectorPlayerProperty prop = {
+      blink::WebString::FromUTF8("test_key"),
+      blink::WebString::FromUTF8("test_value")};
+  expected.emplace_back(prop);
+  EXPECT_CALL(*mock_context_,
+              MockSetPlayerProperties(PropertiesEqualTo(expected)))
+      .Times(1);
+  EXPECT_CALL(*mock_context_, MockNotifyPlayerEvents(_)).Times(0);
+
+  handler_->SendQueuedMediaEvents(events);
+}
+
+TEST_F(InspectorMediaEventHandlerTest, SplitsDoubleProperties) {
+  std::vector<media::MediaLogEvent> events = {
+      CreatePropChangeEvent({{"test_key", "test_value"}, {"foo", "bar"}})};
+
+  blink::InspectorPlayerProperties expected;
+  blink::InspectorPlayerProperty prop_test = {
+      blink::WebString::FromUTF8("test_key"),
+      blink::WebString::FromUTF8("test_value")};
+  blink::InspectorPlayerProperty prop_foo = {blink::WebString::FromUTF8("foo"),
+                                             blink::WebString::FromUTF8("bar")};
+  expected.emplace_back(prop_foo);
+  expected.emplace_back(prop_test);
+  EXPECT_CALL(*mock_context_,
+              MockSetPlayerProperties(PropertiesEqualTo(expected)))
+      .Times(1);
+  EXPECT_CALL(*mock_context_, MockNotifyPlayerEvents(_)).Times(0);
+
+  handler_->SendQueuedMediaEvents(events);
+}
+
+TEST_F(InspectorMediaEventHandlerTest, ConvertsMessageEvent) {
+  std::vector<media::MediaLogEvent> events = {
+      CreateLogEvent("Has Anyone Really Been Far Even as Decided to Use Even "
+                     "Go Want to do Look More Like?")};
+
+  blink::InspectorPlayerEvents expected;
+  blink::InspectorPlayerEvent e = {
+      blink::InspectorPlayerEvent::MESSAGE_EVENT, base::TimeTicks(),
+      blink::WebString::FromUTF8("warning"),
+      blink::WebString::FromUTF8("Has Anyone Really Been Far Even as Decided "
+                                 "to Use Even Go Want to do Look More Like?")};
+  expected.emplace_back(e);
+
+  EXPECT_CALL(*mock_context_, MockSetPlayerProperties(_)).Times(0);
+  EXPECT_CALL(*mock_context_, MockNotifyPlayerEvents(EventsEqualTo(expected)))
+      .Times(1);
+
+  handler_->SendQueuedMediaEvents(events);
+}
+
+TEST_F(InspectorMediaEventHandlerTest, ConvertsEventsAndProperties) {
+  std::vector<media::MediaLogEvent> events = {
+      CreateLogEvent("100% medically accurate"),
+      CreatePropChangeEvent(
+          {{"free_puppies", "all_taken"}, {"illuminati", "confirmed"}})};
+
+  blink::InspectorPlayerEvents expected_events;
+  blink::InspectorPlayerEvent e = {
+      blink::InspectorPlayerEvent::MESSAGE_EVENT, base::TimeTicks(),
+      blink::WebString::FromUTF8("warning"),
+      blink::WebString::FromUTF8("100% medically accurate")};
+  expected_events.emplace_back(e);
+
+  blink::InspectorPlayerProperties expected_properties;
+  blink::InspectorPlayerProperty puppies = {
+      blink::WebString::FromUTF8("free_puppies"),
+      blink::WebString::FromUTF8("all_taken")};
+  blink::InspectorPlayerProperty illumanati = {
+      blink::WebString::FromUTF8("illuminati"),
+      blink::WebString::FromUTF8("confirmed")};
+  expected_properties.emplace_back(puppies);
+  expected_properties.emplace_back(illumanati);
+
+  EXPECT_CALL(*mock_context_,
+              MockSetPlayerProperties(PropertiesEqualTo(expected_properties)))
+      .Times(1);
+  EXPECT_CALL(*mock_context_,
+              MockNotifyPlayerEvents(EventsEqualTo(expected_events)))
+      .Times(1);
+
+  handler_->SendQueuedMediaEvents(events);
+}
+
+}  // namespace content
diff --git a/content/renderer/media/media_factory.cc b/content/renderer/media/media_factory.cc
index 615b3b7..69b8d78 100644
--- a/content/renderer/media/media_factory.cc
+++ b/content/renderer/media/media_factory.cc
@@ -19,7 +19,9 @@
 #include "content/public/common/content_client.h"
 #include "content/public/renderer/content_renderer_client.h"
 #include "content/renderer/media/audio/audio_device_factory.h"
-#include "content/renderer/media/render_media_log.h"
+#include "content/renderer/media/batching_media_log.h"
+#include "content/renderer/media/inspector_media_event_handler.h"
+#include "content/renderer/media/render_media_event_handler.h"
 #include "content/renderer/media/renderer_webmediaplayer_delegate.h"
 #include "content/renderer/render_frame_impl.h"
 #include "content/renderer/render_thread_impl.h"
@@ -267,6 +269,7 @@
 blink::WebMediaPlayer* MediaFactory::CreateMediaPlayer(
     const blink::WebMediaPlayerSource& source,
     blink::WebMediaPlayerClient* client,
+    blink::MediaInspectorContext* inspector_context,
     blink::WebMediaPlayerEncryptedMediaClient* encrypted_client,
     blink::WebContentDecryptionModule* initial_cdm,
     const blink::WebString& sink_id,
@@ -279,7 +282,8 @@
       blink::GetWebMediaStreamFromWebMediaPlayerSource(source);
   if (!web_stream.IsNull())
     return CreateWebMediaPlayerForMediaStream(
-        client, sink_id, security_origin, web_frame, layer_tree_view, settings);
+        client, inspector_context, sink_id, security_origin, web_frame,
+        layer_tree_view, settings);
 
   // If |source| was not a MediaStream, it must be a URL.
   // TODO(guidou): Fix this when support for other srcObject types is added.
@@ -317,11 +321,20 @@
           media::kMemoryPressureBasedSourceBufferGC,
           "enable_instant_source_buffer_gc", false);
 
+  std::unique_ptr<BatchingMediaLog::EventHandler> event_handler;
+  if (base::FeatureList::IsEnabled(media::kMediaInspectorLogging)) {
+    event_handler =
+        std::make_unique<InspectorMediaEventHandler>(inspector_context);
+  } else {
+    event_handler = std::make_unique<RenderMediaEventHandler>();
+  }
+
   // This must be created for every new WebMediaPlayer, each instance generates
   // a new player id which is used to collate logs on the browser side.
-  std::unique_ptr<media::MediaLog> media_log(new RenderMediaLog(
+  auto media_log = std::make_unique<BatchingMediaLog>(
       url::Origin(security_origin).GetURL(),
-      render_frame_->GetTaskRunner(blink::TaskType::kInternalMedia)));
+      render_frame_->GetTaskRunner(blink::TaskType::kInternalMedia),
+      std::move(event_handler));
 
   base::WeakPtr<media::MediaObserver> media_observer;
 
@@ -535,6 +548,7 @@
 
 blink::WebMediaPlayer* MediaFactory::CreateWebMediaPlayerForMediaStream(
     blink::WebMediaPlayerClient* client,
+    blink::MediaInspectorContext* inspector_context,
     const blink::WebString& sink_id,
     const blink::WebSecurityOrigin& security_origin,
     blink::WebLocalFrame* frame,
@@ -548,11 +562,24 @@
       CreateSubmitter(&video_frame_compositor_task_runner, settings);
 
   DCHECK(layer_tree_view);
+
+  std::unique_ptr<BatchingMediaLog::EventHandler> event_handler;
+  if (base::FeatureList::IsEnabled(media::kMediaInspectorLogging)) {
+    event_handler =
+        std::make_unique<InspectorMediaEventHandler>(inspector_context);
+  } else {
+    event_handler = std::make_unique<RenderMediaEventHandler>();
+  }
+
+  // This must be created for every new WebMediaPlayer, each instance generates
+  // a new player id which is used to collate logs on the browser side.
+  auto media_log = std::make_unique<BatchingMediaLog>(
+      url::Origin(security_origin).GetURL(),
+      render_frame_->GetTaskRunner(blink::TaskType::kInternalMedia),
+      std::move(event_handler));
+
   return new blink::WebMediaPlayerMS(
-      frame, client, GetWebMediaPlayerDelegate(),
-      std::make_unique<RenderMediaLog>(
-          url::Origin(security_origin).GetURL(),
-          render_frame_->GetTaskRunner(blink::TaskType::kInternalMedia)),
+      frame, client, GetWebMediaPlayerDelegate(), std::move(media_log),
       CreateMediaStreamRendererFactory(),
       render_frame_->GetTaskRunner(blink::TaskType::kInternalMedia),
       render_thread->GetIOTaskRunner(), video_frame_compositor_task_runner,
diff --git a/content/renderer/media/media_factory.h b/content/renderer/media/media_factory.h
index b746680d..946c034 100644
--- a/content/renderer/media/media_factory.h
+++ b/content/renderer/media/media_factory.h
@@ -20,6 +20,7 @@
 #include "third_party/blink/public/platform/web_security_origin.h"
 #include "third_party/blink/public/platform/web_set_sink_id_callbacks.h"
 #include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/public/web/web_media_inspector.h"
 
 #if BUILDFLAG(ENABLE_MOJO_MEDIA)
 #include "media/mojo/mojom/interface_factory.mojom.h"  // nogncheck
@@ -104,6 +105,7 @@
   blink::WebMediaPlayer* CreateMediaPlayer(
       const blink::WebMediaPlayerSource& source,
       blink::WebMediaPlayerClient* client,
+      blink::MediaInspectorContext* inspector_context,
       blink::WebMediaPlayerEncryptedMediaClient* encrypted_client,
       blink::WebContentDecryptionModule* initial_cdm,
       const blink::WebString& sink_id,
@@ -126,6 +128,7 @@
 
   blink::WebMediaPlayer* CreateWebMediaPlayerForMediaStream(
       blink::WebMediaPlayerClient* client,
+      blink::MediaInspectorContext* inspector_context,
       const blink::WebString& sink_id,
       const blink::WebSecurityOrigin& security_origin,
       blink::WebLocalFrame* frame,
diff --git a/content/renderer/media/render_media_event_handler.cc b/content/renderer/media/render_media_event_handler.cc
new file mode 100644
index 0000000..ff3c9de
--- /dev/null
+++ b/content/renderer/media/render_media_event_handler.cc
@@ -0,0 +1,16 @@
+// Copyright 2019 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 "content/renderer/media/render_media_event_handler.h"
+#include "content/common/view_messages.h"
+#include "content/public/renderer/render_thread.h"
+
+namespace content {
+
+void RenderMediaEventHandler::SendQueuedMediaEvents(
+    std::vector<media::MediaLogEvent> events_to_send) {
+  RenderThread::Get()->Send(new ViewHostMsg_MediaLogEvents(events_to_send));
+}
+
+}  // namespace content
diff --git a/content/renderer/media/render_media_event_handler.h b/content/renderer/media/render_media_event_handler.h
new file mode 100644
index 0000000..b95af32
--- /dev/null
+++ b/content/renderer/media/render_media_event_handler.h
@@ -0,0 +1,26 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_MEDIA_RENDER_MEDIA_EVENT_HANDLER_H_
+#define CONTENT_RENDERER_MEDIA_RENDER_MEDIA_EVENT_HANDLER_H_
+
+#include <vector>
+
+#include "content/renderer/media/batching_media_log.h"
+
+namespace content {
+
+// RenderMediaEventHandler is an implementation of
+// BatchingMediaLog::EventHandler that forwards events to the browser process.
+class CONTENT_EXPORT RenderMediaEventHandler
+    : public BatchingMediaLog::EventHandler {
+ public:
+  RenderMediaEventHandler() = default;
+  ~RenderMediaEventHandler() override = default;
+  void SendQueuedMediaEvents(std::vector<media::MediaLogEvent>) override;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_MEDIA_RENDER_MEDIA_EVENT_HANDLER_H_
diff --git a/content/renderer/media/webrtc/rtc_video_decoder_adapter.cc b/content/renderer/media/webrtc/rtc_video_decoder_adapter.cc
index 8c25a0d8..12ca71c 100644
--- a/content/renderer/media/webrtc/rtc_video_decoder_adapter.cc
+++ b/content/renderer/media/webrtc/rtc_video_decoder_adapter.cc
@@ -23,7 +23,6 @@
 #include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
-#include "content/renderer/media/render_media_log.h"
 #include "media/base/media_log.h"
 #include "media/base/media_switches.h"
 #include "media/base/media_util.h"
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 047532d..41ecfe8 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -4172,15 +4172,16 @@
 blink::WebMediaPlayer* RenderFrameImpl::CreateMediaPlayer(
     const blink::WebMediaPlayerSource& source,
     WebMediaPlayerClient* client,
+    blink::MediaInspectorContext* inspector_context,
     WebMediaPlayerEncryptedMediaClient* encrypted_client,
     WebContentDecryptionModule* initial_cdm,
     const blink::WebString& sink_id,
     blink::WebLayerTreeView* layer_tree_view) {
   const cc::LayerTreeSettings& settings =
       GetLocalRootRenderWidget()->layer_tree_view()->GetLayerTreeSettings();
-  return media_factory_.CreateMediaPlayer(source, client, encrypted_client,
-                                          initial_cdm, sink_id, layer_tree_view,
-                                          settings);
+  return media_factory_.CreateMediaPlayer(source, client, inspector_context,
+                                          encrypted_client, initial_cdm,
+                                          sink_id, layer_tree_view, settings);
 }
 
 std::unique_ptr<blink::WebContentSettingsClient>
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index b331bbaa..48a2648 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -675,6 +675,7 @@
   blink::WebMediaPlayer* CreateMediaPlayer(
       const blink::WebMediaPlayerSource& source,
       blink::WebMediaPlayerClient* client,
+      blink::MediaInspectorContext* inspector_context,
       blink::WebMediaPlayerEncryptedMediaClient* encrypted_client,
       blink::WebContentDecryptionModule* initial_cdm,
       const blink::WebString& sink_id,
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 5cb02a6..1d95e306 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -15,6 +15,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
+#include "base/debug/crash_logging.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/macros.h"
@@ -275,6 +276,35 @@
   histogram->Add(sample);
 }
 
+void AddCrashKey(v8::CrashKeyId id, const std::string& value) {
+  namespace bd = base::debug;
+  switch (id) {
+    case v8::CrashKeyId::kIsolateAddress:
+      static bd::CrashKeyString* isolate_address = bd::AllocateCrashKeyString(
+          "v8_isolate_address", bd::CrashKeySize::Size32);
+      bd::SetCrashKeyString(isolate_address, value);
+      break;
+    case v8::CrashKeyId::kReadonlySpaceFirstPageAddress:
+      static bd::CrashKeyString* ro_space_firstpage_address =
+          bd::AllocateCrashKeyString("v8_ro_space_firstpage_address",
+                                     bd::CrashKeySize::Size32);
+      bd::SetCrashKeyString(ro_space_firstpage_address, value);
+      break;
+    case v8::CrashKeyId::kMapSpaceFirstPageAddress:
+      static bd::CrashKeyString* map_space_firstpage_address =
+          bd::AllocateCrashKeyString("v8_map_space_firstpage_address",
+                                     bd::CrashKeySize::Size32);
+      bd::SetCrashKeyString(map_space_firstpage_address, value);
+      break;
+    case v8::CrashKeyId::kCodeSpaceFirstPageAddress:
+      static bd::CrashKeyString* code_space_firstpage_address =
+          bd::AllocateCrashKeyString("v8_code_space_firstpage_address",
+                                     bd::CrashKeySize::Size32);
+      bd::SetCrashKeyString(code_space_firstpage_address, value);
+      break;
+  }
+}
+
 class FrameFactoryImpl : public mojom::FrameFactory {
  public:
   explicit FrameFactoryImpl(const service_manager::BindSourceInfo& source_info)
@@ -1174,6 +1204,7 @@
   v8::Isolate* isolate = blink::MainThreadIsolate();
   isolate->SetCreateHistogramFunction(CreateHistogram);
   isolate->SetAddHistogramSampleFunction(AddHistogramSample);
+  isolate->SetAddCrashKeyCallback(AddCrashKey);
 
   main_thread_compositor_task_runner_ =
       main_thread_scheduler_->CompositorTaskRunner();
diff --git a/content/renderer/service_worker/embedded_worker_instance_client_impl.cc b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
index b1016c7..061b18a 100644
--- a/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
+++ b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
@@ -63,6 +63,10 @@
   service_manager::mojom::InterfaceProviderPtrInfo interface_provider =
       std::move(params->provider_info->interface_provider);
 
+  mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>
+      browser_interface_broker =
+          std::move(params->provider_info->browser_interface_broker);
+
   service_worker_context_client_ = std::make_unique<ServiceWorkerContextClient>(
       params->service_worker_version_id, params->scope, params->script_url,
       !params->installed_scripts_info.is_null(),
@@ -104,7 +108,7 @@
       service_worker_context_client_.get(),
       std::move(installed_scripts_manager_params),
       params->content_settings_proxy.PassHandle(), cache_storage.PassHandle(),
-      interface_provider.PassHandle());
+      interface_provider.PassHandle(), browser_interface_broker.PassPipe());
   service_worker_context_client_->StartWorkerContextOnInitiatorThread(
       std::move(worker), start_data);
 }
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index ab929bad..3e7c6a4 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1917,7 +1917,8 @@
     "../renderer/media/audio/mock_audio_device_factory.h",
     "../renderer/media/audio/mojo_audio_input_ipc_unittest.cc",
     "../renderer/media/audio/mojo_audio_output_ipc_unittest.cc",
-    "../renderer/media/render_media_log_unittest.cc",
+    "../renderer/media/batching_media_log_unittest.cc",
+    "../renderer/media/inspector_media_event_handler_unittest.cc",
     "../renderer/media/renderer_webaudiodevice_impl_unittest.cc",
     "../renderer/media/webrtc/fake_rtc_rtp_transceiver.cc",
     "../renderer/media/webrtc/fake_rtc_rtp_transceiver.h",
diff --git a/content/test/gpu/gpu_tests/gpu_integration_test.py b/content/test/gpu/gpu_tests/gpu_integration_test.py
index 167d2ba5..dbd07d3 100644
--- a/content/test/gpu/gpu_tests/gpu_integration_test.py
+++ b/content/test/gpu/gpu_tests/gpu_integration_test.py
@@ -157,9 +157,13 @@
   @classmethod
   def _RestartBrowser(cls, reason):
     logging.warning('Restarting browser due to '+ reason)
-    cls.StopBrowser()
-    cls.SetBrowserOptions(cls._finder_options)
-    cls.StartBrowser()
+    if cls.browser is None:
+      cls.SetBrowserOptions(cls._original_finder_options)
+      cls.StartBrowser()
+    else:
+      cls.StopBrowser()
+      cls.SetBrowserOptions(cls._finder_options)
+      cls.StartBrowser()
 
   def _RunGpuTest(self, url, test_name, *args):
     expected_results, should_retry_on_failure = (
@@ -323,6 +327,14 @@
   @classmethod
   def _EnsureTabIsAvailable(cls):
     try:
+      # If there is no browser, the previous run may have failed an additional
+      # time, while trying to recover from an initial failure.
+      # ChromeBrowserBackend._GetDevToolsClient can cause this if there is a
+      # crash during browser startup. If this has occurred, reset the options,
+      # and attempt to bring up a browser for this test. Otherwise failures
+      # begin to cascade between tests. https://crbug.com/993379
+      if cls.browser is None:
+        cls._RestartBrowser('failure in previous shutdown')
       cls.tab = cls.browser.tabs[0]
     except Exception:
       # restart the browser to make sure a failure in a test doesn't
diff --git a/extensions/BUILD.gn b/extensions/BUILD.gn
index 02009fbb..a22ed5c 100644
--- a/extensions/BUILD.gn
+++ b/extensions/BUILD.gn
@@ -121,6 +121,8 @@
     "test/logging_timer.h",
     "test/result_catcher.cc",
     "test/result_catcher.h",
+    "test/test_background_page_first_load_observer.cc",
+    "test/test_background_page_first_load_observer.h",
     "test/test_content_utility_client.cc",
     "test/test_content_utility_client.h",
     "test/test_extension_dir.cc",
diff --git a/extensions/browser/api/declarative_net_request/BUILD.gn b/extensions/browser/api/declarative_net_request/BUILD.gn
index 9d3188e3..ffdd5ce2 100644
--- a/extensions/browser/api/declarative_net_request/BUILD.gn
+++ b/extensions/browser/api/declarative_net_request/BUILD.gn
@@ -4,6 +4,8 @@
 
 source_set("declarative_net_request") {
   sources = [
+    "action_tracker.cc",
+    "action_tracker.h",
     "composite_matcher.cc",
     "composite_matcher.h",
     "constants.cc",
diff --git a/extensions/browser/api/declarative_net_request/action_tracker.cc b/extensions/browser/api/declarative_net_request/action_tracker.cc
new file mode 100644
index 0000000..66de566
--- /dev/null
+++ b/extensions/browser/api/declarative_net_request/action_tracker.cc
@@ -0,0 +1,79 @@
+// Copyright 2019 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 "extensions/browser/api/declarative_net_request/action_tracker.h"
+
+#include "base/stl_util.h"
+#include "extensions/browser/api/declarative_net_request/rules_monitor_service.h"
+#include "extensions/browser/api/extensions_api_client.h"
+#include "extensions/browser/extension_prefs.h"
+#include "extensions/common/constants.h"
+
+namespace extensions {
+namespace declarative_net_request {
+
+ActionTracker::ActionTracker(content::BrowserContext* browser_context)
+    : browser_context_(browser_context) {
+  extension_prefs_ = ExtensionPrefs::Get(browser_context_);
+}
+
+ActionTracker::~ActionTracker() {
+  DCHECK(actions_matched_.empty());
+}
+
+void ActionTracker::OnRuleMatched(const std::vector<ExtensionId>& extension_ids,
+                                  int tab_id) {
+  if (tab_id == extension_misc::kUnknownTabId)
+    return;
+
+  for (const auto& extension_id : extension_ids) {
+    auto key = std::make_pair(extension_id, tab_id);
+    int action_count = ++actions_matched_[key];
+
+    if (extension_prefs_->GetDNRUseActionCountAsBadgeText(extension_id)) {
+      DCHECK(ExtensionsAPIClient::Get());
+      ExtensionsAPIClient::Get()->UpdateActionCount(
+          browser_context_, extension_id, tab_id, action_count);
+    }
+  }
+}
+
+void ActionTracker::ClearExtensionData(const ExtensionId& extension_id) {
+  auto compare_by_extension_id =
+      [&extension_id](const std::pair<ExtensionTabKey, size_t>& it) {
+        return it.first.first == extension_id;
+      };
+
+  base::EraseIf(actions_matched_, compare_by_extension_id);
+}
+
+void ActionTracker::ClearTabData(int tab_id) {
+  auto compare_by_tab_id =
+      [&tab_id](const std::pair<ExtensionTabKey, size_t>& it) {
+        return it.first.second == tab_id;
+      };
+
+  base::EraseIf(actions_matched_, compare_by_tab_id);
+}
+
+void ActionTracker::ResetActionCountForTab(int tab_id) {
+  RulesMonitorService* rules_monitor_service =
+      RulesMonitorService::Get(browser_context_);
+
+  DCHECK(rules_monitor_service);
+  for (const auto& extension_id :
+       rules_monitor_service->extensions_with_rulesets()) {
+    auto key = std::make_pair(extension_id, tab_id);
+    actions_matched_[key] = 0;
+
+    if (extension_prefs_->GetDNRUseActionCountAsBadgeText(extension_id)) {
+      DCHECK(ExtensionsAPIClient::Get());
+      ExtensionsAPIClient::Get()->UpdateActionCount(
+          browser_context_, extension_id, tab_id, 0 /* action_count */);
+    }
+  }
+}
+
+}  // namespace declarative_net_request
+}  // namespace extensions
diff --git a/extensions/browser/api/declarative_net_request/action_tracker.h b/extensions/browser/api/declarative_net_request/action_tracker.h
new file mode 100644
index 0000000..76255a27
--- /dev/null
+++ b/extensions/browser/api/declarative_net_request/action_tracker.h
@@ -0,0 +1,63 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_ACTION_TRACKER_H_
+#define EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_ACTION_TRACKER_H_
+
+#include <map>
+#include <vector>
+
+#include "base/macros.h"
+#include "extensions/common/extension_id.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace extensions {
+
+class ExtensionPrefs;
+
+namespace declarative_net_request {
+
+class ActionTracker {
+ public:
+  explicit ActionTracker(content::BrowserContext* browser_context);
+  ~ActionTracker();
+
+  // Called whenever a request matches with a rule.
+  void OnRuleMatched(const std::vector<ExtensionId>& extension_ids, int tab_id);
+
+  // Clears the action count for the specified |extension_id| for all tabs.
+  // Called when an extension's ruleset is removed.
+  void ClearExtensionData(const ExtensionId& extension_id);
+
+  // Clears the action count for every extension for the specified |tab_id|.
+  // Called when the tab has been closed.
+  void ClearTabData(int tab_id);
+
+  // Sets the action count for every extension for the specified |tab_id| to 0
+  // and notifies the extension action to set the badge text to 0 for that tab.
+  // Called when the a main-frame navigation to a different document finishes on
+  // the tab.
+  void ResetActionCountForTab(int tab_id);
+
+ private:
+  using ExtensionTabKey = std::pair<ExtensionId, int>;
+
+  // Maps a pair of (extension ID, tab ID) to the number of actions matched for
+  // the extension and tab specified.
+  std::map<ExtensionTabKey, int> actions_matched_;
+
+  content::BrowserContext* browser_context_;
+
+  ExtensionPrefs* extension_prefs_;
+
+  DISALLOW_COPY_AND_ASSIGN(ActionTracker);
+};
+
+}  // namespace declarative_net_request
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_ACTION_TRACKER_H_
diff --git a/extensions/browser/api/declarative_net_request/declarative_net_request_api.cc b/extensions/browser/api/declarative_net_request/declarative_net_request_api.cc
index 6d26296..82b0d93 100644
--- a/extensions/browser/api/declarative_net_request/declarative_net_request_api.cc
+++ b/extensions/browser/api/declarative_net_request/declarative_net_request_api.cc
@@ -330,6 +330,11 @@
 
   ExtensionPrefs* prefs = ExtensionPrefs::Get(browser_context());
   prefs->SetDNRUseActionCountAsBadgeText(extension_id(), params->enable);
+
+  // TODO(crbug.com/979068): If the preference is switched on, update the
+  // extension's badge text with the number of actions matched for this
+  // extension. Otherwise, clear the badge text for the extension's icon and
+  // show the default badge text.
   return RespondNow(NoArguments());
 }
 
diff --git a/extensions/browser/api/declarative_net_request/rules_monitor_service.h b/extensions/browser/api/declarative_net_request/rules_monitor_service.h
index 54c4c2a..1349a41 100644
--- a/extensions/browser/api/declarative_net_request/rules_monitor_service.h
+++ b/extensions/browser/api/declarative_net_request/rules_monitor_service.h
@@ -61,6 +61,10 @@
   // the given |extension_id|.
   bool HasRegisteredRuleset(const ExtensionId& extension_id) const;
 
+  const std::set<ExtensionId>& extensions_with_rulesets() const {
+    return extensions_with_rulesets_;
+  }
+
   // Updates the dynamic rules for the |extension| and then invokes
   // |callback| with an optional error.
   using DynamicRuleUpdateUICallback =
diff --git a/extensions/browser/api/declarative_net_request/ruleset_manager.cc b/extensions/browser/api/declarative_net_request/ruleset_manager.cc
index 1f0ebc38..a8f1ebd 100644
--- a/extensions/browser/api/declarative_net_request/ruleset_manager.cc
+++ b/extensions/browser/api/declarative_net_request/ruleset_manager.cc
@@ -223,7 +223,8 @@
 RulesetManager::RulesetManager(content::BrowserContext* browser_context)
     : browser_context_(browser_context),
       prefs_(ExtensionPrefs::Get(browser_context)),
-      permission_helper_(PermissionHelper::Get(browser_context)) {
+      permission_helper_(PermissionHelper::Get(browser_context)),
+      action_tracker_(browser_context) {
   DCHECK(browser_context_);
 
   // RulesetManager can be created on any sequence.
@@ -268,6 +269,7 @@
       << "RemoveRuleset called without a corresponding AddRuleset for "
       << extension_id;
 
+  action_tracker_.ClearExtensionData(extension_id);
   base::EraseIf(rulesets_, compare_by_id);
 
   if (test_observer_)
@@ -399,9 +401,11 @@
     const RequestParams& params) const {
   for (const ExtensionRulesetData* ruleset : rulesets) {
     if (ruleset->matcher->ShouldBlockRequest(params)) {
-      return ShouldCollapseResourceType(params.element_type)
-                 ? Action(Action::Type::COLLAPSE)
-                 : Action(Action::Type::BLOCK);
+      Action action = ShouldCollapseResourceType(params.element_type)
+                          ? Action(Action::Type::COLLAPSE)
+                          : Action(Action::Type::BLOCK);
+      action.extension_ids.push_back(ruleset->extension_id);
+      return action;
     }
   }
   return base::nullopt;
@@ -447,6 +451,7 @@
 
     Action action(Action::Type::REDIRECT);
     action.redirect_url = std::move(redirect_action.redirect_url);
+    action.extension_ids.push_back(ruleset->extension_id);
     return action;
   }
 
@@ -456,14 +461,19 @@
 base::Optional<RulesetManager::Action> RulesetManager::GetRemoveHeadersAction(
     const std::vector<const ExtensionRulesetData*>& rulesets,
     const RequestParams& params) const {
+  Action action(Action::Type::REMOVE_HEADERS);
   uint8_t mask = 0;
-  for (const ExtensionRulesetData* ruleset : rulesets)
-    mask |= ruleset->matcher->GetRemoveHeadersMask(params, mask);
+  for (const ExtensionRulesetData* ruleset : rulesets) {
+    uint8_t ruleset_mask = ruleset->matcher->GetRemoveHeadersMask(params, mask);
+    if (ruleset_mask)
+      action.extension_ids.push_back(ruleset->extension_id);
+
+    mask |= ruleset_mask;
+  }
 
   if (!mask)
     return base::nullopt;
 
-  Action action(Action::Type::REMOVE_HEADERS);
   PopulateHeadersFromMask(mask, &action.request_headers_to_remove,
                           &action.response_headers_to_remove);
   return action;
diff --git a/extensions/browser/api/declarative_net_request/ruleset_manager.h b/extensions/browser/api/declarative_net_request/ruleset_manager.h
index 652fe90..7f7bef6 100644
--- a/extensions/browser/api/declarative_net_request/ruleset_manager.h
+++ b/extensions/browser/api/declarative_net_request/ruleset_manager.h
@@ -14,6 +14,7 @@
 #include "base/optional.h"
 #include "base/sequence_checker.h"
 #include "base/time/time.h"
+#include "extensions/browser/api/declarative_net_request/action_tracker.h"
 #include "extensions/browser/api/declarative_net_request/utils.h"
 #include "extensions/common/extension_id.h"
 #include "extensions/common/permissions/permissions_data.h"
@@ -61,6 +62,11 @@
     // Valid iff |type| is |REDIRECT|.
     base::Optional<GURL> redirect_url;
 
+    // The ids of the extensions the action is attributed to.
+    // TODO(crbug.com/991420): This is not exactly correct for attributing
+    // an Action to the extension(s) for |REMOVE_HEADERS| rules.
+    std::vector<ExtensionId> extension_ids;
+
     // Valid iff |type| is |REMOVE_HEADERS|. The vectors point to strings of
     // static storage duration.
     std::vector<const char*> request_headers_to_remove;
@@ -124,6 +130,9 @@
   // Sets the TestObserver. Client maintains ownership of |observer|.
   void SetObserverForTest(TestObserver* observer);
 
+  const ActionTracker& action_tracker() const { return action_tracker_; }
+  ActionTracker& action_tracker() { return action_tracker_; }
+
  private:
   struct ExtensionRulesetData {
     ExtensionRulesetData(const ExtensionId& extension_id,
@@ -187,6 +196,10 @@
   // Non-owning pointer to TestObserver.
   TestObserver* test_observer_ = nullptr;
 
+  // Mutable because this is updated in multiple const methods where we create
+  // and return the appropriate action based on the rule matched.
+  mutable ActionTracker action_tracker_;
+
   SEQUENCE_CHECKER(sequence_checker_);
 
   DISALLOW_COPY_AND_ASSIGN(RulesetManager);
diff --git a/extensions/browser/api/extensions_api_client.cc b/extensions/browser/api/extensions_api_client.cc
index bac64cb..d5b265f 100644
--- a/extensions/browser/api/extensions_api_client.cc
+++ b/extensions/browser/api/extensions_api_client.cc
@@ -54,6 +54,11 @@
     int render_frame_id,
     const ExtensionId& extension_id) {}
 
+void ExtensionsAPIClient::UpdateActionCount(content::BrowserContext* context,
+                                            const ExtensionId& extension_id,
+                                            int tab_id,
+                                            int action_count) {}
+
 AppViewGuestDelegate* ExtensionsAPIClient::CreateAppViewGuestDelegate() const {
   return NULL;
 }
diff --git a/extensions/browser/api/extensions_api_client.h b/extensions/browser/api/extensions_api_client.h
index 1b6021c..04673c64 100644
--- a/extensions/browser/api/extensions_api_client.h
+++ b/extensions/browser/api/extensions_api_client.h
@@ -109,6 +109,12 @@
                                         int render_frame_id,
                                         const ExtensionId& extension_id);
 
+  // Updates an extension's matched action count stored in an ExtensionAction.
+  virtual void UpdateActionCount(content::BrowserContext* context,
+                                 const ExtensionId& extension_id,
+                                 int tab_id,
+                                 int action_count);
+
   // Creates the AppViewGuestDelegate.
   virtual AppViewGuestDelegate* CreateAppViewGuestDelegate() const;
 
diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc
index 1e0def6..eeaff91 100644
--- a/extensions/browser/api/web_request/web_request_api.cc
+++ b/extensions/browser/api/web_request/web_request_api.cc
@@ -68,6 +68,7 @@
 #include "extensions/browser/warning_service.h"
 #include "extensions/browser/warning_set.h"
 #include "extensions/common/api/web_request.h"
+#include "extensions/common/constants.h"
 #include "extensions/common/error_utils.h"
 #include "extensions/common/event_filtering_info.h"
 #include "extensions/common/extension.h"
@@ -476,6 +477,19 @@
   return *headers_filtered ? result : response_headers;
 }
 
+// Helper to record a matched DNR action in RulesetManager's ActionTracker.
+void OnDNRActionMatched(content::BrowserContext* browser_context,
+                        const WebRequestInfo& request) {
+  DCHECK(request.dnr_action.has_value());
+
+  declarative_net_request::ActionTracker& action_tracker =
+      declarative_net_request::RulesMonitorService::Get(browser_context)
+          ->ruleset_manager()
+          ->action_tracker();
+  action_tracker.OnRuleMatched(request.dnr_action->extension_ids,
+                               request.frame_data.tab_id);
+}
+
 }  // namespace
 
 void WebRequestAPI::Proxy::HandleAuthRequest(
@@ -1013,12 +1027,15 @@
     case Action::Type::NONE:
       break;
     case Action::Type::BLOCK:
+      OnDNRActionMatched(browser_context, *request);
       return net::ERR_BLOCKED_BY_CLIENT;
     case Action::Type::COLLAPSE:
+      OnDNRActionMatched(browser_context, *request);
       *should_collapse_initiator = true;
       return net::ERR_BLOCKED_BY_CLIENT;
     case Action::Type::REDIRECT:
       DCHECK(action.redirect_url);
+      OnDNRActionMatched(browser_context, *request);
       *new_url = action.redirect_url.value();
       return net::OK;
     case Action::Type::REMOVE_HEADERS:
@@ -1091,6 +1108,11 @@
     } while (headers->HasHeader(header));
   }
 
+  // TODO(crbug.com/991420): This does not properly associate which headers are
+  // removed by which extensions.
+  if (!removed_headers.empty())
+    OnDNRActionMatched(browser_context, *request);
+
   bool initialize_blocked_requests = false;
 
   initialize_blocked_requests |=
@@ -1184,6 +1206,10 @@
     // |override_response_headers| don't point to the same object.
     *override_response_headers = base::MakeRefCounted<net::HttpResponseHeaders>(
         filtered_response_headers->raw_headers());
+
+    // TODO(crbug.com/991420): This does not properly associate which headers
+    // are removed by which extensions.
+    OnDNRActionMatched(browser_context, *request);
   }
 
   bool initialize_blocked_requests = false;
diff --git a/extensions/browser/content_hash_fetcher.cc b/extensions/browser/content_hash_fetcher.cc
index db1c8d02..d0aa506 100644
--- a/extensions/browser/content_hash_fetcher.cc
+++ b/extensions/browser/content_hash_fetcher.cc
@@ -83,9 +83,8 @@
         })");
   auto resource_request = std::make_unique<network::ResourceRequest>();
   resource_request->url = fetch_params_.fetch_url;
-  resource_request->load_flags = net::LOAD_DO_NOT_SEND_COOKIES |
-                                 net::LOAD_DO_NOT_SAVE_COOKIES |
-                                 net::LOAD_DISABLE_CACHE;
+  resource_request->load_flags = net::LOAD_DISABLE_CACHE;
+  resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
 
   network::mojom::URLLoaderFactoryPtr url_loader_factory_ptr;
   url_loader_factory_ptr.Bind(
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index f7343aea..2b10bca0 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -210,7 +210,7 @@
   DELETED_EXPERIMENTAL_MEDIAGALLERIES_ASSEMBLEMEDIAFILE = 149,
   BOOKMARKMANAGERPRIVATE_STARTDRAG = 150,
   BROWSINGDATA_REMOVEPASSWORDS = 151,
-  DOWNLOADS_DRAG = 152,
+  DELETED_DOWNLOADS_DRAG = 152,
   INPUT_IME_SETCOMPOSITION = 153,
   METRICSPRIVATE_RECORDUSERACTION = 154,
   USB_RELEASEINTERFACE = 155,
diff --git a/extensions/browser/guest_view/web_view/web_ui/web_ui_url_fetcher.cc b/extensions/browser/guest_view/web_view/web_ui/web_ui_url_fetcher.cc
index ad27ff6..bc6ec53 100644
--- a/extensions/browser/guest_view/web_view/web_ui/web_ui_url_fetcher.cc
+++ b/extensions/browser/guest_view/web_view/web_ui/web_ui_url_fetcher.cc
@@ -56,8 +56,7 @@
         })");
   auto resource_request = std::make_unique<network::ResourceRequest>();
   resource_request->url = url_;
-  resource_request->load_flags =
-      net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES;
+  resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
   fetcher_ = network::SimpleURLLoader::Create(std::move(resource_request),
                                               traffic_annotation);
   fetcher_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
diff --git a/extensions/test/test_background_page_first_load_observer.cc b/extensions/test/test_background_page_first_load_observer.cc
new file mode 100644
index 0000000..7f8300aa
--- /dev/null
+++ b/extensions/test/test_background_page_first_load_observer.cc
@@ -0,0 +1,58 @@
+// Copyright 2019 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 "extensions/test/test_background_page_first_load_observer.h"
+
+#include "base/logging.h"
+#include "extensions/browser/extension_host.h"
+#include "extensions/browser/process_manager.h"
+
+namespace extensions {
+
+TestBackgroundPageFirstLoadObserver::TestBackgroundPageFirstLoadObserver(
+    content::BrowserContext* browser_context,
+    const ExtensionId& extension_id)
+    : extension_id_(extension_id),
+      process_manager_(ProcessManager::Get(browser_context)),
+      process_manager_observer_(this) {
+  process_manager_observer_.Add(process_manager_);
+  extension_host_ =
+      process_manager_->GetBackgroundHostForExtension(extension_id_);
+  if (extension_host_)
+    OnObtainedExtensionHost();
+}
+
+TestBackgroundPageFirstLoadObserver::~TestBackgroundPageFirstLoadObserver() {
+  if (extension_host_) {
+    static_cast<DeferredStartRenderHost*>(extension_host_)
+        ->RemoveDeferredStartRenderHostObserver(this);
+  }
+}
+
+void TestBackgroundPageFirstLoadObserver::Wait() {
+  if (!extension_host_ || !extension_host_->has_loaded_once())
+    run_loop_.Run();
+}
+
+void TestBackgroundPageFirstLoadObserver::OnBackgroundHostCreated(
+    ExtensionHost* host) {
+  if (host->extension_id() == extension_id_) {
+    DCHECK(!extension_host_);
+    extension_host_ = host;
+    OnObtainedExtensionHost();
+  }
+}
+
+void TestBackgroundPageFirstLoadObserver::
+    OnDeferredStartRenderHostDidStopFirstLoad(
+        const DeferredStartRenderHost* host) {
+  run_loop_.Quit();
+}
+
+void TestBackgroundPageFirstLoadObserver::OnObtainedExtensionHost() {
+  static_cast<DeferredStartRenderHost*>(extension_host_)
+      ->AddDeferredStartRenderHostObserver(this);
+}
+
+}  // namespace extensions
diff --git a/extensions/test/test_background_page_first_load_observer.h b/extensions/test/test_background_page_first_load_observer.h
new file mode 100644
index 0000000..63a2bc5
--- /dev/null
+++ b/extensions/test/test_background_page_first_load_observer.h
@@ -0,0 +1,58 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_TEST_TEST_BACKGROUND_PAGE_FIRST_LOAD_OBSERVER_H_
+#define EXTENSIONS_TEST_TEST_BACKGROUND_PAGE_FIRST_LOAD_OBSERVER_H_
+
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/scoped_observer.h"
+#include "extensions/browser/deferred_start_render_host_observer.h"
+#include "extensions/browser/process_manager_observer.h"
+#include "extensions/common/extension_id.h"
+
+namespace content {
+class BrowserContext;
+}
+
+// Allows to wait until the WebContents of an extension's ExtensionHost sees its
+// first DidStopLoading().
+namespace extensions {
+
+class ExtensionHost;
+class ProcessManager;
+
+class TestBackgroundPageFirstLoadObserver
+    : public ProcessManagerObserver,
+      public DeferredStartRenderHostObserver {
+ public:
+  TestBackgroundPageFirstLoadObserver(content::BrowserContext* browser_context,
+                                      const ExtensionId& extension_id);
+  ~TestBackgroundPageFirstLoadObserver() override;
+
+  void Wait();
+
+ private:
+  // ProcessManagerObserver:
+  void OnBackgroundHostCreated(ExtensionHost* host) override;
+
+  // DeferredStartRenderHostObserver:
+  void OnDeferredStartRenderHostDidStopFirstLoad(
+      const DeferredStartRenderHost* host) override;
+
+  void OnObtainedExtensionHost();
+
+  const ExtensionId extension_id_;
+  ProcessManager* const process_manager_ = nullptr;
+  ExtensionHost* extension_host_ = nullptr;
+  base::RunLoop run_loop_;
+  ScopedObserver<ProcessManager, ProcessManagerObserver>
+      process_manager_observer_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestBackgroundPageFirstLoadObserver);
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_TEST_TEST_BACKGROUND_PAGE_FIRST_LOAD_OBSERVER_H_
diff --git a/gin/converter.cc b/gin/converter.cc
index bc95df4..3498080e 100644
--- a/gin/converter.cc
+++ b/gin/converter.cc
@@ -6,6 +6,7 @@
 
 #include <stdint.h>
 
+#include "base/strings/string_util.h"
 #include "v8/include/v8.h"
 
 using v8::ArrayBuffer;
@@ -151,6 +152,29 @@
   return true;
 }
 
+Local<Value> Converter<base::string16>::ToV8(Isolate* isolate,
+                                             const base::string16& val) {
+  return String::NewFromTwoByte(isolate,
+                                reinterpret_cast<const uint16_t*>(val.data()),
+                                v8::NewStringType::kNormal, val.size())
+      .ToLocalChecked();
+}
+
+bool Converter<base::string16>::FromV8(Isolate* isolate,
+                                       Local<Value> val,
+                                       base::string16* out) {
+  if (!val->IsString())
+    return false;
+  Local<String> str = Local<String>::Cast(val);
+  int length = str->Length();
+  // Note that the reinterpret cast is because on Windows string16 is an alias
+  // to wstring, and hence has character type wchar_t not uint16_t.
+  str->Write(isolate,
+             reinterpret_cast<uint16_t*>(base::WriteInto(out, length + 1)), 0,
+             length);
+  return true;
+}
+
 Local<Value> Converter<Local<Function>>::ToV8(Isolate* isolate,
                                               Local<Function> val) {
   return val.As<Value>();
@@ -240,6 +264,14 @@
       .ToLocalChecked();
 }
 
+v8::Local<v8::String> StringToSymbol(v8::Isolate* isolate,
+                                     const base::StringPiece16& val) {
+  return String::NewFromTwoByte(isolate,
+                                reinterpret_cast<const uint16_t*>(val.data()),
+                                v8::NewStringType::kInternalized, val.length())
+      .ToLocalChecked();
+}
+
 std::string V8ToString(v8::Isolate* isolate, v8::Local<v8::Value> value) {
   if (value.IsEmpty())
     return std::string();
diff --git a/gin/converter.h b/gin/converter.h
index 48be87c..27b4d0ac 100644
--- a/gin/converter.h
+++ b/gin/converter.h
@@ -12,6 +12,7 @@
 #include <vector>
 
 #include "base/logging.h"
+#include "base/strings/string16.h"
 #include "base/strings/string_piece.h"
 #include "gin/gin_export.h"
 #include "v8/include/v8.h"
@@ -119,8 +120,17 @@
                      std::string* out);
 };
 
-template<>
-struct GIN_EXPORT Converter<v8::Local<v8::Function> > {
+template <>
+struct GIN_EXPORT Converter<base::string16> {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
+                                   const base::string16& val);
+  static bool FromV8(v8::Isolate* isolate,
+                     v8::Local<v8::Value> val,
+                     base::string16* out);
+};
+
+template <>
+struct GIN_EXPORT Converter<v8::Local<v8::Function>> {
   static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
                                    v8::Local<v8::Function> val);
   static bool FromV8(v8::Isolate* isolate,
@@ -263,6 +273,10 @@
 GIN_EXPORT v8::Local<v8::String> StringToSymbol(v8::Isolate* isolate,
                                                  const base::StringPiece& val);
 
+// This crashes when input.size() > v8::String::kMaxLength.
+GIN_EXPORT v8::Local<v8::String> StringToSymbol(v8::Isolate* isolate,
+                                                const base::StringPiece16& val);
+
 template<typename T>
 bool ConvertFromV8(v8::Isolate* isolate, v8::Local<v8::Value> input,
                    T* result) {
diff --git a/google_apis/drive/base_requests.cc b/google_apis/drive/base_requests.cc
index 49227c7d..ef79519c 100644
--- a/google_apis/drive/base_requests.cc
+++ b/google_apis/drive/base_requests.cc
@@ -315,8 +315,8 @@
   auto request = std::make_unique<network::ResourceRequest>();
   request->url = url;
   request->method = GetRequestType();
-  request->load_flags = net::LOAD_DO_NOT_SEND_COOKIES |
-                        net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DISABLE_CACHE;
+  request->load_flags = net::LOAD_DISABLE_CACHE;
+  request->credentials_mode = network::mojom::CredentialsMode::kOmit;
 
   // Add request headers.
   // Note that SetHeader clears the current headers and sets it to the passed-in
diff --git a/google_apis/gaia/gaia_oauth_client.cc b/google_apis/gaia/gaia_oauth_client.cc
index 4e0335bf..4838ad5 100644
--- a/google_apis/gaia/gaia_oauth_client.cc
+++ b/google_apis/gaia/gaia_oauth_client.cc
@@ -386,8 +386,7 @@
   auto resource_request = std::make_unique<network::ResourceRequest>();
   resource_request->url = url_;
   resource_request->method = post_body_.empty() ? "GET" : "POST";
-  resource_request->load_flags =
-      net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES;
+  resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
   if (!authorization_header_.empty())
     resource_request->headers.SetHeader("Authorization", authorization_header_);
 
diff --git a/google_apis/gaia/oauth2_access_token_fetcher_impl.cc b/google_apis/gaia/oauth2_access_token_fetcher_impl.cc
index 7e0e085..9105555 100644
--- a/google_apis/gaia/oauth2_access_token_fetcher_impl.cc
+++ b/google_apis/gaia/oauth2_access_token_fetcher_impl.cc
@@ -120,8 +120,7 @@
 
   auto resource_request = std::make_unique<network::ResourceRequest>();
   resource_request->url = url;
-  resource_request->load_flags =
-      net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES;
+  resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
   if (!body.empty())
     resource_request->method = "POST";
 
diff --git a/google_apis/gaia/oauth2_api_call_flow.cc b/google_apis/gaia/oauth2_api_call_flow.cc
index 14c637d2..7ef2fdd 100644
--- a/google_apis/gaia/oauth2_api_call_flow.cc
+++ b/google_apis/gaia/oauth2_api_call_flow.cc
@@ -89,8 +89,7 @@
   auto request = std::make_unique<network::ResourceRequest>();
   request->url = CreateApiCallUrl();
   request->method = request_type;
-  request->load_flags =
-      net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES;
+  request->credentials_mode = network::mojom::CredentialsMode::kOmit;
   request->headers.SetHeader("Authorization",
                              MakeAuthorizationValue(access_token));
   std::unique_ptr<network::SimpleURLLoader> result =
diff --git a/google_apis/gcm/engine/checkin_request.cc b/google_apis/gcm/engine/checkin_request.cc
index b2723cd..a0999b6 100644
--- a/google_apis/gcm/engine/checkin_request.cc
+++ b/google_apis/gcm/engine/checkin_request.cc
@@ -183,8 +183,7 @@
   auto resource_request = std::make_unique<network::ResourceRequest>();
   resource_request->url = checkin_url_;
   resource_request->method = "POST";
-  resource_request->load_flags =
-      net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES;
+  resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
   url_loader_ = network::SimpleURLLoader::Create(std::move(resource_request),
                                                  traffic_annotation);
   url_loader_->AttachStringForUpload(upload_data, kRequestContentType);
diff --git a/google_apis/gcm/engine/registration_request.cc b/google_apis/gcm/engine/registration_request.cc
index a99879d..1332d878 100644
--- a/google_apis/gcm/engine/registration_request.cc
+++ b/google_apis/gcm/engine/registration_request.cc
@@ -177,8 +177,7 @@
   auto request = std::make_unique<network::ResourceRequest>();
   request->url = registration_url_;
   request->method = "POST";
-  request->load_flags =
-      net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES;
+  request->credentials_mode = network::mojom::CredentialsMode::kOmit;
   BuildRequestHeaders(&request->headers);
 
   std::string body;
diff --git a/google_apis/gcm/engine/registration_request_unittest.cc b/google_apis/gcm/engine/registration_request_unittest.cc
index d325019..4df9c22 100644
--- a/google_apis/gcm/engine/registration_request_unittest.cc
+++ b/google_apis/gcm/engine/registration_request_unittest.cc
@@ -462,8 +462,8 @@
   const network::ResourceRequest* pending_request;
   ASSERT_TRUE(
       test_url_loader_factory()->IsPending(kRegistrationURL, &pending_request));
-  EXPECT_TRUE(pending_request->load_flags & net::LOAD_DO_NOT_SEND_COOKIES);
-  EXPECT_TRUE(pending_request->load_flags & net::LOAD_DO_NOT_SAVE_COOKIES);
+  EXPECT_EQ(network::mojom::CredentialsMode::kOmit,
+            pending_request->credentials_mode);
 
   // Verify that authorization header was put together properly.
   const net::HttpRequestHeaders* headers =
diff --git a/google_apis/gcm/engine/unregistration_request.cc b/google_apis/gcm/engine/unregistration_request.cc
index ca1a7c2..e20991b5 100644
--- a/google_apis/gcm/engine/unregistration_request.cc
+++ b/google_apis/gcm/engine/unregistration_request.cc
@@ -162,8 +162,7 @@
   auto request = std::make_unique<network::ResourceRequest>();
   request->url = registration_url_;
   request->method = "POST";
-  request->load_flags =
-      net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES;
+  request->credentials_mode = network::mojom::CredentialsMode::kOmit;
   BuildRequestHeaders(&request->headers);
 
   std::string body;
diff --git a/google_apis/gcm/engine/unregistration_request_unittest.cc b/google_apis/gcm/engine/unregistration_request_unittest.cc
index 16a3543..228fee9 100644
--- a/google_apis/gcm/engine/unregistration_request_unittest.cc
+++ b/google_apis/gcm/engine/unregistration_request_unittest.cc
@@ -115,8 +115,8 @@
   const network::ResourceRequest* pending_request;
   ASSERT_TRUE(
       test_url_loader_factory()->IsPending(kRegistrationURL, &pending_request));
-  EXPECT_TRUE(pending_request->load_flags & net::LOAD_DO_NOT_SEND_COOKIES);
-  EXPECT_TRUE(pending_request->load_flags & net::LOAD_DO_NOT_SAVE_COOKIES);
+  EXPECT_EQ(network::mojom::CredentialsMode::kOmit,
+            pending_request->credentials_mode);
 
   // Verify that authorization header was put together properly.
   const net::HttpRequestHeaders* headers =
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg
index cc5cc33..19f6bde 100644
--- a/infra/config/cr-buildbucket.cfg
+++ b/infra/config/cr-buildbucket.cfg
@@ -1281,6 +1281,23 @@
     }
 
     builders {
+      name: "android-sdk-packager"
+      mixins: "linux-xenial"
+      mixins: "builderless"
+      recipe {
+        name: "android/sdk_packager"
+        properties_j: <<END
+          packages: [
+            {
+              "sdk_package_name": "emulator",
+              "cipd_yaml": "third_party/android_sdk/cipd_emulator.yaml"
+            }
+          ]
+        END
+      }
+    }
+
+    builders {
       name: "Cast Android (dbg)"
       mixins: "android-ci"
       mixins: "linux-xenial"
diff --git a/infra/config/luci-scheduler.cfg b/infra/config/luci-scheduler.cfg
index a472ce6..0554925 100644
--- a/infra/config/luci-scheduler.cfg
+++ b/infra/config/luci-scheduler.cfg
@@ -885,6 +885,18 @@
 }
 
 job {
+  id: "android-sdk-packager"
+  acl_sets: "default"
+  # Run weekly, on Sunday morning at midnight.
+  schedule: "0 7 * * 0 *"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "android-sdk-packager"
+  }
+}
+
+job {
   id: "Cast Android (dbg)"
   acl_sets: "default"
   buildbucket: {
diff --git a/ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm b/ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm
index 58b6f6c..b966875 100644
--- a/ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm
+++ b/ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm
@@ -655,9 +655,7 @@
 - (void)testOpenLinkInNewTab {
   // TODO(crbug.com/989550) Disable broken context menu tests on Xc11b5.
   if (@available(iOS 13, *)) {
-    if ([ChromeEarlGrey isIPadIdiom]) {
-      EARL_GREY_TEST_DISABLED(@"Test disabled on iPad.");
-    }
+    EARL_GREY_TEST_DISABLED(@"Test disabled on iOS13.");
   }
   // Create map of canned responses and set up the test HTML server.
   std::map<GURL, std::string> responses;
diff --git a/ios/chrome/browser/omaha/omaha_service.mm b/ios/chrome/browser/omaha/omaha_service.mm
index 931bbc8..821c864 100644
--- a/ios/chrome/browser/omaha/omaha_service.mm
+++ b/ios/chrome/browser/omaha/omaha_service.mm
@@ -549,8 +549,7 @@
   auto resource_request = std::make_unique<network::ResourceRequest>();
   resource_request->url = url;
   resource_request->method = "POST";
-  resource_request->load_flags =
-      net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES;
+  resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
 
   // If this is not the first try, notify the omaha server.
   if (number_of_tries_ && IsNextPingInstallRetry()) {
diff --git a/ios/chrome/browser/ui/autofill/cells/cvc_item.mm b/ios/chrome/browser/ui/autofill/cells/cvc_item.mm
index 81d5721..1f440d42 100644
--- a/ios/chrome/browser/ui/autofill/cells/cvc_item.mm
+++ b/ios/chrome/browser/ui/autofill/cells/cvc_item.mm
@@ -5,11 +5,10 @@
 #import "ios/chrome/browser/ui/autofill/cells/cvc_item.h"
 
 #include "components/strings/grit/components_strings.h"
-#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
+#import "ios/chrome/common/colors/semantic_color_names.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
-#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
 #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -110,7 +109,7 @@
     _instructionsTextLabel = [[UILabel alloc] init];
     _instructionsTextLabel.font =
         [[MDCTypography fontLoader] mediumFontOfSize:14];
-    _instructionsTextLabel.textColor = [[MDCPalette greyPalette] tint500];
+    _instructionsTextLabel.textColor = [UIColor colorNamed:kTextSecondaryColor];
     _instructionsTextLabel.numberOfLines = 0;
     _instructionsTextLabel.lineBreakMode = NSLineBreakByWordWrapping;
     _instructionsTextLabel.translatesAutoresizingMaskIntoConstraints = NO;
@@ -118,7 +117,7 @@
 
     _errorLabel = [[UILabel alloc] init];
     _errorLabel.font = [[MDCTypography fontLoader] regularFontOfSize:12];
-    _errorLabel.textColor = [[MDCPalette cr_redPalette] tint500];
+    _errorLabel.textColor = [UIColor colorNamed:kRedColor];
     _errorLabel.numberOfLines = 0;
     _errorLabel.lineBreakMode = NSLineBreakByWordWrapping;
     _errorLabel.translatesAutoresizingMaskIntoConstraints = NO;
@@ -157,6 +156,7 @@
     [contentView addSubview:_CVCContainerView];
 
     _CVCInput = ios::GetChromeBrowserProvider()->CreateStyledTextField();
+    _CVCInput.textColor = [UIColor colorNamed:kTextPrimaryColor];
     _CVCInput.placeholder =
         l10n_util::GetNSString(IDS_AUTOFILL_DIALOG_PLACEHOLDER_CVC);
     _CVCInput.accessibilityIdentifier = @"CVC_textField";
@@ -175,7 +175,7 @@
     [_buttonForNewCard
         setTitle:l10n_util::GetNSString(IDS_AUTOFILL_CARD_UNMASK_NEW_CARD_LINK)
         forState:UIControlStateNormal];
-    [_buttonForNewCard setTitleColor:[[MDCPalette cr_bluePalette] tint500]
+    [_buttonForNewCard setTitleColor:[UIColor colorNamed:kBlueColor]
                             forState:UIControlStateNormal];
     _buttonForNewCard.translatesAutoresizingMaskIntoConstraints = NO;
     [contentView addSubview:_buttonForNewCard];
diff --git a/ios/chrome/browser/ui/autofill/cells/legacy_autofill_edit_item.mm b/ios/chrome/browser/ui/autofill/cells/legacy_autofill_edit_item.mm
index a17a9cef..df91db86 100644
--- a/ios/chrome/browser/ui/autofill/cells/legacy_autofill_edit_item.mm
+++ b/ios/chrome/browser/ui/autofill/cells/legacy_autofill_edit_item.mm
@@ -5,11 +5,10 @@
 #import "ios/chrome/browser/ui/autofill/cells/legacy_autofill_edit_item.h"
 
 #include "ios/chrome/browser/ui/collection_view/cells/collection_view_cell_constants.h"
-#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
 #import "ios/chrome/browser/ui/util/rtl_geometry.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
+#import "ios/chrome/common/colors/semantic_color_names.h"
 #import "ios/chrome/common/ui_util/constraints_ui_util.h"
-#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
 #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -79,8 +78,8 @@
   }
   cell.textField.enabled = self.textFieldEnabled;
   cell.textField.textColor = self.textFieldEnabled
-                                 ? [[MDCPalette cr_bluePalette] tint500]
-                                 : [[MDCPalette greyPalette] tint500];
+                                 ? [UIColor colorNamed:kBlueColor]
+                                 : [UIColor colorNamed:kTextSecondaryColor];
   [cell.textField addTarget:self
                      action:@selector(textFieldChanged:)
            forControlEvents:UIControlEventEditingChanged];
@@ -182,11 +181,11 @@
   } else {
     MaybeSetUILabelScaledFont(withFontScaling, self.textLabel,
                               [[MDCTypography fontLoader] mediumFontOfSize:14]);
-    self.textLabel.textColor = [[MDCPalette greyPalette] tint900];
+    self.textLabel.textColor = [UIColor colorNamed:kTextPrimaryColor];
     MaybeSetUITextFieldScaledFont(
         withFontScaling, self.textField,
         [[MDCTypography fontLoader] lightFontOfSize:16]);
-    self.textField.textColor = [[MDCPalette greyPalette] tint500];
+    self.textField.textColor = [UIColor colorNamed:kTextSecondaryColor];
   }
 }
 
diff --git a/ios/chrome/browser/ui/autofill/cells/status_item.mm b/ios/chrome/browser/ui/autofill/cells/status_item.mm
index acad67fe..0c8bf81 100644
--- a/ios/chrome/browser/ui/autofill/cells/status_item.mm
+++ b/ios/chrome/browser/ui/autofill/cells/status_item.mm
@@ -5,11 +5,10 @@
 #import "ios/chrome/browser/ui/autofill/cells/status_item.h"
 
 #include "base/logging.h"
-#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
+#import "ios/chrome/common/colors/semantic_color_names.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
 #import "ios/third_party/material_components_ios/src/components/ActivityIndicator/src/MaterialActivityIndicator.h"
-#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
 #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -66,7 +65,7 @@
     [contentView addSubview:verticalCenteringView];
 
     _activityIndicator = [[MDCActivityIndicator alloc] init];
-    _activityIndicator.cycleColors = @[ [[MDCPalette cr_bluePalette] tint500] ];
+    _activityIndicator.cycleColors = @[ [UIColor colorNamed:kBlueColor] ];
     [_activityIndicator setRadius:10];
     _activityIndicator.translatesAutoresizingMaskIntoConstraints = NO;
     [verticalCenteringView addSubview:_activityIndicator];
@@ -169,21 +168,21 @@
 - (void)configureForState:(StatusItemState)state {
   switch (state) {
     case StatusItemState::VERIFYING:
-      self.textLabel.textColor = [[MDCPalette cr_bluePalette] tint500];
+      self.textLabel.textColor = [UIColor colorNamed:kBlueColor];
       [self.activityIndicator startAnimating];
       self.activityIndicator.hidden = NO;
       self.verifiedImageView.hidden = YES;
       self.errorImageView.hidden = YES;
       break;
     case StatusItemState::VERIFIED:
-      self.textLabel.textColor = [[MDCPalette cr_bluePalette] tint500];
+      self.textLabel.textColor = [UIColor colorNamed:kBlueColor];
       [self.activityIndicator stopAnimating];
       self.activityIndicator.hidden = YES;
       self.verifiedImageView.hidden = NO;
       self.errorImageView.hidden = YES;
       break;
     case StatusItemState::ERROR:
-      self.textLabel.textColor = [[MDCPalette cr_redPalette] tint500];
+      self.textLabel.textColor = [UIColor colorNamed:kRedColor];
       [self.activityIndicator stopAnimating];
       self.activityIndicator.hidden = YES;
       self.verifiedImageView.hidden = YES;
diff --git a/ios/chrome/browser/ui/badges/BUILD.gn b/ios/chrome/browser/ui/badges/BUILD.gn
index 0b0aa5f9..07ee5a8 100644
--- a/ios/chrome/browser/ui/badges/BUILD.gn
+++ b/ios/chrome/browser/ui/badges/BUILD.gn
@@ -22,11 +22,14 @@
     "badge_consumer.h",
     "badge_mediator.h",
     "badge_mediator.mm",
+    "badge_static_item.h",
+    "badge_static_item.mm",
     "badge_view_controller.h",
     "badge_view_controller.mm",
   ]
   deps = [
     ":public",
+    "resources:incognito_badge",
     "//base:base",
     "//ios/chrome/browser/infobars:badge",
     "//ios/chrome/browser/infobars:public",
@@ -40,5 +43,6 @@
     "//ios/chrome/browser/web_state_list",
     "//ios/chrome/common/colors",
     "//ios/chrome/common/ui_util",
+    "//ios/web/public",
   ]
 }
diff --git a/ios/chrome/browser/ui/badges/badge_button_factory.mm b/ios/chrome/browser/ui/badges/badge_button_factory.mm
index 98e6a15..249f634 100644
--- a/ios/chrome/browser/ui/badges/badge_button_factory.mm
+++ b/ios/chrome/browser/ui/badges/badge_button_factory.mm
@@ -36,6 +36,8 @@
       break;
     case BadgeType::kBadgeTypePasswordUpdate:
       return [self passwordsUpdateBadgeButton];
+    case BadgeType::kBadgeTypeIncognito:
+      return [self incognitoBadgeButton];
     case BadgeType::kBadgeTypeNone:
       NOTREACHED() << "A badge should not have kBadgeTypeNone";
       return nil;
@@ -64,6 +66,17 @@
   return button;
 }
 
+- (BadgeButton*)incognitoBadgeButton {
+  BadgeButton* button = [self createButtonForType:BadgeType::kBadgeTypeIncognito
+                                       imageNamed:@"incognito_badge"];
+  UIImage* image = [[UIImage imageNamed:@"incognito_badge"]
+      imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
+  [button setImage:image forState:UIControlStateDisabled];
+  button.accessibilityTraits &= ~UIAccessibilityTraitButton;
+  button.enabled = NO;
+  return button;
+}
+
 - (BadgeButton*)createButtonForType:(BadgeType)badgeType
                          imageNamed:(NSString*)imageName {
   BadgeButton* button = [BadgeButton badgeButtonWithType:badgeType];
@@ -72,6 +85,9 @@
   [button setImage:image forState:UIControlStateNormal];
   button.translatesAutoresizingMaskIntoConstraints = NO;
   button.imageView.contentMode = UIViewContentModeScaleAspectFit;
+  [NSLayoutConstraint
+      activateConstraints:@[ [button.widthAnchor
+                              constraintEqualToAnchor:button.heightAnchor] ]];
   return button;
 }
 
diff --git a/ios/chrome/browser/ui/badges/badge_mediator.mm b/ios/chrome/browser/ui/badges/badge_mediator.mm
index 7968da1b..9430b004 100644
--- a/ios/chrome/browser/ui/badges/badge_mediator.mm
+++ b/ios/chrome/browser/ui/badges/badge_mediator.mm
@@ -9,8 +9,10 @@
 #import "ios/chrome/browser/infobars/infobar_type.h"
 #import "ios/chrome/browser/ui/badges/badge_consumer.h"
 #import "ios/chrome/browser/ui/badges/badge_item.h"
+#import "ios/chrome/browser/ui/badges/badge_static_item.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h"
+#include "ios/web/public/browser_state.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -109,6 +111,11 @@
   NSArray* infobar_badges_array =
       [NSArray arrayWithObjects:&infobar_badges[0] count:infobar_badges.size()];
   [self.consumer setupWithBadges:infobar_badges_array];
+  if (newWebState->GetBrowserState()->IsOffTheRecord()) {
+    BadgeStaticItem* incognitoItem = [[BadgeStaticItem alloc]
+        initWithBadgeType:BadgeType::kBadgeTypeIncognito];
+    [self.consumer addBadge:incognitoItem];
+  }
 }
 
 @end
diff --git a/ios/chrome/browser/ui/badges/badge_static_item.h b/ios/chrome/browser/ui/badges/badge_static_item.h
new file mode 100644
index 0000000..6344645
--- /dev/null
+++ b/ios/chrome/browser/ui/badges/badge_static_item.h
@@ -0,0 +1,20 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_BADGES_BADGE_STATIC_ITEM_H_
+#define IOS_CHROME_BROWSER_UI_BADGES_BADGE_STATIC_ITEM_H_
+
+#import "ios/chrome/browser/ui/badges/badge_item.h"
+
+// Holds properties and values needed to configure an BadgeButton that is not
+// tappable.
+@interface BadgeStaticItem : NSObject <BadgeItem>
+
+- (instancetype)initWithBadgeType:(BadgeType)badgeType
+    NS_DESIGNATED_INITIALIZER;
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_BADGES_BADGE_STATIC_ITEM_H_
diff --git a/ios/chrome/browser/ui/badges/badge_static_item.mm b/ios/chrome/browser/ui/badges/badge_static_item.mm
new file mode 100644
index 0000000..deb3fa8
--- /dev/null
+++ b/ios/chrome/browser/ui/badges/badge_static_item.mm
@@ -0,0 +1,42 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/badges/badge_static_item.h"
+
+#import "ios/chrome/browser/ui/badges/badge_type.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@interface BadgeStaticItem ()
+
+// The BadgeType of this item.
+@property(nonatomic, assign) BadgeType badgeType;
+
+@end
+
+@implementation BadgeStaticItem
+// Synthesized from protocol.
+@synthesize tappable = _tappable;
+// Sythesized from protocol.
+@synthesize accepted = _accepted;
+
+- (instancetype)initWithBadgeType:(BadgeType)badgeType {
+  self = [super init];
+  if (self) {
+    _badgeType = badgeType;
+    _tappable = NO;
+    _accepted = NO;
+  }
+  return self;
+}
+
+#pragma mark - BadgeItem
+
+- (BadgeType)badgeType {
+  return _badgeType;
+}
+
+@end
diff --git a/ios/chrome/browser/ui/badges/badge_type.h b/ios/chrome/browser/ui/badges/badge_type.h
index c676a2b8..1bca959 100644
--- a/ios/chrome/browser/ui/badges/badge_type.h
+++ b/ios/chrome/browser/ui/badges/badge_type.h
@@ -15,6 +15,8 @@
   kBadgeTypePasswordSave = 1,
   // Badge type for the Update Passwords Infobar.
   kBadgeTypePasswordUpdate = 2,
+  // Badge type for the Incognito Badge.
+  kBadgeTypeIncognito = 3,
 };
 
 #endif  // IOS_CHROME_BROWSER_UI_BADGES_BADGE_TYPE_H_
diff --git a/ios/chrome/browser/ui/badges/badge_view_controller.mm b/ios/chrome/browser/ui/badges/badge_view_controller.mm
index 89cdd92..618cd57 100644
--- a/ios/chrome/browser/ui/badges/badge_view_controller.mm
+++ b/ios/chrome/browser/ui/badges/badge_view_controller.mm
@@ -20,14 +20,20 @@
 // Button factory.
 @property(nonatomic, strong) BadgeButtonFactory* buttonFactory;
 
-// Badge button to show when FullScreen is in expanded mode (i.e. when the
+// BadgeButton to show when in FullScreen (i.e. when the
 // toolbars are expanded). Setting this property will add the button to the
-// view hierarchy.
+// StackView.
 @property(nonatomic, strong) BadgeButton* displayedBadge;
 
+// BadgeButton to show in both FullScreen and non FullScreen.
+@property(nonatomic, strong) BadgeButton* fullScreenBadge;
+
 // Array of all available badges.
 @property(nonatomic, strong) NSMutableArray<BadgeButton*>* badges;
 
+// StackView holding the displayedBadge and fullScreenBadge.
+@property(nonatomic, strong) UIStackView* stackView;
+
 @end
 
 @implementation BadgeViewController
@@ -39,6 +45,11 @@
   actionHandler.dispatcher = self.dispatcher;
   self.buttonFactory =
       [[BadgeButtonFactory alloc] initWithActionHandler:actionHandler];
+  self.stackView = [[UIStackView alloc] init];
+  self.stackView.translatesAutoresizingMaskIntoConstraints = NO;
+  self.stackView.axis = UILayoutConstraintAxisHorizontal;
+  [self.view addSubview:self.stackView];
+  AddSameConstraints(self.view, self.stackView);
 }
 
 #pragma mark - Protocols
@@ -49,7 +60,7 @@
   if (!self.badges) {
     self.badges = [[NSMutableArray alloc] init];
   }
-  [self.displayedBadge removeFromSuperview];
+  self.fullScreenBadge = nil;
   self.displayedBadge = nil;
   [self.badges removeAllObjects];
   for (id<BadgeItem> item in badges) {
@@ -63,11 +74,17 @@
 }
 
 - (void)addBadge:(id<BadgeItem>)badgeItem {
+  BadgeButton* newButton =
+      [self.buttonFactory getBadgeButtonForBadgeType:badgeItem.badgeType];
+  // The incognito badge is one that must be visible at all times and persist
+  // when fullscreen is expanded and collapsed.
+  if (badgeItem.badgeType == BadgeType::kBadgeTypeIncognito) {
+    self.fullScreenBadge = newButton;
+    return;
+  }
   if (!self.badges) {
     self.badges = [[NSMutableArray alloc] init];
   }
-  BadgeButton* newButton =
-      [self.buttonFactory getBadgeButtonForBadgeType:badgeItem.badgeType];
   // No need to animate this change since it is the initial state.
   [newButton setAccepted:badgeItem.accepted animated:NO];
   [self.badges addObject:newButton];
@@ -103,25 +120,25 @@
 #pragma mark - Getter/Setter
 
 - (void)setDisplayedBadge:(BadgeButton*)badgeButton {
+  [self.stackView removeArrangedSubview:_displayedBadge];
   [_displayedBadge removeFromSuperview];
   if (!badgeButton) {
     _displayedBadge = nil;
     return;
   }
-
   _displayedBadge = badgeButton;
-  [self.view addSubview:_displayedBadge];
-  [NSLayoutConstraint activateConstraints:@[
-    [_displayedBadge.widthAnchor
-        constraintEqualToAnchor:_displayedBadge.heightAnchor],
-    [_displayedBadge.topAnchor constraintEqualToAnchor:self.view.topAnchor],
-    [_displayedBadge.bottomAnchor
-        constraintEqualToAnchor:self.view.bottomAnchor],
-    [_displayedBadge.leadingAnchor
-        constraintEqualToAnchor:self.view.leadingAnchor],
-    [_displayedBadge.trailingAnchor
-        constraintEqualToAnchor:self.view.trailingAnchor],
-  ]];
+  [self.stackView addArrangedSubview:_displayedBadge];
+}
+
+- (void)setFullScreenBadge:(BadgeButton*)fullScreenBadge {
+  [self.stackView removeArrangedSubview:_fullScreenBadge];
+  [_fullScreenBadge removeFromSuperview];
+  if (!fullScreenBadge) {
+    _fullScreenBadge = nil;
+    return;
+  }
+  _fullScreenBadge = fullScreenBadge;
+  [self.stackView insertArrangedSubview:_fullScreenBadge atIndex:0];
 }
 
 #pragma mark - Helpers
diff --git a/ios/chrome/browser/ui/badges/resources/BUILD.gn b/ios/chrome/browser/ui/badges/resources/BUILD.gn
new file mode 100644
index 0000000..4f30b86
--- /dev/null
+++ b/ios/chrome/browser/ui/badges/resources/BUILD.gn
@@ -0,0 +1,13 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ios/asset_catalog.gni")
+
+imageset("incognito_badge") {
+  sources = [
+    "incognito_badge.imageset/Contents.json",
+    "incognito_badge.imageset/incognito_badge@2x.png",
+    "incognito_badge.imageset/incognito_badge@3x.png",
+  ]
+}
diff --git a/ios/chrome/browser/ui/badges/resources/incognito_badge.imageset/Contents.json b/ios/chrome/browser/ui/badges/resources/incognito_badge.imageset/Contents.json
new file mode 100644
index 0000000..1b85dab
--- /dev/null
+++ b/ios/chrome/browser/ui/badges/resources/incognito_badge.imageset/Contents.json
@@ -0,0 +1,18 @@
+{
+    "images": [
+        {
+            "idiom": "universal",
+            "scale": "2x",
+            "filename": "incognito_badge@2x.png"
+        },
+        {
+            "idiom": "universal",
+            "scale": "3x",
+            "filename": "incognito_badge@3x.png"
+        }
+    ],
+    "info": {
+        "version": 1,
+        "author": "xcode"
+    }
+}
diff --git a/ios/chrome/browser/ui/badges/resources/incognito_badge.imageset/incognito_badge@2x.png b/ios/chrome/browser/ui/badges/resources/incognito_badge.imageset/incognito_badge@2x.png
new file mode 100644
index 0000000..2f5062d
--- /dev/null
+++ b/ios/chrome/browser/ui/badges/resources/incognito_badge.imageset/incognito_badge@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/badges/resources/incognito_badge.imageset/incognito_badge@3x.png b/ios/chrome/browser/ui/badges/resources/incognito_badge.imageset/incognito_badge@3x.png
new file mode 100644
index 0000000..3750f4a
--- /dev/null
+++ b/ios/chrome/browser/ui/badges/resources/incognito_badge.imageset/incognito_badge@3x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.mm
index 6ac804b..2c2e6a1 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.mm
@@ -8,7 +8,7 @@
 #import "ios/chrome/browser/ui/util/i18n_string.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
-#import "ios/chrome/common/colors/UIColor+cr_semantic_colors.h"
+#import "ios/chrome/common/colors/semantic_color_names.h"
 #import "ios/chrome/common/favicon/favicon_view.h"
 #import "ios/chrome/common/ui_util/constraints_ui_util.h"
 #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
@@ -30,10 +30,6 @@
 // Name of the icon displayed when there is not image but one should be
 // displayed.
 NSString* const kNoImageIconName = @"content_suggestions_no_image";
-// No image icon percentage of white.
-const CGFloat kNoImageIconWhite = 0.38;
-// No image background percentage of white.
-const CGFloat kNoImageBackgroundWhite = 0.95;
 // Duration of the animation to display the image.
 const CGFloat kAnimationDuration = 0.3;
 }
@@ -104,17 +100,16 @@
     [_imageContainer addSubview:_noImageIcon];
     [_imageContainer addSubview:_contentImageView];
 
-    _imageContainer.backgroundColor =
-        [UIColor colorWithWhite:kNoImageBackgroundWhite alpha:1];
+    _imageContainer.backgroundColor = [UIColor colorNamed:kGrey100Color];
     _noImageIcon.image = [[UIImage imageNamed:kNoImageIconName]
         imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
-    [_noImageIcon
-        setTintColor:[UIColor colorWithWhite:kNoImageIconWhite alpha:1]];
+    _noImageIcon.tintColor = [UIColor colorNamed:kGrey400Color];
 
     [[self class] configureTitleLabel:_titleLabel];
     _additionalInformationLabel.font = [[self class] additionalInformationFont];
     _faviconView.font = [[MDCTypography fontLoader] mediumFontOfSize:10];
-    _additionalInformationLabel.textColor = UIColor.cr_secondaryLabelColor;
+    _additionalInformationLabel.textColor =
+        [UIColor colorNamed:kTextSecondaryColor];
 
     [self applyConstraints];
   }
@@ -124,7 +119,7 @@
 - (void)setHighlighted:(BOOL)highlighted {
   [super setHighlighted:highlighted];
   self.contentView.backgroundColor =
-      highlighted ? [UIColor colorWithWhite:0 alpha:0.05] : nil;
+      highlighted ? [UIColor colorNamed:kTableViewRowHighlightColor] : nil;
 }
 
 - (void)setContentImage:(UIImage*)image animated:(BOOL)animated {
@@ -376,7 +371,7 @@
 
 // Configures the |titleLabel|.
 + (void)configureTitleLabel:(UILabel*)titleLabel {
-  titleLabel.textColor = UIColor.cr_labelColor;
+  titleLabel.textColor = [UIColor colorNamed:kTextPrimaryColor];
   UIFontDescriptor* descriptor = [[UIFontDescriptor
       preferredFontDescriptorWithTextStyle:UIFontTextStyleSubheadline]
       fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold];
diff --git a/ios/chrome/browser/ui/download/download_manager_egtest.mm b/ios/chrome/browser/ui/download/download_manager_egtest.mm
index fe5a101..fbd01bc 100644
--- a/ios/chrome/browser/ui/download/download_manager_egtest.mm
+++ b/ios/chrome/browser/ui/download/download_manager_egtest.mm
@@ -174,9 +174,7 @@
 - (void)testDownloadInNewTab {
   // TODO(crbug.com/989550) Disable broken context menu tests on Xc11b5.
   if (@available(iOS 13, *)) {
-    if ([ChromeEarlGrey isIPadIdiom]) {
-      EARL_GREY_TEST_DISABLED(@"Test disabled on iPad.");
-    }
+    EARL_GREY_TEST_DISABLED(@"Test disabled on iOS13.");
   }
 
   [ChromeEarlGrey loadURL:self.testServer->GetURL("/")];
diff --git a/ios/chrome/browser/ui/history/BUILD.gn b/ios/chrome/browser/ui/history/BUILD.gn
index 7d28dd5a..bdab756 100644
--- a/ios/chrome/browser/ui/history/BUILD.gn
+++ b/ios/chrome/browser/ui/history/BUILD.gn
@@ -27,6 +27,7 @@
     "//ios/chrome/browser/ui/context_menu",
     "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
     "//ios/chrome/browser/ui/table_view",
+    "//ios/chrome/browser/ui/table_view:feature_flags",
     "//ios/chrome/browser/ui/util",
   ]
   libs = [
diff --git a/ios/chrome/browser/ui/history/history_coordinator.mm b/ios/chrome/browser/ui/history/history_coordinator.mm
index 7f5b167b..37b6a74 100644
--- a/ios/chrome/browser/ui/history/history_coordinator.mm
+++ b/ios/chrome/browser/ui/history/history_coordinator.mm
@@ -16,6 +16,7 @@
 #include "ios/chrome/browser/ui/history/history_table_view_controller.h"
 #import "ios/chrome/browser/ui/history/history_transitioning_delegate.h"
 #include "ios/chrome/browser/ui/history/ios_browsing_history_driver.h"
+#import "ios/chrome/browser/ui/table_view/feature_flags.h"
 #import "ios/chrome/browser/ui/table_view/table_view_navigation_controller.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
 
@@ -86,12 +87,28 @@
   self.historyTableViewController.localDispatcher = self;
   self.historyTableViewController.presentationDelegate =
       self.presentationDelegate;
-  self.historyTransitioningDelegate =
-      [[HistoryTransitioningDelegate alloc] init];
-  self.historyNavigationController.transitioningDelegate =
-      self.historyTransitioningDelegate;
-  [self.historyNavigationController
-      setModalPresentationStyle:UIModalPresentationCustom];
+
+  BOOL useCustomPresentation = YES;
+  if (IsCollectionsCardPresentationStyleEnabled()) {
+    if (@available(iOS 13, *)) {
+#if defined(__IPHONE_13_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0)
+      [self.historyNavigationController
+          setModalPresentationStyle:UIModalPresentationFormSheet];
+      self.historyNavigationController.presentationController.delegate =
+          self.historyTableViewController;
+      useCustomPresentation = NO;
+#endif
+    }
+  }
+
+  if (useCustomPresentation) {
+    self.historyTransitioningDelegate =
+        [[HistoryTransitioningDelegate alloc] init];
+    self.historyNavigationController.transitioningDelegate =
+        self.historyTransitioningDelegate;
+    [self.historyNavigationController
+        setModalPresentationStyle:UIModalPresentationCustom];
+  }
   [self.baseViewController
       presentViewController:self.historyNavigationController
                    animated:YES
diff --git a/ios/chrome/browser/ui/history/history_table_view_controller.h b/ios/chrome/browser/ui/history/history_table_view_controller.h
index 4ce8eef..7847b787 100644
--- a/ios/chrome/browser/ui/history/history_table_view_controller.h
+++ b/ios/chrome/browser/ui/history/history_table_view_controller.h
@@ -22,7 +22,8 @@
 
 // ChromeTableViewController for displaying history items.
 @interface HistoryTableViewController
-    : ChromeTableViewController<HistoryConsumer>
+    : ChromeTableViewController <HistoryConsumer,
+                                 UIAdaptivePresentationControllerDelegate>
 // The ViewController's BrowserState.
 @property(nonatomic, assign) ios::ChromeBrowserState* browserState;
 // Abstraction to communicate with HistoryService and WebHistoryService.
diff --git a/ios/chrome/browser/ui/history/history_table_view_controller.mm b/ios/chrome/browser/ui/history/history_table_view_controller.mm
index 0d238cb6..5993b2d 100644
--- a/ios/chrome/browser/ui/history/history_table_view_controller.mm
+++ b/ios/chrome/browser/ui/history/history_table_view_controller.mm
@@ -167,6 +167,7 @@
   // Add a tableFooterView in order to disable separators at the bottom of the
   // tableView.
   self.tableView.tableFooterView = [[UIView alloc] init];
+  self.tableView.accessibilityIdentifier = kHistoryTableViewIdentifier;
 
   // ContextMenu gesture recognizer.
   UILongPressGestureRecognizer* longPressRecognizer = [
@@ -475,6 +476,24 @@
   [self updateEntriesStatusMessage];
 }
 
+#pragma mark UIAdaptivePresentationControllerDelegate
+
+- (void)presentationControllerWillDismiss:
+    (UIPresentationController*)presentationController {
+  if (self.searchInProgress) {
+    // Dismiss the keyboard if trying to dismiss the VC so the keyboard doesn't
+    // linger until the VC dismissal has completed.
+    [self.searchController.searchBar endEditing:YES];
+  }
+}
+
+- (void)presentationControllerDidDismiss:
+    (UIPresentationController*)presentationController {
+  // Call the localDispatcher dismissHistoryWithCompletion to clean up state and
+  // stop the Coordinator.
+  [self.localDispatcher dismissHistoryWithCompletion:nil];
+}
+
 #pragma mark - History Data Updates
 
 // Search history for text |query| and display the results. |query| may be nil.
diff --git a/ios/chrome/browser/ui/history/history_ui_constants.h b/ios/chrome/browser/ui/history/history_ui_constants.h
index f155ea5c..3dbe6c4c 100644
--- a/ios/chrome/browser/ui/history/history_ui_constants.h
+++ b/ios/chrome/browser/ui/history/history_ui_constants.h
@@ -7,6 +7,8 @@
 
 #import <Foundation/Foundation.h>
 
+// Accessibility identifier for the History TableView.
+extern NSString* const kHistoryTableViewIdentifier;
 // Accessibility identifier of the search controller search bar.
 extern NSString* const kHistorySearchControllerSearchBarIdentifier;
 // Accessibility identifier of the navigation controller done button.
@@ -19,7 +21,7 @@
 extern NSString* const kHistoryToolbarEditButtonIdentifier;
 // Accessibility identifier of the cancel toolbar button.
 extern NSString* const kHistoryToolbarCancelButtonIdentifier;
-// Accessibility ID for the scrim over TableView.
+// Accessibility identifier for the scrim over TableView.
 extern NSString* const kHistorySearchScrimIdentifier;
 
 #endif  // IOS_CHROME_BROWSER_UI_HISTORY_HISTORY_UI_CONSTANTS_H_
diff --git a/ios/chrome/browser/ui/history/history_ui_constants.mm b/ios/chrome/browser/ui/history/history_ui_constants.mm
index 216d36fc..c41fe3c 100644
--- a/ios/chrome/browser/ui/history/history_ui_constants.mm
+++ b/ios/chrome/browser/ui/history/history_ui_constants.mm
@@ -8,6 +8,7 @@
 #error "This file requires ARC support."
 #endif
 
+NSString* const kHistoryTableViewIdentifier = @"kHistoryTableViewIdentifier";
 NSString* const kHistorySearchControllerSearchBarIdentifier =
     @"kHistorySearchControllerSearchBarIdentifier";
 NSString* const kHistoryNavigationControllerDoneButtonIdentifier =
diff --git a/ios/chrome/browser/ui/history/history_ui_egtest.mm b/ios/chrome/browser/ui/history/history_ui_egtest.mm
index 1d5e421..e1d307e 100644
--- a/ios/chrome/browser/ui/history/history_ui_egtest.mm
+++ b/ios/chrome/browser/ui/history/history_ui_egtest.mm
@@ -404,6 +404,62 @@
                  _URL1.spec().c_str());
 }
 
+// Tests that the VC can be dismissed by swiping down.
+- (void)testSwipeDownDismiss {
+  if (!base::ios::IsRunningOnOrLater(13, 0, 0)) {
+    EARL_GREY_TEST_SKIPPED(@"Test disabled on iOS 12 and lower.");
+  }
+  [self loadTestURLs];
+  [self openHistoryPanel];
+
+  // Check that the TableView is presented.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          kHistoryTableViewIdentifier)]
+      assertWithMatcher:grey_notNil()];
+
+  // Swipe TableView down.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          kHistoryTableViewIdentifier)]
+      performAction:grey_swipeFastInDirection(kGREYDirectionDown)];
+
+  // Check that the TableView has been dismissed.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          kHistoryTableViewIdentifier)]
+      assertWithMatcher:grey_nil()];
+}
+
+// Tests that the VC can be dismissed by swiping down while its searching.
+- (void)testSwipeDownDismissWhileSearching {
+  if (!base::ios::IsRunningOnOrLater(13, 0, 0)) {
+    EARL_GREY_TEST_SKIPPED(@"Test disabled on iOS 12 and lower.");
+  }
+  [self loadTestURLs];
+  [self openHistoryPanel];
+
+  // Check that the TableView is presented.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          kHistoryTableViewIdentifier)]
+      assertWithMatcher:grey_notNil()];
+
+  // Search for the first URL.
+  [[EarlGrey selectElementWithMatcher:SearchIconButton()]
+      performAction:grey_tap()];
+  NSString* searchString =
+      [NSString stringWithFormat:@"%s", _URL1.path().c_str()];
+  [[EarlGrey selectElementWithMatcher:SearchIconButton()]
+      performAction:grey_typeText(searchString)];
+
+  // Swipe TableView down.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          kHistoryTableViewIdentifier)]
+      performAction:grey_swipeFastInDirection(kGREYDirectionDown)];
+
+  // Check that the TableView has been dismissed.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          kHistoryTableViewIdentifier)]
+      assertWithMatcher:grey_nil()];
+}
+
 // Navigates to history and checks elements for accessibility.
 - (void)testAccessibilityOnHistory {
   [self loadTestURLs];
diff --git a/ios/chrome/browser/ui/page_info/BUILD.gn b/ios/chrome/browser/ui/page_info/BUILD.gn
index c7548ae1..6003459 100644
--- a/ios/chrome/browser/ui/page_info/BUILD.gn
+++ b/ios/chrome/browser/ui/page_info/BUILD.gn
@@ -5,8 +5,6 @@
 source_set("page_info") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
-    "page_info_constants.h",
-    "page_info_constants.mm",
     "page_info_model.cc",
     "page_info_model.h",
     "page_info_model_observer.h",
@@ -36,9 +34,20 @@
     "//ui/gfx",
     "//url",
   ]
+  public_deps = [
+    ":constants",
+  ]
   libs = [ "UIKit.framework" ]
 }
 
+source_set("constants") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [
+    "page_info_constants.h",
+    "page_info_constants.mm",
+  ]
+}
+
 source_set("coordinator") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
@@ -66,6 +75,7 @@
 
 source_set("eg_tests") {
   configs += [ "//build/config/compiler:enable_arc" ]
+  defines = [ "CHROME_EARL_GREY_1" ]
   testonly = true
   sources = [
     "page_info_egtest.mm",
@@ -75,6 +85,31 @@
     "//ios/chrome/browser/ui/popup_menu:constants",
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/test/earl_grey:test_support",
+    "//ios/testing/earl_grey:earl_grey_support",
+  ]
+  libs = [
+    "UIKit.framework",
+    "XCTest.framework",
+  ]
+}
+
+source_set("eg2_tests") {
+  defines = [ "CHROME_EARL_GREY_2" ]
+  configs += [
+    "//build/config/compiler:enable_arc",
+    "//build/config/ios:xctest_config",
+  ]
+  testonly = true
+  sources = [
+    "page_info_egtest.mm",
+  ]
+  deps = [
+    ":constants",
+    "//ios/chrome/browser/ui/popup_menu:constants",
+    "//ios/chrome/test/earl_grey:eg_test_support+eg2",
+    "//ios/testing/earl_grey:eg_test_support+eg2",
+    "//ios/third_party/earl_grey2:test_lib",
+    "//ui/base",
   ]
   libs = [
     "UIKit.framework",
diff --git a/ios/chrome/browser/ui/page_info/page_info_egtest.mm b/ios/chrome/browser/ui/page_info/page_info_egtest.mm
index 1e8c6fc..57ed9c4 100644
--- a/ios/chrome/browser/ui/page_info/page_info_egtest.mm
+++ b/ios/chrome/browser/ui/page_info/page_info_egtest.mm
@@ -2,16 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import <EarlGrey/EarlGrey.h>
 #import <UIKit/UIKit.h>
 #import <XCTest/XCTest.h>
 
 #import "ios/chrome/browser/ui/page_info/page_info_constants.h"
 #import "ios/chrome/browser/ui/popup_menu/popup_menu_constants.h"
-#include "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
 #import "ios/chrome/test/earl_grey/chrome_test_case.h"
+#import "ios/testing/earl_grey/earl_grey_test.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -31,8 +30,14 @@
   }
 
   if ([[UIDevice currentDevice] orientation] != UIDeviceOrientationPortrait) {
+#if defined(CHROME_EARL_GREY_1)
     [EarlGrey rotateDeviceToOrientation:UIDeviceOrientationPortrait
                              errorOrNil:nil];
+#elif defined(CHROME_EARL_GREY_2)
+    [EarlGrey rotateDeviceToOrientation:UIDeviceOrientationPortrait error:nil];
+#else
+#error Neither CHROME_EARL_GREY_1 nor CHROME_EARL_GREY_2 are defined
+#endif
   }
 
   [ChromeEarlGrey loadURL:GURL("https://invalid")];
@@ -50,8 +55,15 @@
                                           kPageInfoViewAccessibilityIdentifier)]
       assertWithMatcher:grey_sufficientlyVisible()];
 
+#if defined(CHROME_EARL_GREY_1)
   [EarlGrey rotateDeviceToOrientation:UIDeviceOrientationLandscapeRight
                            errorOrNil:nil];
+#elif defined(CHROME_EARL_GREY_2)
+  [EarlGrey rotateDeviceToOrientation:UIDeviceOrientationLandscapeRight
+                                error:nil];
+#else
+#error Neither CHROME_EARL_GREY_1 nor CHROME_EARL_GREY_2 are defined
+#endif
 
   // Expect that the page info view has disappeared.
   [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
diff --git a/ios/chrome/browser/ui/payments/payment_request_picker_view_controller.mm b/ios/chrome/browser/ui/payments/payment_request_picker_view_controller.mm
index d54a210..dff0702 100644
--- a/ios/chrome/browser/ui/payments/payment_request_picker_view_controller.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_picker_view_controller.mm
@@ -96,7 +96,6 @@
 
   self.tableView.delegate = self;
 
-  [self updateTableInset];
   self.tableView.estimatedRowHeight = MDCCellDefaultOneLineHeight;
   self.tableView.rowHeight = UITableViewAutomaticDimension;
   self.tableView.accessibilityIdentifier =
@@ -133,11 +132,6 @@
   [self.appBarViewController didMoveToParentViewController:self];
 }
 
-- (void)viewSafeAreaInsetsDidChange {
-  [super viewSafeAreaInsetsDidChange];
-  [self updateTableInset];
-}
-
 - (UIViewController*)childViewControllerForStatusBarHidden {
   return self.appBarViewController;
 }
@@ -274,26 +268,6 @@
 
 #pragma mark - Private
 
-- (void)updateTableInset {
-  const bool isFullScreen =
-      !IsIPadIdiom() || ([self navigationController].modalPresentationStyle !=
-                         UIModalPresentationFormSheet);
-
-  if (isFullScreen && [self navigationController].navigationBarHidden) {
-    // TODO(crbug.com/767428): When shown full screen, the UITableViewController
-    // uses the full screen even when the status bar is present, but insets the
-    // section headers by the size of the status bar. This will inset the
-    // content by the same amount, to ensure they line up properly. Also insets
-    // by one more pixel to hide the one pixel gap left in between the
-    // navigation bar and the UITableView.
-    CGFloat topInset = self.view.safeAreaInsets.top;
-    const UIEdgeInsets statusBarInset =
-        UIEdgeInsetsMake(-1 - topInset, 0, 0, 0);
-    self.tableView.contentInset = statusBarInset;
-    self.tableView.scrollIndicatorInsets = statusBarInset;
-  }
-}
-
 - (void)onBack {
   [self.delegate paymentRequestPickerViewControllerDidFinish:self];
 }
diff --git a/ios/chrome/browser/ui/recent_tabs/BUILD.gn b/ios/chrome/browser/ui/recent_tabs/BUILD.gn
index c0ecfa9..e4560dc 100644
--- a/ios/chrome/browser/ui/recent_tabs/BUILD.gn
+++ b/ios/chrome/browser/ui/recent_tabs/BUILD.gn
@@ -31,6 +31,7 @@
     "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
     "//ios/chrome/browser/ui/ntp",
     "//ios/chrome/browser/ui/table_view",
+    "//ios/chrome/browser/ui/table_view:feature_flags",
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/browser/url_loading",
     "//ui/base",
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm
index 2775ce36..66c2e75 100644
--- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm
@@ -12,6 +12,7 @@
 #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_presentation_delegate.h"
 #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.h"
 #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_transitioning_delegate.h"
+#import "ios/chrome/browser/ui/table_view/feature_flags.h"
 #import "ios/chrome/browser/ui/table_view/table_view_navigation_controller.h"
 #import "ios/chrome/browser/ui/table_view/table_view_navigation_controller_constants.h"
 #import "ios/chrome/browser/url_loading/url_loading_params.h"
@@ -83,12 +84,29 @@
   self.recentTabsNavigationController = [[TableViewNavigationController alloc]
       initWithTable:recentTabsTableViewController];
   self.recentTabsNavigationController.toolbarHidden = YES;
-  self.recentTabsTransitioningDelegate =
-      [[RecentTabsTransitioningDelegate alloc] init];
-  self.recentTabsNavigationController.transitioningDelegate =
-      self.recentTabsTransitioningDelegate;
-  [self.recentTabsNavigationController
-      setModalPresentationStyle:UIModalPresentationCustom];
+
+  BOOL useCustomPresentation = YES;
+  if (IsCollectionsCardPresentationStyleEnabled()) {
+    if (@available(iOS 13, *)) {
+#if defined(__IPHONE_13_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0)
+      [self.recentTabsNavigationController
+          setModalPresentationStyle:UIModalPresentationFormSheet];
+      self.recentTabsNavigationController.presentationController.delegate =
+          recentTabsTableViewController;
+      useCustomPresentation = NO;
+#endif
+    }
+  }
+
+  if (useCustomPresentation) {
+    self.recentTabsTransitioningDelegate =
+        [[RecentTabsTransitioningDelegate alloc] init];
+    self.recentTabsNavigationController.transitioningDelegate =
+        self.recentTabsTransitioningDelegate;
+    [self.recentTabsNavigationController
+        setModalPresentationStyle:UIModalPresentationCustom];
+  }
+
   [self.baseViewController
       presentViewController:self.recentTabsNavigationController
                    animated:YES
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_egtest.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_egtest.mm
index d410a829..3570436 100644
--- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_egtest.mm
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_egtest.mm
@@ -8,6 +8,7 @@
 #import <map>
 #import <string>
 
+#include "base/ios/ios_util.h"
 #include "base/test/scoped_feature_list.h"
 #include "components/strings/grit/components_strings.h"
 #import "ios/chrome/app/main_controller.h"
@@ -241,4 +242,32 @@
       ->RemoveIdentity(identity);
 }
 
+// Tests that the VC can be dismissed by swiping down.
+- (void)testSwipeDownDismiss {
+  if (!base::ios::IsRunningOnOrLater(13, 0, 0)) {
+    EARL_GREY_TEST_SKIPPED(@"Test disabled on iOS 12 and lower.");
+  }
+  OpenRecentTabsPanel();
+
+  // Check that the TableView is presented.
+  [[EarlGrey selectElementWithMatcher:
+                 grey_accessibilityID(
+                     kRecentTabsTableViewControllerAccessibilityIdentifier)]
+      assertWithMatcher:grey_notNil()];
+
+  // Swipe TableView down.
+  [[EarlGrey selectElementWithMatcher:
+                 grey_accessibilityID(
+                     kRecentTabsTableViewControllerAccessibilityIdentifier)]
+      performAction:grey_swipeFastInDirection(kGREYDirectionDown)];
+
+  // Check that the TableView has been dismissed.
+  [[EarlGrey selectElementWithMatcher:
+                 grey_accessibilityID(
+                     kRecentTabsTableViewControllerAccessibilityIdentifier)]
+      assertWithMatcher:grey_nil()];
+
+  [ChromeEarlGrey closeCurrentTab];
+}
+
 @end
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.h b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.h
index 0dc66fb0..1d89ab7 100644
--- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.h
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.h
@@ -21,7 +21,8 @@
 @protocol TableViewFaviconDataSource;
 
 @interface RecentTabsTableViewController
-    : ChromeTableViewController<RecentTabsConsumer>
+    : ChromeTableViewController <RecentTabsConsumer,
+                                 UIAdaptivePresentationControllerDelegate>
 // The coordinator's BrowserState.
 @property(nonatomic, assign) ios::ChromeBrowserState* browserState;
 // The dispatcher used by this ViewController.
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm
index 24c3b26..9bb2bc7 100644
--- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm
@@ -1148,6 +1148,13 @@
   [self.dispatcher showSignin:command baseViewController:self];
 }
 
+#pragma mark - UIAdaptivePresentationControllerDelegate
+- (void)presentationControllerDidDismiss:
+    (UIPresentationController*)presentationController {
+  // Call dismissRecentTabs so the Coordinator cleans up any state it needs to.
+  [self.presentationDelegate dismissRecentTabs];
+}
+
 #pragma mark - Accessibility
 
 - (BOOL)accessibilityPerformEscape {
diff --git a/ios/chrome/browser/ui/signin_interaction/signin_interaction_controller_egtest.mm b/ios/chrome/browser/ui/signin_interaction/signin_interaction_controller_egtest.mm
index 9e1bdb0..9c431800 100644
--- a/ios/chrome/browser/ui/signin_interaction/signin_interaction_controller_egtest.mm
+++ b/ios/chrome/browser/ui/signin_interaction/signin_interaction_controller_egtest.mm
@@ -86,8 +86,10 @@
                                  block:^BOOL {
                                    return browsing_data_removed;
                                  }];
-  GREYAssert([condition waitWithTimeout:base::test::ios::kWaitForActionTimeout],
-             @"Browsing data was not removed.");
+  GREYAssert(
+      [condition
+          waitWithTimeout:base::test::ios::kWaitForClearBrowsingDataTimeout],
+      @"Browsing data was not removed.");
 }
 
 }  // namespace
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_egtest.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_egtest.mm
index c9b6354..7f80b0b8 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_egtest.mm
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_egtest.mm
@@ -158,11 +158,12 @@
 
   [[EarlGrey selectElementWithMatcher:chrome_test_util::ShowTabsButton()]
       performAction:grey_tap()];
-  // Swipe over to Recent Tabs
-  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
-                                          kTabGridScrollViewIdentifier)]
-      performAction:[GREYActions
-                        actionForSwipeFastInDirection:kGREYDirectionLeft]];
+
+  // Switch over to Recent Tabs.
+  [[EarlGrey
+      selectElementWithMatcher:grey_accessibilityID(
+                                   kTabGridRemoteTabsPageButtonIdentifier)]
+      performAction:grey_tap()];
 
   // Tap on "Show History"
   // Undo is available after close all action.
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_link_header_footer_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_link_header_footer_item.mm
index 72ec411..73f5448b 100644
--- a/ios/chrome/browser/ui/table_view/cells/table_view_link_header_footer_item.mm
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_link_header_footer_item.mm
@@ -41,6 +41,7 @@
   [super configureHeaderFooterView:headerFooter withStyler:styler];
 
   headerFooter.linkURL = self.linkURL;
+  headerFooter.accessibilityTraits |= UIAccessibilityTraitLink;
   [headerFooter setText:self.text];
 }
 
@@ -141,4 +142,10 @@
   return NO;
 }
 
+#pragma mark - NSObject(Accessibility)
+
+- (NSString*)accessibilityLabel {
+  return [self.textView.attributedText string];
+}
+
 @end
diff --git a/ios/chrome/browser/ui/toolbar/adaptive_toolbar_egtest.mm b/ios/chrome/browser/ui/toolbar/adaptive_toolbar_egtest.mm
index 0bb265dc..dd930b0d 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive_toolbar_egtest.mm
+++ b/ios/chrome/browser/ui/toolbar/adaptive_toolbar_egtest.mm
@@ -627,9 +627,7 @@
 - (void)testNavigationButtons {
   // TODO(crbug.com/989550) Disable broken context menu tests on Xc11b5.
   if (@available(iOS 13, *)) {
-    if ([ChromeEarlGrey isIPadIdiom]) {
-      EARL_GREY_TEST_DISABLED(@"Test disabled on iPad.");
-    }
+    EARL_GREY_TEST_DISABLED(@"Test disabled on iOS13.");
   }
   // Setup the server.
   self.testServer->RegisterRequestHandler(
diff --git a/ios/chrome/browser/web/tab_order_egtest.mm b/ios/chrome/browser/web/tab_order_egtest.mm
index 28f296a..6912e47 100644
--- a/ios/chrome/browser/web/tab_order_egtest.mm
+++ b/ios/chrome/browser/web/tab_order_egtest.mm
@@ -55,9 +55,7 @@
 - (void)testChildTabOrdering {
   // TODO(crbug.com/989550) Disable broken context menu tests on Xc11b5.
   if (@available(iOS 13, *)) {
-    if ([ChromeEarlGrey isIPadIdiom]) {
-      EARL_GREY_TEST_DISABLED(@"Test disabled on iPad.");
-    }
+    EARL_GREY_TEST_DISABLED(@"Test disabled on iOS13.");
   }
 
   GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");
diff --git a/ios/chrome/test/app/history_test_util.mm b/ios/chrome/test/app/history_test_util.mm
index 3300fbc31..756f5ca 100644
--- a/ios/chrome/test/app/history_test_util.mm
+++ b/ios/chrome/test/app/history_test_util.mm
@@ -27,7 +27,7 @@
                           did_complete = true;
                         }];
   return base::test::ios::WaitUntilConditionOrTimeout(
-      base::test::ios::kWaitForUIElementTimeout, ^{
+      base::test::ios::kWaitForClearBrowsingDataTimeout, ^{
         return did_complete;
       });
 }
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey_ui.mm b/ios/chrome/test/earl_grey/chrome_earl_grey_ui.mm
index 6b560d8d..3296fe8 100644
--- a/ios/chrome/test/earl_grey/chrome_earl_grey_ui.mm
+++ b/ios/chrome/test/earl_grey/chrome_earl_grey_ui.mm
@@ -121,6 +121,21 @@
       performAction:grey_tap()];
   [[EarlGrey selectElementWithMatcher:chrome_test_util::ClearCacheButton()]
       performAction:grey_tap()];
+
+  // Set 'Time Range' to 'All Time'.
+  [[EarlGrey selectElementWithMatcher:
+                 chrome_test_util::ButtonWithAccessibilityLabelId(
+                     IDS_IOS_CLEAR_BROWSING_DATA_TIME_RANGE_SELECTOR_TITLE)]
+      performAction:grey_tap()];
+  [[EarlGrey
+      selectElementWithMatcher:
+          chrome_test_util::ButtonWithAccessibilityLabelId(
+              IDS_IOS_CLEAR_BROWSING_DATA_TIME_RANGE_OPTION_BEGINNING_OF_TIME)]
+      performAction:grey_tap()];
+  [[[EarlGrey
+      selectElementWithMatcher:chrome_test_util::SettingsMenuBackButton()]
+      atIndex:0] performAction:grey_tap()];
+
   [[EarlGrey
       selectElementWithMatcher:chrome_test_util::ClearBrowsingDataButton()]
       performAction:grey_tap()];
@@ -131,6 +146,12 @@
   // data has been finished.
   [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
 
+  // Recheck "Cookies, Site Data" and "Cached Images and Files."
+  [[EarlGrey selectElementWithMatcher:chrome_test_util::ClearCookiesButton()]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:chrome_test_util::ClearCacheButton()]
+      performAction:grey_tap()];
+
   // Include sufficientlyVisible condition for the case of the clear browsing
   // dialog, which also has a "Done" button and is displayed over the history
   // panel.
diff --git a/ios/chrome/test/earl_grey2/BUILD.gn b/ios/chrome/test/earl_grey2/BUILD.gn
index 40dc58a..93e8845 100644
--- a/ios/chrome/test/earl_grey2/BUILD.gn
+++ b/ios/chrome/test/earl_grey2/BUILD.gn
@@ -44,6 +44,7 @@
     "//ios/chrome/browser/ui/omnibox/popup:eg2_tests",
     "//ios/chrome/browser/ui/omnibox/popup/shortcuts:eg2_tests",
     "//ios/chrome/browser/ui/open_in:eg2_tests",
+    "//ios/chrome/browser/ui/page_info:eg2_tests",
     "//ios/chrome/browser/ui/toolbar:eg2_tests",
   ]
 }
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index 561ad69..d673484 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -513,6 +513,10 @@
 const base::Feature kMediaEngagementHTTPSOnly{
     "MediaEngagementHTTPSOnly", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Send events to devtools rather than to chrome://media-internals
+const base::Feature kMediaInspectorLogging{"MediaInspectorLogging",
+                                           base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enables experimental local learning for media.  Adds reporting only; does not
 // change media behavior.
 const base::Feature kMediaLearningExperiment{"MediaLearningExperiment",
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index b8137f35..9d8de56 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -113,6 +113,7 @@
 MEDIA_EXPORT extern const base::Feature kMediaCastOverlayButton;
 MEDIA_EXPORT extern const base::Feature kMediaEngagementBypassAutoplayPolicies;
 MEDIA_EXPORT extern const base::Feature kMediaEngagementHTTPSOnly;
+MEDIA_EXPORT extern const base::Feature kMediaInspectorLogging;
 MEDIA_EXPORT extern const base::Feature kMediaLearningExperiment;
 MEDIA_EXPORT extern const base::Feature kMemoryPressureBasedSourceBufferGC;
 MEDIA_EXPORT extern const base::Feature kChromeosVideoDecoder;
diff --git a/media/base/simple_watch_timer.cc b/media/base/simple_watch_timer.cc
index aa3038fa..83668df 100644
--- a/media/base/simple_watch_timer.cc
+++ b/media/base/simple_watch_timer.cc
@@ -5,6 +5,7 @@
 #include "media/base/simple_watch_timer.h"
 
 #include "base/location.h"
+#include "media/base/timestamp_constants.h"
 
 namespace media {
 
@@ -43,7 +44,11 @@
 
 void SimpleWatchTimer::Tick() {
   base::TimeDelta current_time = get_current_time_cb_.Run();
-  base::TimeDelta duration = current_time - last_current_time_;
+  base::TimeDelta duration;
+  if (last_current_time_ != kNoTimestamp &&
+      last_current_time_ != kInfiniteDuration) {
+    duration = current_time - last_current_time_;
+  }
   last_current_time_ = current_time;
 
   // Accumulate watch time if the duration is reasonable.
diff --git a/media/filters/fuchsia/fuchsia_video_decoder.cc b/media/filters/fuchsia/fuchsia_video_decoder.cc
index de64a4e9..0ab9a43 100644
--- a/media/filters/fuchsia/fuchsia_video_decoder.cc
+++ b/media/filters/fuchsia/fuchsia_video_decoder.cc
@@ -338,7 +338,8 @@
 
  private:
   // Event handlers for |codec_|.
-  void OnStreamFailed(uint64_t stream_lifetime_ordinal);
+  void OnStreamFailed(uint64_t stream_lifetime_ordinal,
+                      fuchsia::media::StreamError error);
   void OnInputConstraints(
       fuchsia::media::StreamBufferConstraints input_constraints);
   void OnFreeInputPacket(fuchsia::media::PacketHeader free_input_packet);
@@ -506,7 +507,7 @@
         OnError();
       });
 
-  codec_.events().OnStreamFailed =
+  codec_.events().OnStreamFailed2 =
       fit::bind_member(this, &FuchsiaVideoDecoder::OnStreamFailed);
   codec_.events().OnInputConstraints =
       fit::bind_member(this, &FuchsiaVideoDecoder::OnInputConstraints);
@@ -578,7 +579,8 @@
   return input_buffers_.size() + 1;
 }
 
-void FuchsiaVideoDecoder::OnStreamFailed(uint64_t stream_lifetime_ordinal) {
+void FuchsiaVideoDecoder::OnStreamFailed(uint64_t stream_lifetime_ordinal,
+                                         fuchsia::media::StreamError error) {
   if (stream_lifetime_ordinal_ != stream_lifetime_ordinal) {
     return;
   }
diff --git a/net/reporting/reporting_uploader.cc b/net/reporting/reporting_uploader.cc
index 3f8acaa..930a49f 100644
--- a/net/reporting/reporting_uploader.cc
+++ b/net/reporting/reporting_uploader.cc
@@ -169,9 +169,8 @@
 
     upload->request->set_method("OPTIONS");
 
-    upload->request->SetLoadFlags(LOAD_DISABLE_CACHE |
-                                  LOAD_DO_NOT_SAVE_COOKIES |
-                                  LOAD_DO_NOT_SEND_COOKIES);
+    upload->request->SetLoadFlags(LOAD_DISABLE_CACHE);
+    upload->request->set_allow_credentials(false);
 
     upload->request->SetExtraRequestHeaderByName(
         HttpRequestHeaders::kOrigin, upload->report_origin.Serialize(), true);
@@ -201,9 +200,8 @@
 
     upload->request->set_method("POST");
 
-    upload->request->SetLoadFlags(LOAD_DISABLE_CACHE |
-                                  LOAD_DO_NOT_SAVE_COOKIES |
-                                  LOAD_DO_NOT_SEND_COOKIES);
+    upload->request->SetLoadFlags(LOAD_DISABLE_CACHE);
+    upload->request->set_allow_credentials(false);
 
     upload->request->SetExtraRequestHeaderByName(
         HttpRequestHeaders::kContentType, kUploadContentType, true);
diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc
index 1a203fc..0a73a41 100644
--- a/net/socket/ssl_client_socket_impl.cc
+++ b/net/socket/ssl_client_socket_impl.cc
@@ -865,8 +865,7 @@
   mode.ConfigureFlag(SSL_MODE_RELEASE_BUFFERS, true);
   mode.ConfigureFlag(SSL_MODE_CBC_RECORD_SPLITTING, true);
 
-  mode.ConfigureFlag(SSL_MODE_ENABLE_FALSE_START,
-                     ssl_config_.false_start_enabled);
+  mode.ConfigureFlag(SSL_MODE_ENABLE_FALSE_START, true);
 
   SSL_set_mode(ssl_.get(), mode.set_mask);
   SSL_clear_mode(ssl_.get(), mode.clear_mask);
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index 9ed7f43..3120803 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -1267,6 +1267,32 @@
   }
 };
 
+// Sends an HTTP request on the socket and reads the response. This may be used
+// to ensure some data has been consumed from the server.
+int MakeHTTPRequest(StreamSocket* socket) {
+  base::StringPiece request = "GET / HTTP/1.0\r\n\r\n";
+  TestCompletionCallback callback;
+  while (!request.empty()) {
+    auto request_buffer =
+        base::MakeRefCounted<StringIOBuffer>(request.as_string());
+    int rv = callback.GetResult(
+        socket->Write(request_buffer.get(), request_buffer->size(),
+                      callback.callback(), TRAFFIC_ANNOTATION_FOR_TESTS));
+    if (rv < 0) {
+      return rv;
+    }
+    request = request.substr(rv);
+  }
+
+  auto response_buffer = base::MakeRefCounted<IOBuffer>(1024);
+  int rv = callback.GetResult(
+      socket->Read(response_buffer.get(), 1024, callback.callback()));
+  if (rv < 0) {
+    return rv;
+  }
+  return OK;
+}
+
 // Provides a response to the 0RTT request indicating whether it was received
 // as early data.
 class ZeroRTTResponse : public test_server::HttpResponse {
@@ -1384,13 +1410,7 @@
 
     // Use the socket for an HTTP request to ensure we've processed the
     // post-handshake TLS 1.3 ticket.
-    constexpr base::StringPiece kRequest = "GET / HTTP/1.0\r\n\r\n";
-    if (kRequest.size() != WriteAndWait(kRequest))
-      return false;
-
-    scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(4096);
-    if (ReadAndWait(buf.get(), 4096) <= 0)
-      return false;
+    EXPECT_THAT(MakeHTTPRequest(ssl_socket_.get()), IsOk());
 
     SSLInfo ssl_info;
     EXPECT_TRUE(GetSSLInfo(&ssl_info));
@@ -1745,14 +1765,10 @@
   int rv = callback.GetResult(transport->Connect(callback.callback()));
   EXPECT_THAT(rv, IsOk());
 
-  // Disable TLS False Start to avoid handshake non-determinism.
-  SSLConfig ssl_config;
-  ssl_config.false_start_enabled = false;
-
   SynchronousErrorStreamSocket* raw_transport = transport.get();
   std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
       std::move(transport), spawned_test_server()->host_port_pair(),
-      ssl_config));
+      SSLConfig()));
 
   raw_transport->SetNextWriteError(ERR_CONNECTION_RESET);
 
@@ -1776,14 +1792,10 @@
   int rv = callback.GetResult(transport->Connect(callback.callback()));
   EXPECT_THAT(rv, IsOk());
 
-  // Disable TLS False Start to avoid handshake non-determinism.
-  SSLConfig ssl_config;
-  ssl_config.false_start_enabled = false;
-
   SynchronousErrorStreamSocket* raw_transport = transport.get();
   std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
       std::move(transport), spawned_test_server()->host_port_pair(),
-      ssl_config));
+      SSLConfig()));
 
   rv = callback.GetResult(sock->Connect(callback.callback()));
   EXPECT_THAT(rv, IsOk());
@@ -1834,13 +1846,9 @@
   int rv = callback.GetResult(transport->Connect(callback.callback()));
   EXPECT_THAT(rv, IsOk());
 
-  // Disable TLS False Start to avoid handshake non-determinism.
-  SSLConfig ssl_config;
-  ssl_config.false_start_enabled = false;
-
   std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
       std::move(transport), spawned_test_server()->host_port_pair(),
-      ssl_config));
+      SSLConfig()));
 
   rv = callback.GetResult(sock->Connect(callback.callback()));
   EXPECT_THAT(rv, IsOk());
@@ -1903,13 +1911,9 @@
   int rv = callback.GetResult(counting_socket->Connect(callback.callback()));
   ASSERT_THAT(rv, IsOk());
 
-  // Disable TLS False Start to avoid handshake non-determinism.
-  SSLConfig ssl_config;
-  ssl_config.false_start_enabled = false;
-
   std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
       std::move(counting_socket), spawned_test_server()->host_port_pair(),
-      ssl_config));
+      SSLConfig()));
 
   rv = callback.GetResult(sock->Connect(callback.callback()));
   ASSERT_THAT(rv, IsOk());
@@ -2008,13 +2012,9 @@
   int rv = callback.GetResult(transport->Connect(callback.callback()));
   EXPECT_THAT(rv, IsOk());
 
-  // Disable TLS False Start to avoid handshake non-determinism.
-  SSLConfig ssl_config;
-  ssl_config.false_start_enabled = false;
-
   std::unique_ptr<SSLClientSocket> sock = CreateSSLClientSocket(
       std::move(transport), spawned_test_server()->host_port_pair(),
-      ssl_config);
+      SSLConfig());
 
   rv = callback.GetResult(sock->Connect(callback.callback()));
   EXPECT_THAT(rv, IsOk());
@@ -2094,13 +2094,9 @@
   int rv = callback.GetResult(transport->Connect(callback.callback()));
   EXPECT_THAT(rv, IsOk());
 
-  // Disable TLS False Start to avoid handshake non-determinism.
-  SSLConfig ssl_config;
-  ssl_config.false_start_enabled = false;
-
   std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
       std::move(transport), spawned_test_server()->host_port_pair(),
-      ssl_config));
+      SSLConfig()));
 
   rv = callback.GetResult(sock->Connect(callback.callback()));
   EXPECT_THAT(rv, IsOk());
@@ -2204,14 +2200,10 @@
   int rv = callback.GetResult(transport->Connect(callback.callback()));
   EXPECT_THAT(rv, IsOk());
 
-  // Disable TLS False Start to ensure the handshake has completed.
-  SSLConfig ssl_config;
-  ssl_config.false_start_enabled = false;
-
   SynchronousErrorStreamSocket* raw_transport = transport.get();
   std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
       std::move(transport), spawned_test_server()->host_port_pair(),
-      ssl_config));
+      SSLConfig()));
 
   rv = callback.GetResult(sock->Connect(callback.callback()));
   EXPECT_THAT(rv, IsOk());
@@ -2241,13 +2233,9 @@
   int rv = callback.GetResult(transport->Connect(callback.callback()));
   EXPECT_THAT(rv, IsOk());
 
-  // Disable TLS False Start to ensure the handshake has completed.
-  SSLConfig ssl_config;
-  ssl_config.false_start_enabled = false;
-
   std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
       std::move(transport), spawned_test_server()->host_port_pair(),
-      ssl_config));
+      SSLConfig()));
 
   rv = callback.GetResult(sock->Connect(callback.callback()));
   EXPECT_THAT(rv, IsOk());
@@ -3223,8 +3211,6 @@
 
   // First, perform a full handshake.
   SSLConfig ssl_config;
-  // Disable TLS False Start to ensure the handshake has completed.
-  ssl_config.false_start_enabled = false;
   ssl_config.alpn_protos.push_back(kProtoHTTP2);
   int rv;
   ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
@@ -3234,6 +3220,10 @@
   EXPECT_EQ(SSLInfo::HANDSHAKE_FULL, ssl_info.handshake_type);
   EXPECT_EQ(kProtoHTTP2, sock_->GetNegotiatedProtocol());
 
+  // TLS 1.2 with False Start and TLS 1.3 cause the ticket to arrive later, so
+  // use the socket to ensure the session ticket has been picked up.
+  EXPECT_THAT(MakeHTTPRequest(sock_.get()), IsOk());
+
   // The next connection should resume; ALPN should be renegotiated.
   ssl_config.alpn_protos.clear();
   ssl_config.alpn_protos.push_back(kProtoHTTP11);
@@ -5766,23 +5756,9 @@
     histograms.ExpectUniqueSample("Net.SSLHandshakeDetails",
                                   GetParam().expected_initial, 1);
 
-    // Use the socket to ensure the session ticket has been picked up.
-    base::StringPiece request = "GET / HTTP/1.0\r\n\r\n";
-    TestCompletionCallback callback;
-    while (!request.empty()) {
-      auto request_buffer =
-          base::MakeRefCounted<StringIOBuffer>(request.as_string());
-      rv = callback.GetResult(
-          sock_->Write(request_buffer.get(), request_buffer->size(),
-                       callback.callback(), TRAFFIC_ANNOTATION_FOR_TESTS));
-      ASSERT_GT(rv, 0);
-      request = request.substr(rv);
-    }
-
-    auto response_buffer = base::MakeRefCounted<IOBuffer>(1024);
-    rv = callback.GetResult(
-        sock_->Read(response_buffer.get(), 1024, callback.callback()));
-    ASSERT_GT(rv, 0);
+    // TLS 1.2 with False Start and TLS 1.3 cause the ticket to arrive later, so
+    // use the socket to ensure the session ticket has been picked up.
+    EXPECT_THAT(MakeHTTPRequest(sock_.get()), IsOk());
   }
 
   // Make a resumption connection.
diff --git a/net/socket/ssl_server_socket_unittest.cc b/net/socket/ssl_server_socket_unittest.cc
index 274ae98..adc2664 100644
--- a/net/socket/ssl_server_socket_unittest.cc
+++ b/net/socket/ssl_server_socket_unittest.cc
@@ -380,8 +380,6 @@
     ASSERT_TRUE(key);
     server_ssl_private_key_ = WrapOpenSSLPrivateKey(bssl::UpRef(key->key()));
 
-    client_ssl_config_.false_start_enabled = false;
-
     // Certificate provided by the host doesn't need authority.
     client_ssl_config_.allowed_bad_certs.emplace_back(
         server_cert_, CERT_STATUS_AUTHORITY_INVALID);
diff --git a/net/ssl/ssl_config.cc b/net/ssl/ssl_config.cc
index fbd71b01..3178d017 100644
--- a/net/ssl/ssl_config.cc
+++ b/net/ssl/ssl_config.cc
@@ -23,7 +23,6 @@
 
 SSLConfig::SSLConfig()
     : early_data_enabled(false),
-      false_start_enabled(true),
       require_ecdhe(false),
       ignore_certificate_errors(false),
       disable_cert_verification_network_fetches(false),
diff --git a/net/ssl/ssl_config.h b/net/ssl/ssl_config.h
index 4be4323..11f360b 100644
--- a/net/ssl/ssl_config.h
+++ b/net/ssl/ssl_config.h
@@ -75,8 +75,6 @@
   // If unsure, do not enable this option.
   bool early_data_enabled;
 
-  bool false_start_enabled;  // True if we'll use TLS False Start.
-
   // If true, causes only ECDHE cipher suites to be enabled.
   bool require_ecdhe;
 
diff --git a/remoting/base/chromium_url_request.cc b/remoting/base/chromium_url_request.cc
index 2ae424c..842d267 100644
--- a/remoting/base/chromium_url_request.cc
+++ b/remoting/base/chromium_url_request.cc
@@ -33,8 +33,7 @@
   resource_request_ = std::make_unique<network::ResourceRequest>();
   resource_request_->url = GURL(url);
   resource_request_->method = request_type;
-  resource_request_->load_flags =
-      net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES;
+  resource_request_->credentials_mode = network::mojom::CredentialsMode::kOmit;
   resource_request_->referrer = GURL("https://chrome.google.com/remotedesktop");
 }
 
diff --git a/services/network/cors/cors_url_loader_factory.cc b/services/network/cors/cors_url_loader_factory.cc
index ebda635..7ca16c3 100644
--- a/services/network/cors/cors_url_loader_factory.cc
+++ b/services/network/cors/cors_url_loader_factory.cc
@@ -36,6 +36,7 @@
     const OriginAccessList* origin_access_list,
     std::unique_ptr<mojom::URLLoaderFactory> network_loader_factory_for_testing)
     : context_(context),
+      is_trusted_(params->is_trusted),
       disable_web_security_(params->disable_web_security),
       process_id_(params->process_id),
       request_initiator_site_lock_(params->request_initiator_site_lock),
@@ -142,6 +143,14 @@
     return false;
   }
 
+  // Reject request with trusted params if factory is not for a trusted
+  // consumer.
+  if (request.trusted_params && !is_trusted_) {
+    mojo::ReportBadMessage(
+        "CorsURLLoaderFactory: Untrusted caller making trusted request");
+    return false;
+  }
+
   // Ensure that renderer requests are covered either by CORS or CORB.
   if (process_id_ != mojom::kBrowserProcessId) {
     switch (request.mode) {
diff --git a/services/network/cors/cors_url_loader_factory.h b/services/network/cors/cors_url_loader_factory.h
index 89616115..4ad1e408 100644
--- a/services/network/cors/cors_url_loader_factory.h
+++ b/services/network/cors/cors_url_loader_factory.h
@@ -77,6 +77,9 @@
   NetworkContext* const context_ = nullptr;
   scoped_refptr<ResourceSchedulerClient> resource_scheduler_client_;
 
+  // If false, ResourceRequests cannot have their |trusted_params| fields set.
+  bool is_trusted_;
+
   // Retained from URLLoaderFactoryParams:
   const bool disable_web_security_;
   const uint32_t process_id_ = mojom::kInvalidProcessId;
diff --git a/services/network/cors/cors_url_loader_unittest.cc b/services/network/cors/cors_url_loader_unittest.cc
index 95962de2..6bc0af7 100644
--- a/services/network/cors/cors_url_loader_unittest.cc
+++ b/services/network/cors/cors_url_loader_unittest.cc
@@ -183,10 +183,11 @@
   }
 
   void CreateLoaderAndStart(const ResourceRequest& request) {
+    test_cors_loader_client_ = std::make_unique<TestURLLoaderClient>();
     cors_url_loader_factory_->CreateLoaderAndStart(
         mojo::MakeRequest(&url_loader_), 0 /* routing_id */, 0 /* request_id */,
         mojom::kURLLoadOptionNone, request,
-        test_cors_loader_client_.CreateInterfacePtr(),
+        test_cors_loader_client_->CreateInterfacePtr(),
         net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
   }
 
@@ -254,9 +255,11 @@
     return test_url_loader_factory_->num_created_loaders();
   }
 
-  const TestURLLoaderClient& client() const { return test_cors_loader_client_; }
+  const TestURLLoaderClient& client() const {
+    return *test_cors_loader_client_;
+  }
   void ClearHasReceivedRedirect() {
-    test_cors_loader_client_.ClearHasReceivedRedirect();
+    test_cors_loader_client_->ClearHasReceivedRedirect();
   }
 
   void RunUntilCreateLoaderAndStartCalled() {
@@ -266,9 +269,9 @@
     run_loop.Run();
     test_url_loader_factory_->SetOnCreateLoaderAndStart({});
   }
-  void RunUntilComplete() { test_cors_loader_client_.RunUntilComplete(); }
+  void RunUntilComplete() { test_cors_loader_client_->RunUntilComplete(); }
   void RunUntilRedirectReceived() {
-    test_cors_loader_client_.RunUntilRedirectReceived();
+    test_cors_loader_client_->RunUntilRedirectReceived();
   }
 
   void AddAllowListEntryForOrigin(const url::Origin& source_origin,
@@ -319,11 +322,11 @@
   }
 
   void ResetFactory(base::Optional<url::Origin> initiator,
-                    uint32_t process_id) {
+                    uint32_t process_id,
+                    bool is_trusted = false) {
     std::unique_ptr<TestURLLoaderFactory> factory =
         std::make_unique<TestURLLoaderFactory>();
     test_url_loader_factory_ = factory->GetWeakPtr();
-
     auto factory_params = network::mojom::URLLoaderFactoryParams::New();
     if (initiator) {
       factory_params->request_initiator_site_lock = *initiator;
@@ -332,6 +335,7 @@
         cloned_patterns.push_back(item.Clone());
       factory_params->factory_bound_allow_patterns = std::move(cloned_patterns);
     }
+    factory_params->is_trusted = is_trusted;
     factory_params->process_id = process_id;
     factory_params->is_corb_enabled = (process_id != mojom::kBrowserProcessId);
     constexpr int kRouteId = 765;
@@ -372,7 +376,7 @@
   mojom::URLLoaderPtr url_loader_;
 
   // TestURLLoaderClient that records callback activities.
-  TestURLLoaderClient test_cors_loader_client_;
+  std::unique_ptr<TestURLLoaderClient> test_cors_loader_client_;
 
   // Holds for allowed origin access lists.
   OriginAccessList origin_access_list_;
@@ -1774,6 +1778,54 @@
           "CorsURLLoaderFactory: unsupported credentials mode on navigation"));
 }
 
+// Make sure than when a request is failed due to having |trusted_params| set
+// and being sent to an untrusted URLLoaderFactory, no CORS request is made.
+TEST_F(CorsURLLoaderTest, TrustedParamsWithUntrustedFactoryFailsBeforeCORS) {
+  // Run the test with a trusted URLLoaderFactory as well, to make sure a CORS
+  // request is in fact made when using a trusted factory.
+  for (bool is_trusted : {false, true}) {
+    ResetFactory(base::nullopt, kRendererProcessId, is_trusted);
+
+    BadMessageTestHelper bad_message_helper;
+
+    ResourceRequest request;
+    request.mode = mojom::RequestMode::kCors;
+    request.credentials_mode = mojom::CredentialsMode::kOmit;
+    request.method = net::HttpRequestHeaders::kGetMethod;
+    request.url = GURL("http://other.com/foo.png");
+    request.request_initiator = url::Origin::Create(GURL("http://example.com"));
+    request.trusted_params = ResourceRequest::TrustedParams();
+    CreateLoaderAndStart(request);
+
+    if (!is_trusted) {
+      RunUntilComplete();
+      EXPECT_FALSE(IsNetworkLoaderStarted());
+      EXPECT_FALSE(client().has_received_redirect());
+      EXPECT_FALSE(client().has_received_response());
+      EXPECT_TRUE(client().has_received_completion());
+      EXPECT_EQ(net::ERR_INVALID_ARGUMENT,
+                client().completion_status().error_code);
+      EXPECT_THAT(
+          bad_message_helper.bad_message_reports(),
+          ::testing::ElementsAre(
+              "CorsURLLoaderFactory: Untrusted caller making trusted request"));
+    } else {
+      NotifyLoaderClientOnReceiveResponse(
+          {"Access-Control-Allow-Origin: http://example.com"});
+      NotifyLoaderClientOnComplete(net::OK);
+
+      RunUntilComplete();
+
+      EXPECT_TRUE(IsNetworkLoaderStarted());
+      EXPECT_TRUE(client().has_received_response());
+      EXPECT_TRUE(client().has_received_completion());
+      EXPECT_EQ(net::OK, client().completion_status().error_code);
+      EXPECT_TRUE(
+          GetRequest().headers.HasHeader(net::HttpRequestHeaders::kOrigin));
+    }
+  }
+}
+
 }  // namespace
 
 }  // namespace cors
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc
index 528efc0..f794703 100644
--- a/services/network/network_context_unittest.cc
+++ b/services/network/network_context_unittest.cc
@@ -3432,6 +3432,11 @@
     std::move(on_done_accepting_connections_).Run();
   }
 
+  int GetTotalSocketsSeen() const {
+    base::AutoLock lock(lock_);
+    return total_sockets_seen_;
+  }
+
  private:
   static uint16_t GetPort(const net::StreamSocket& connection) {
     // Get the remote port of the peer, since the local port will always be the
@@ -3756,6 +3761,59 @@
   }
 }
 
+// Test that only trusted URLLoaderFactories accept
+// ResourceRequest::trusted_params.
+TEST_F(NetworkContextTest, TrustedParams) {
+  for (bool trusted_factory : {false, true}) {
+    ConnectionListener connection_listener;
+    net::EmbeddedTestServer test_server;
+    test_server.AddDefaultHandlers(
+        base::FilePath(FILE_PATH_LITERAL("services/test/data")));
+    test_server.SetConnectionListener(&connection_listener);
+    ASSERT_TRUE(test_server.Start());
+
+    std::unique_ptr<NetworkContext> network_context =
+        CreateContextWithParams(CreateContextParams());
+
+    mojom::URLLoaderFactoryPtr loader_factory;
+    mojom::URLLoaderFactoryParamsPtr params =
+        mojom::URLLoaderFactoryParams::New();
+    params->process_id = mojom::kBrowserProcessId;
+    params->is_corb_enabled = false;
+    // URLLoaderFactories should not be trusted by default.
+    EXPECT_FALSE(params->is_trusted);
+    params->is_trusted = trusted_factory;
+    network_context->CreateURLLoaderFactory(mojo::MakeRequest(&loader_factory),
+                                            std::move(params));
+
+    ResourceRequest request;
+    request.url = test_server.GetURL("/echo");
+    request.trusted_params = ResourceRequest::TrustedParams();
+    mojom::URLLoaderPtr loader;
+    TestURLLoaderClient client;
+    loader_factory->CreateLoaderAndStart(
+        mojo::MakeRequest(&loader), 0 /* routing_id */, 0 /* request_id */,
+        0 /* options */, request, client.CreateInterfacePtr(),
+        net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
+
+    client.RunUntilComplete();
+
+    // If the factory was trusted, the request should have succeeded. Otherwise,
+    // it should have failed.
+    EXPECT_EQ(trusted_factory, client.has_received_response());
+
+    if (trusted_factory) {
+      EXPECT_THAT(client.completion_status().error_code, net::test::IsOk());
+      EXPECT_EQ(1, connection_listener.GetTotalSocketsSeen());
+    } else {
+      EXPECT_THAT(client.completion_status().error_code,
+                  net::test::IsError(net::ERR_INVALID_ARGUMENT));
+      // No connection should have been made to the test server.
+      EXPECT_EQ(0, connection_listener.GetTotalSocketsSeen());
+    }
+  }
+}
+
 #if BUILDFLAG(IS_CT_SUPPORTED)
 TEST_F(NetworkContextTest, ExpectCT) {
   std::unique_ptr<NetworkContext> network_context =
@@ -5731,16 +5789,22 @@
       base::Optional<GURL> new_url = base::nullopt) {
     ResourceRequest request = CreateResourceRequest("GET", url);
     request.load_flags |= net::LOAD_SKIP_CACHE_VALIDATION;
-    request.update_network_isolation_key_on_redirect =
-        update_network_isolation_key_on_redirect;
 
     mojom::URLLoaderFactoryPtr loader_factory;
     auto params = mojom::URLLoaderFactoryParams::New();
     params->process_id = mojom::kBrowserProcessId;
     params->is_corb_enabled = false;
     if (is_navigation) {
-      request.trusted_network_isolation_key = key;
+      request.trusted_params = ResourceRequest::TrustedParams();
+      request.trusted_params->network_isolation_key = key;
+      request.trusted_params->update_network_isolation_key_on_redirect =
+          update_network_isolation_key_on_redirect;
+      params->is_trusted = true;
     } else {
+      // Different |update_network_isolation_key_on_redirect| values may only be
+      // set for navigations.
+      DCHECK_EQ(mojom::UpdateNetworkIsolationKeyOnRedirect::kDoNotUpdate,
+                update_network_isolation_key_on_redirect);
       params->network_isolation_key = key;
     }
     network_context_->CreateURLLoaderFactory(mojo::MakeRequest(&loader_factory),
diff --git a/services/network/public/cpp/resource_request.cc b/services/network/public/cpp/resource_request.cc
index 29d598bd..9ce60f78 100644
--- a/services/network/public/cpp/resource_request.cc
+++ b/services/network/public/cpp/resource_request.cc
@@ -8,6 +8,16 @@
 
 namespace network {
 
+ResourceRequest::TrustedParams::TrustedParams() = default;
+ResourceRequest::TrustedParams::~TrustedParams() = default;
+
+bool ResourceRequest::TrustedParams::operator==(
+    const TrustedParams& other) const {
+  return network_isolation_key == other.network_isolation_key &&
+         update_network_isolation_key_on_redirect ==
+             other.update_network_isolation_key_on_redirect;
+}
+
 ResourceRequest::ResourceRequest() {}
 ResourceRequest::ResourceRequest(const ResourceRequest& request) = default;
 ResourceRequest::~ResourceRequest() {}
@@ -16,10 +26,6 @@
   return method == request.method && url == request.url &&
          site_for_cookies == request.site_for_cookies &&
          top_frame_origin == request.top_frame_origin &&
-         trusted_network_isolation_key ==
-             request.trusted_network_isolation_key &&
-         update_network_isolation_key_on_redirect ==
-             request.update_network_isolation_key_on_redirect &&
          attach_same_site_cookies == request.attach_same_site_cookies &&
          update_first_party_url_on_redirect ==
              request.update_first_party_url_on_redirect &&
@@ -70,7 +76,8 @@
          devtools_request_id == request.devtools_request_id &&
          is_signed_exchange_prefetch_cache_enabled ==
              request.is_signed_exchange_prefetch_cache_enabled &&
-         obey_origin_policy == request.obey_origin_policy;
+         obey_origin_policy == request.obey_origin_policy &&
+         trusted_params == trusted_params;
 }
 
 bool ResourceRequest::SendsCookies() const {
diff --git a/services/network/public/cpp/resource_request.h b/services/network/public/cpp/resource_request.h
index d3d2a026..0ad6712 100644
--- a/services/network/public/cpp/resource_request.h
+++ b/services/network/public/cpp/resource_request.h
@@ -29,6 +29,23 @@
 // Note: Please revise EqualsForTesting accordingly on any updates to this
 // struct.
 struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ResourceRequest {
+  // Typemapped to network.mojom::TrustedUrlRequestParams, see comments there
+  // for details of each field.
+  //
+  // TODO(mmenke):  There are likely other fields that should be moved into this
+  // class.
+  struct COMPONENT_EXPORT(NETWORK_CPP_BASE) TrustedParams {
+    TrustedParams();
+    ~TrustedParams();
+
+    bool operator==(const TrustedParams& other) const;
+
+    net::NetworkIsolationKey network_isolation_key;
+    mojom::UpdateNetworkIsolationKeyOnRedirect
+        update_network_isolation_key_on_redirect =
+            network::mojom::UpdateNetworkIsolationKeyOnRedirect::kDoNotUpdate;
+  };
+
   ResourceRequest();
   ResourceRequest(const ResourceRequest& request);
   ~ResourceRequest();
@@ -41,10 +58,6 @@
   GURL url;
   GURL site_for_cookies;
   base::Optional<url::Origin> top_frame_origin;
-  net::NetworkIsolationKey trusted_network_isolation_key;
-  mojom::UpdateNetworkIsolationKeyOnRedirect
-      update_network_isolation_key_on_redirect =
-          network::mojom::UpdateNetworkIsolationKeyOnRedirect::kDoNotUpdate;
   bool attach_same_site_cookies = false;
   bool update_first_party_url_on_redirect = false;
   base::Optional<url::Origin> request_initiator;
@@ -91,6 +104,8 @@
   base::Optional<std::string> devtools_request_id;
   bool is_signed_exchange_prefetch_cache_enabled = false;
   bool obey_origin_policy = false;
+
+  base::Optional<TrustedParams> trusted_params;
 };
 
 }  // namespace network
diff --git a/services/network/public/cpp/url_request.typemap b/services/network/public/cpp/url_request.typemap
index c31e3eb9..7a1b6ede 100644
--- a/services/network/public/cpp/url_request.typemap
+++ b/services/network/public/cpp/url_request.typemap
@@ -21,6 +21,7 @@
   "//services/network/public/cpp:cpp_base",
 ]
 type_mappings = [
+  "network.mojom.TrustedUrlRequestParams=network::ResourceRequest::TrustedParams",
   "network.mojom.URLRequest=network::ResourceRequest",
   "network.mojom.URLRequestBody=scoped_refptr<network::ResourceRequestBody>[nullable_is_same_type,copyable_pass_by_value]",
   "network.mojom.URLRequestReferrerPolicy=net::URLRequest::ReferrerPolicy",
diff --git a/services/network/public/cpp/url_request_mojom_traits.cc b/services/network/public/cpp/url_request_mojom_traits.cc
index ff757b8..a4bca43 100644
--- a/services/network/public/cpp/url_request_mojom_traits.cc
+++ b/services/network/public/cpp/url_request_mojom_traits.cc
@@ -150,6 +150,17 @@
   return false;
 }
 
+bool StructTraits<network::mojom::TrustedUrlRequestParamsDataView,
+                  network::ResourceRequest::TrustedParams>::
+    Read(network::mojom::TrustedUrlRequestParamsDataView data,
+         network::ResourceRequest::TrustedParams* out) {
+  if (!data.ReadNetworkIsolationKey(&out->network_isolation_key))
+    return false;
+  out->update_network_isolation_key_on_redirect =
+      data.update_network_isolation_key_on_redirect();
+  return true;
+}
+
 bool StructTraits<
     network::mojom::URLRequestDataView,
     network::ResourceRequest>::Read(network::mojom::URLRequestDataView data,
@@ -157,8 +168,7 @@
   if (!data.ReadMethod(&out->method) || !data.ReadUrl(&out->url) ||
       !data.ReadSiteForCookies(&out->site_for_cookies) ||
       !data.ReadTopFrameOrigin(&out->top_frame_origin) ||
-      !data.ReadTrustedNetworkIsolationKey(
-          &out->trusted_network_isolation_key) ||
+      !data.ReadTrustedParams(&out->trusted_params) ||
       !data.ReadRequestInitiator(&out->request_initiator) ||
       !data.ReadReferrer(&out->referrer) ||
       !data.ReadReferrerPolicy(&out->referrer_policy) ||
@@ -181,8 +191,6 @@
     return false;
   }
 
-  out->update_network_isolation_key_on_redirect =
-      data.update_network_isolation_key_on_redirect();
   out->attach_same_site_cookies = data.attach_same_site_cookies();
   out->update_first_party_url_on_redirect =
       data.update_first_party_url_on_redirect();
diff --git a/services/network/public/cpp/url_request_mojom_traits.h b/services/network/public/cpp/url_request_mojom_traits.h
index 482291a..15d5031 100644
--- a/services/network/public/cpp/url_request_mojom_traits.h
+++ b/services/network/public/cpp/url_request_mojom_traits.h
@@ -46,6 +46,24 @@
 
 template <>
 struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
+    StructTraits<network::mojom::TrustedUrlRequestParamsDataView,
+                 network::ResourceRequest::TrustedParams> {
+  static const net::NetworkIsolationKey& network_isolation_key(
+      const network::ResourceRequest::TrustedParams& trusted_params) {
+    return trusted_params.network_isolation_key;
+  }
+  static network::mojom::UpdateNetworkIsolationKeyOnRedirect
+  update_network_isolation_key_on_redirect(
+      const network::ResourceRequest::TrustedParams& trusted_params) {
+    return trusted_params.update_network_isolation_key_on_redirect;
+  }
+
+  static bool Read(network::mojom::TrustedUrlRequestParamsDataView data,
+                   network::ResourceRequest::TrustedParams* out);
+};
+
+template <>
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
     StructTraits<network::mojom::URLRequestDataView, network::ResourceRequest> {
   static const std::string& method(const network::ResourceRequest& request) {
     return request.method;
@@ -60,15 +78,6 @@
       const network::ResourceRequest& request) {
     return request.top_frame_origin;
   }
-  static network::mojom::UpdateNetworkIsolationKeyOnRedirect
-  update_network_isolation_key_on_redirect(
-      const network::ResourceRequest& request) {
-    return request.update_network_isolation_key_on_redirect;
-  }
-  static const net::NetworkIsolationKey& trusted_network_isolation_key(
-      const network::ResourceRequest& request) {
-    return request.trusted_network_isolation_key;
-  }
   static bool attach_same_site_cookies(
       const network::ResourceRequest& request) {
     return request.attach_same_site_cookies;
@@ -224,6 +233,10 @@
   static bool obey_origin_policy(const network::ResourceRequest& request) {
     return request.obey_origin_policy;
   }
+  static const base::Optional<network::ResourceRequest::TrustedParams>&
+  trusted_params(const network::ResourceRequest& request) {
+    return request.trusted_params;
+  }
 
   static bool Read(network::mojom::URLRequestDataView data,
                    network::ResourceRequest* out);
diff --git a/services/network/public/cpp/url_request_mojom_traits_unittest.cc b/services/network/public/cpp/url_request_mojom_traits_unittest.cc
index cc4b846..32ce01b 100644
--- a/services/network/public/cpp/url_request_mojom_traits_unittest.cc
+++ b/services/network/public/cpp/url_request_mojom_traits_unittest.cc
@@ -49,12 +49,7 @@
   original.url = GURL("https://example.com/resources/dummy.xml");
   original.site_for_cookies = GURL("https://example.com/index.html");
   url::Origin origin = url::Origin::Create(original.url);
-  ;
   original.top_frame_origin = origin;
-  original.trusted_network_isolation_key =
-      net::NetworkIsolationKey(origin, origin);
-  original.update_network_isolation_key_on_redirect = network::mojom::
-      UpdateNetworkIsolationKeyOnRedirect::kUpdateTopFrameAndFrameOrigin;
   original.attach_same_site_cookies = true;
   original.update_first_party_url_on_redirect = false;
   original.request_initiator = url::Origin::Create(original.url);
@@ -94,6 +89,12 @@
   original.custom_proxy_post_cache_headers.SetHeader("post_y", "y_value");
   original.fetch_window_id = base::UnguessableToken::Create();
 
+  original.trusted_params = ResourceRequest::TrustedParams();
+  original.trusted_params->network_isolation_key =
+      net::NetworkIsolationKey(origin, origin);
+  original.trusted_params->update_network_isolation_key_on_redirect = network::
+      mojom::UpdateNetworkIsolationKeyOnRedirect::kUpdateTopFrameAndFrameOrigin;
+
   network::ResourceRequest copied;
   EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::URLRequest>(&original,
                                                                      &copied));
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
index ecccb54c..afa8aaf 100644
--- a/services/network/public/mojom/network_context.mojom
+++ b/services/network/public/mojom/network_context.mojom
@@ -507,6 +507,11 @@
 
   // Key used to isolate shared network resources like the cache.
   NetworkIsolationKey? network_isolation_key;
+
+  // True if this is for exclusive use by a trusted consumer. Only trusted
+  // consumers can issue requests with ResourceRequest::trusted_params
+  // populated.
+  bool is_trusted;
 };
 
 // Callback interface for NetworkContext when routing identifiers aren't
diff --git a/services/network/public/mojom/url_loader.mojom b/services/network/public/mojom/url_loader.mojom
index 2152f55..d839a35 100644
--- a/services/network/public/mojom/url_loader.mojom
+++ b/services/network/public/mojom/url_loader.mojom
@@ -80,12 +80,24 @@
   // the top frame origin and frame origin.
   kUpdateTopFrameAndFrameOrigin,
 
-  // The updated network isolation key will take existing
-  // |trusted_network_isolation_key|'s top frame origin and redirected url's
-  // origin as the frame origin.
+  // The updated network isolation key will take the existing
+  // NetworkIsolationKey's top frame origin and redirected url's origin as the
+  // frame origin.
   kUpdateFrameOrigin
 };
 
+// Options that may only be set on URLRequests passed to a URLLoaderFactory
+// created with |is_trusted| set to true.
+struct TrustedUrlRequestParams {
+  // This resource request will be keyed using |network_isolation_key| for
+  // accessing shared network resources like the http cache.
+  NetworkIsolationKey? network_isolation_key;
+
+  // Whether or not the network isolation key needs to be recomputed on
+  // redirects. Typically this is only done for navigations.
+  UpdateNetworkIsolationKeyOnRedirect update_network_isolation_key_on_redirect;
+};
+
 // Typemapped to network::ResourceRequest.
 struct URLRequest {
   // The request method: GET, POST, etc.
@@ -121,18 +133,6 @@
   // removed at some point.
   url.mojom.Origin? top_frame_origin;
 
-  // This resource request will be keyed using |trusted_network_isolation_key|
-  // for accessing shared network resources like the http cache. This must only
-  // be populated from a trusted process. Optional since it is not filled for
-  // all requests e.g. those coming from a less trusted process. This parameter
-  // may only be set if the URLLoaderFactory was not created with a pre-bound
-  // network isolation key, and it is an error to do otherwise.
-  NetworkIsolationKey? trusted_network_isolation_key;
-
-  // Whether or not the network isolation key needs to be recomputed on
-  // redirects. Typically this is only done for navigations.
-  UpdateNetworkIsolationKeyOnRedirect update_network_isolation_key_on_redirect;
-
   // Boolean indicating whether SameSite cookies are allowed to be attached
   // to the request. It should be used as additional input to network side
   // checks.
@@ -345,6 +345,9 @@
   // policy, if necessary, and attach it to the ResourceResponseHead.
   // Spec: https://wicg.github.io/origin-policy/
   bool obey_origin_policy;
+
+  // Setting these from an untrusted URLLoader will cause the request to fail.
+  TrustedUrlRequestParams? trusted_params;
 };
 
 // URLRequestBody represents body (i.e. upload data) of a HTTP request.
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index 113225b..6efc3537 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -382,7 +382,9 @@
           request.custom_proxy_use_alternate_proxy_list),
       fetch_window_id_(request.fetch_window_id),
       update_network_isolation_key_on_redirect_(
-          request.update_network_isolation_key_on_redirect),
+          request.trusted_params
+              ? request.trusted_params->update_network_isolation_key_on_redirect
+              : mojom::UpdateNetworkIsolationKeyOnRedirect::kDoNotUpdate),
       origin_policy_manager_(nullptr) {
   DCHECK(delete_callback_);
   DCHECK(factory_params_);
@@ -411,17 +413,13 @@
   url_request_->set_referrer_policy(request.referrer_policy);
   url_request_->set_upgrade_if_insecure(request.upgrade_if_insecure);
 
-  // Populate network isolation key from the factory params or from the resource
-  // request for navigation resources.
-  if (!request.trusted_network_isolation_key.IsEmpty()) {
-    DCHECK(!factory_params_->network_isolation_key);
-    url_request_->set_network_isolation_key(
-        request.trusted_network_isolation_key);
-  }
   if (factory_params_->network_isolation_key) {
-    DCHECK(request.trusted_network_isolation_key.IsEmpty());
     url_request_->set_network_isolation_key(
         factory_params_->network_isolation_key.value());
+  } else if (request.trusted_params &&
+             !request.trusted_params->network_isolation_key.IsEmpty()) {
+    url_request_->set_network_isolation_key(
+        request.trusted_params->network_isolation_key);
   }
 
   // |cors_excempt_headers| must be merged here to avoid breaking CORS checks.
diff --git a/services/network/url_loader_factory.cc b/services/network/url_loader_factory.cc
index d2e68cc..2e9e147d 100644
--- a/services/network/url_loader_factory.cc
+++ b/services/network/url_loader_factory.cc
@@ -71,6 +71,10 @@
     const ResourceRequest& url_request,
     mojom::URLLoaderClientPtr client,
     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
+  // Requests with |trusted_params| when params_->is_trusted is not set should
+  // have been rejected at the CorsURLLoader layer.
+  DCHECK(!url_request.trusted_params || params_->is_trusted);
+
   std::string origin_string;
   bool has_origin = url_request.headers.GetHeader("Origin", &origin_string) &&
                     origin_string != "null";
@@ -132,21 +136,6 @@
     return;
   }
 
-  // For navigation and worker script resources, the network isolation key may
-  // be set in the resource request and for sub-resources, it is set in params_.
-  // Fail if it is set in both as that could imply a compromised less trusted
-  // process filling up the resource request's trusted_network_isolation_key (It
-  // should only be filled up by a trusted process).
-  if (params_->network_isolation_key &&
-      !url_request.trusted_network_isolation_key.IsEmpty()) {
-    URLLoaderCompletionStatus status;
-    status.error_code = net::ERR_INVALID_ARGUMENT;
-    status.exists_in_cache = false;
-    status.completion_time = base::TimeTicks::Now();
-    client->OnComplete(status);
-    return;
-  }
-
   auto loader = std::make_unique<URLLoader>(
       context_->url_request_context(), network_service_client,
       context_->client(),
diff --git a/services/resource_coordinator/memory_instrumentation/coordinator_impl_unittest.cc b/services/resource_coordinator/memory_instrumentation/coordinator_impl_unittest.cc
index 9fd9ee8..230a254 100644
--- a/services/resource_coordinator/memory_instrumentation/coordinator_impl_unittest.cc
+++ b/services/resource_coordinator/memory_instrumentation/coordinator_impl_unittest.cc
@@ -11,7 +11,6 @@
 #include "base/test/trace_event_analyzer.h"
 #include "base/threading/platform_thread.h"
 #include "base/time/time.h"
-#include "base/time/time_override.h"
 #include "base/trace_event/memory_dump_request_args.h"
 #include "build/build_config.h"
 #include "mojo/public/cpp/bindings/binding.h"
@@ -148,13 +147,12 @@
         base::TimeDelta::FromMilliseconds(5));
   }
 
- private:
+ protected:
   std::unique_ptr<NiceMock<FakeCoordinatorImpl>> coordinator_;
-  // Do not start a ThreadPool as we are overriding global time with
-  // ScopedTimeClockOverrides and that might lead to races (as worker threads
-  // try to access base::TimeTicks::Now())
+
   base::test::ScopedTaskEnvironment scoped_task_environment_{
-      base::test::ScopedTaskEnvironment::ThreadingMode::MAIN_THREAD_ONLY};
+      base::test::ScopedTaskEnvironment::ThreadingMode::MAIN_THREAD_ONLY,
+      base::test::ScopedTaskEnvironment::TimeSource::MOCK_TIME};
 };
 
 class MockClientProcess : public mojom::ClientProcess {
@@ -321,16 +319,10 @@
 TEST_F(CoordinatorImplTest, QueuedRequest) {
   base::RunLoop run_loop;
 
-  // Override TimeTicks::Now with a timer that has extra_time added.
   // This variable to be static as the lambda below has to convert to a function
   // pointer rather than a functor.
-  static base::TimeDelta extra_time;
-  base::subtle::ScopedTimeClockOverrides time_override(
-      nullptr,
-      []() {
-        return base::subtle::TimeTicksNowIgnoringOverride() + extra_time;
-      },
-      nullptr);
+  static base::test::ScopedTaskEnvironment* task_environment = nullptr;
+  task_environment = &scoped_task_environment_;
 
   NiceMock<MockClientProcess> client_process_1(this, 1,
                                                mojom::ProcessType::BROWSER);
@@ -345,7 +337,8 @@
              MockClientProcess::RequestChromeMemoryDumpCallback& callback) {
             // Skip the wall clock time-ticks forward to make sure start_time
             // is strictly increasing.
-            extra_time += base::TimeDelta::FromMilliseconds(10);
+            task_environment->FastForwardBy(
+                base::TimeDelta::FromMilliseconds(10));
             MemoryDumpArgs dump_args{MemoryDumpLevelOfDetail::DETAILED};
             auto pmd = std::make_unique<ProcessMemoryDump>(dump_args);
             std::move(callback).Run(true, args.dump_guid, std::move(pmd));
@@ -360,7 +353,7 @@
   base::TimeTicks first_dump_time;
   EXPECT_CALL(callback1, OnCall(true, NotNull()))
       .WillOnce(Invoke([&](bool success, GlobalMemoryDump* global_dump) {
-        EXPECT_LT(before, global_dump->start_time);
+        EXPECT_LE(before, global_dump->start_time);
         first_dump_time = global_dump->start_time;
       }));
   EXPECT_CALL(callback2, OnCall(true, NotNull()))
diff --git a/services/service_manager/public/cpp/binder_map.h b/services/service_manager/public/cpp/binder_map.h
index eb9c717..28f4315 100644
--- a/services/service_manager/public/cpp/binder_map.h
+++ b/services/service_manager/public/cpp/binder_map.h
@@ -51,12 +51,6 @@
   BinderMapWithContext() = default;
   ~BinderMapWithContext() = default;
 
-  // Adds a new generic binder to this map. A generic binder takes an interface
-  // name, a receiver pipe, and (if ContextType is non-void) a context value.
-  void Add(const std::string& interface_name, GenericBinderType binder) {
-    binders_[interface_name] = std::move(binder);
-  }
-
   // Adds a new binder specifically for Interface receivers. This exists for the
   // convenience of being able to register strongly-typed binding methods like:
   //
@@ -64,8 +58,11 @@
   //
   // more easily.
   template <typename Interface>
-  void Add(BinderType<Interface> binder) {
-    binders_[Interface::Name_] = Traits::MakeGenericBinder(std::move(binder));
+  void Add(BinderType<Interface> binder,
+           scoped_refptr<base::SequencedTaskRunner> task_runner = nullptr) {
+    binders_[Interface::Name_] = std::make_unique<
+        internal::GenericCallbackBinderWithContext<ContextType>>(
+        Traits::MakeGenericBinder(std::move(binder)), std::move(task_runner));
   }
 
   // Passes |*receiver_pipe| to a registered binder for |interface_name| if any
@@ -81,7 +78,7 @@
     if (it == binders_.end())
       return false;
 
-    it->second.Run(std::move(*receiver_pipe));
+    it->second->BindInterface(std::move(*receiver_pipe));
     return true;
   }
 
@@ -97,7 +94,7 @@
     if (it == binders_.end())
       return false;
 
-    it->second.Run(std::move(context), std::move(*receiver_pipe));
+    it->second->BindInterface(std::move(context), std::move(*receiver_pipe));
     return true;
   }
 
@@ -105,7 +102,10 @@
   void Clear() { binders_.clear(); }
 
  private:
-  std::map<std::string, GenericBinderType> binders_;
+  std::map<
+      std::string,
+      std::unique_ptr<internal::GenericCallbackBinderWithContext<ContextType>>>
+      binders_;
 
   DISALLOW_COPY_AND_ASSIGN(BinderMapWithContext);
 };
diff --git a/services/service_manager/public/cpp/binder_map_internal.h b/services/service_manager/public/cpp/binder_map_internal.h
index 7a72e0c6..a8265bd 100644
--- a/services/service_manager/public/cpp/binder_map_internal.h
+++ b/services/service_manager/public/cpp/binder_map_internal.h
@@ -70,6 +70,62 @@
   }
 };
 
+template <typename ContextType>
+class GenericCallbackBinderWithContext {
+ public:
+  using Traits = BinderContextTraits<ContextType>;
+  using ContextValueType = typename Traits::ValueType;
+  using GenericBinderType = typename Traits::GenericBinderType;
+
+  GenericCallbackBinderWithContext(
+      GenericBinderType callback,
+      scoped_refptr<base::SequencedTaskRunner> task_runner)
+      : callback_(std::move(callback)), task_runner_(std::move(task_runner)) {}
+
+  ~GenericCallbackBinderWithContext() = default;
+
+  void BindInterface(ContextValueType context,
+                     mojo::ScopedMessagePipeHandle receiver_pipe) {
+    if (task_runner_) {
+      task_runner_->PostTask(
+          FROM_HERE,
+          base::BindOnce(
+              &GenericCallbackBinderWithContext::RunCallbackWithContext,
+              callback_, std::move(context), std::move(receiver_pipe)));
+      return;
+    }
+    RunCallbackWithContext(callback_, std::move(context),
+                           std::move(receiver_pipe));
+  }
+
+  void BindInterface(mojo::ScopedMessagePipeHandle receiver_pipe) {
+    if (task_runner_) {
+      task_runner_->PostTask(
+          FROM_HERE,
+          base::BindOnce(&GenericCallbackBinderWithContext::RunCallback,
+                         callback_, std::move(receiver_pipe)));
+      return;
+    }
+    RunCallback(callback_, std::move(receiver_pipe));
+  }
+
+ private:
+  static void RunCallbackWithContext(const GenericBinderType& callback,
+                                     ContextValueType context,
+                                     mojo::ScopedMessagePipeHandle handle) {
+    callback.Run(std::move(context), std::move(handle));
+  }
+
+  static void RunCallback(const GenericBinderType& callback,
+                          mojo::ScopedMessagePipeHandle handle) {
+    callback.Run(std::move(handle));
+  }
+
+  const GenericBinderType callback_;
+  const scoped_refptr<base::SequencedTaskRunner> task_runner_;
+  DISALLOW_COPY_AND_ASSIGN(GenericCallbackBinderWithContext);
+};
+
 }  // namespace internal
 }  // namespace service_manager
 
diff --git a/services/tracing/public/cpp/perfetto/perfetto_traced_process.cc b/services/tracing/public/cpp/perfetto/perfetto_traced_process.cc
index f9d583f4..4f46634 100644
--- a/services/tracing/public/cpp/perfetto/perfetto_traced_process.cc
+++ b/services/tracing/public/cpp/perfetto/perfetto_traced_process.cc
@@ -12,6 +12,7 @@
 #include "build/build_config.h"
 #include "services/tracing/public/cpp/perfetto/dummy_producer.h"
 #include "services/tracing/public/cpp/perfetto/producer_client.h"
+#include "services/tracing/public/cpp/trace_startup.h"
 #include "services/tracing/public/cpp/tracing_features.h"
 
 #if defined(OS_ANDROID)
@@ -79,6 +80,7 @@
 
 PerfettoTracedProcess::PerfettoTracedProcess(const char* system_socket)
     : producer_client_(std::make_unique<ProducerClient>(GetTaskRunner())) {
+  CHECK(IsTracingInitialized());
   DETACH_FROM_SEQUENCE(sequence_checker_);
   // All communication with the system Perfetto service should occur on a single
   // sequence. To ensure we set up the socket correctly we construct the
@@ -143,6 +145,7 @@
 void PerfettoTracedProcess::ResetTaskRunnerForTesting(
     scoped_refptr<base::SequencedTaskRunner> task_runner) {
   GetTaskRunner()->ResetTaskRunnerForTesting(task_runner);
+  InitTracingPostThreadPoolStartAndFeatureList();
   // Detaching the sequence_checker_ must happen after we reset the task runner.
   // This is because the Get() could call the constructor (if this is the first
   // call to Get()) which would then PostTask which would create races if we
diff --git a/services/tracing/public/cpp/perfetto/trace_event_data_source.cc b/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
index cd529bef..7440586 100644
--- a/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
+++ b/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
@@ -33,6 +33,7 @@
 #include "services/tracing/public/cpp/perfetto/traced_value_proto_writer.h"
 #include "services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.h"
 #include "services/tracing/public/cpp/trace_event_args_whitelist.h"
+#include "services/tracing/public/cpp/trace_startup.h"
 #include "services/tracing/public/mojom/constants.mojom.h"
 #include "third_party/perfetto/include/perfetto/ext/tracing/core/shared_memory_arbiter.h"
 #include "third_party/perfetto/include/perfetto/ext/tracing/core/startup_trace_writer.h"
@@ -287,6 +288,7 @@
 }
 
 void TraceEventDataSource::OnTaskSchedulerAvailable() {
+  CHECK(IsTracingInitialized());
   {
     base::AutoLock lock(lock_);
     if (!startup_writer_registry_)
diff --git a/services/tracing/public/cpp/trace_startup.cc b/services/tracing/public/cpp/trace_startup.cc
index 7ccc0789..59812b6 100644
--- a/services/tracing/public/cpp/trace_startup.cc
+++ b/services/tracing/public/cpp/trace_startup.cc
@@ -6,6 +6,7 @@
 
 #include "base/command_line.h"
 #include "base/logging.h"
+#include "base/task/thread_pool/thread_pool.h"
 #include "base/trace_event/trace_log.h"
 #include "components/tracing/common/trace_startup_config.h"
 #include "components/tracing/common/trace_to_console.h"
@@ -15,12 +16,17 @@
 #include "services/tracing/public/cpp/tracing_features.h"
 
 namespace tracing {
-
 namespace {
 using base::trace_event::TraceConfig;
 using base::trace_event::TraceLog;
 }  // namespace
 
+bool g_tracing_initialized_after_threadpool_and_featurelist = false;
+
+bool IsTracingInitialized() {
+  return g_tracing_initialized_after_threadpool_and_featurelist;
+}
+
 void EnableStartupTracingIfNeeded() {
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
@@ -66,7 +72,17 @@
   }
 }
 
-void InitTracingPostThreadPoolStart() {
+void InitTracingPostThreadPoolStartAndFeatureList() {
+  if (g_tracing_initialized_after_threadpool_and_featurelist) {
+    return;
+  }
+  g_tracing_initialized_after_threadpool_and_featurelist = true;
+  // TODO(nuskos): We should switch these to DCHECK once we're reasonably
+  // confident we've ensured this is called properly in all processes. Probably
+  // after M78 release has been cut (since we'll verify in the rollout of M78).
+  CHECK(base::ThreadPoolInstance::Get());
+  CHECK(base::FeatureList::GetInstance());
+  // Below are the things tracing must do once per process.
   TraceEventDataSource::GetInstance()->OnTaskSchedulerAvailable();
   if (base::FeatureList::IsEnabled(features::kEnablePerfettoSystemTracing)) {
     // To ensure System tracing connects we have to initialize the process wide
diff --git a/services/tracing/public/cpp/trace_startup.h b/services/tracing/public/cpp/trace_startup.h
index 0273ef8f..658856a 100644
--- a/services/tracing/public/cpp/trace_startup.h
+++ b/services/tracing/public/cpp/trace_startup.h
@@ -9,14 +9,19 @@
 
 namespace tracing {
 
-// If startup tracing command line flags are specified for the process, enables
+// Returns true if InitTracingPostThreadPoolStartAndFeatureList has been called
+// for this process.
+bool COMPONENT_EXPORT(TRACING_CPP) IsTracingInitialized();
+
 // TraceLog with config based on the command line flags. Also hooks up service
 // callbacks in TraceLog if necessary. The latter is required when the perfetto
 // tracing backend is used.
 void COMPONENT_EXPORT(TRACING_CPP) EnableStartupTracingIfNeeded();
 
-// Initialize tracing components that require task runners.
-void COMPONENT_EXPORT(TRACING_CPP) InitTracingPostThreadPoolStart();
+// Initialize tracing components that require task runners. Will switch
+// IsTracingInitialized() to return true.
+void COMPONENT_EXPORT(TRACING_CPP)
+    InitTracingPostThreadPoolStartAndFeatureList();
 
 }  // namespace tracing
 
diff --git a/testing/test_env.py b/testing/test_env.py
index 3e6723b..13808a2f 100755
--- a/testing/test_env.py
+++ b/testing/test_env.py
@@ -284,6 +284,7 @@
     signal.signal(signal.SIGTERM, _sig_handler)
     signal.signal(signal.SIGINT, _sig_handler)
 
+
 def run_executable(cmd, env, stdoutfile=None):
   """Runs an executable with:
     - CHROME_HEADLESS set to indicate that the test is running on a
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 4eeafed..4e04c96f 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -99,7 +99,7 @@
             ],
             "experiments": [
                 {
-                    "name": "InstallApp",
+                    "name": "Install app",
                     "params": {
                         "include_no_download_required": "false"
                     },
@@ -108,7 +108,7 @@
                     ]
                 },
                 {
-                    "name": "InstallAppNoDownloadRequired",
+                    "name": "Install app (no download required)",
                     "params": {
                         "include_no_download_required": "true"
                     },
diff --git a/third_party/blink/public/mojom/service_worker/service_worker_provider.mojom b/third_party/blink/public/mojom/service_worker/service_worker_provider.mojom
index 8f32ac2..8583e16 100644
--- a/third_party/blink/public/mojom/service_worker/service_worker_provider.mojom
+++ b/third_party/blink/public/mojom/service_worker/service_worker_provider.mojom
@@ -5,6 +5,7 @@
 module blink.mojom;
 
 import "services/network/public/mojom/url_loader_factory.mojom";
+import "third_party/blink/public/mojom/browser_interface_broker.mojom";
 import "services/service_manager/public/mojom/interface_provider.mojom";
 import "third_party/blink/public/mojom/cache_storage/cache_storage.mojom";
 import "third_party/blink/public/mojom/service_worker/controller_service_worker_mode.mojom";
@@ -48,7 +49,12 @@
   // byte-to-byte update check before running.
   CacheStorage? cache_storage;
 
+  // TODO(crbug.com/990845): remove when no longer used.
   service_manager.mojom.InterfaceProvider interface_provider;
+
+  // Used for accessing services from the worker.
+  // Should replace the |interface_provider| above.
+  pending_remote<blink.mojom.BrowserInterfaceBroker> browser_interface_broker;
 };
 
 // ServiceWorkerWorkerClient represents a service worker client that is a worker
diff --git a/third_party/blink/public/web/web_embedded_worker.h b/third_party/blink/public/web/web_embedded_worker.h
index a72755f..8d0f16b4 100644
--- a/third_party/blink/public/web/web_embedded_worker.h
+++ b/third_party/blink/public/web/web_embedded_worker.h
@@ -66,7 +66,8 @@
       std::unique_ptr<WebServiceWorkerInstalledScriptsManagerParams>,
       mojo::ScopedMessagePipeHandle content_settings_handle,
       mojo::ScopedMessagePipeHandle cache_storage,
-      mojo::ScopedMessagePipeHandle interface_provider);
+      mojo::ScopedMessagePipeHandle interface_provider,
+      mojo::ScopedMessagePipeHandle browser_interface_broker);
 
   virtual ~WebEmbeddedWorker() = default;
 
diff --git a/third_party/blink/public/web/web_local_frame_client.h b/third_party/blink/public/web/web_local_frame_client.h
index 2c8b6e7..b438a4b 100644
--- a/third_party/blink/public/web/web_local_frame_client.h
+++ b/third_party/blink/public/web/web_local_frame_client.h
@@ -69,6 +69,7 @@
 #include "third_party/blink/public/web/web_history_commit_type.h"
 #include "third_party/blink/public/web/web_history_item.h"
 #include "third_party/blink/public/web/web_icon_url.h"
+#include "third_party/blink/public/web/web_media_inspector.h"
 #include "third_party/blink/public/web/web_navigation_params.h"
 #include "third_party/blink/public/web/web_navigation_policy.h"
 #include "third_party/blink/public/web/web_navigation_type.h"
@@ -145,6 +146,7 @@
   // WebContentDecryptionModule* may be null if one has not yet been set.
   virtual WebMediaPlayer* CreateMediaPlayer(const WebMediaPlayerSource&,
                                             WebMediaPlayerClient*,
+                                            blink::MediaInspectorContext*,
                                             WebMediaPlayerEncryptedMediaClient*,
                                             WebContentDecryptionModule*,
                                             const WebString& sink_id,
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/ir_builder.py b/third_party/blink/renderer/bindings/scripts/web_idl/ir_builder.py
index b3a6088..85979f2 100644
--- a/third_party/blink/renderer/bindings/scripts/web_idl/ir_builder.py
+++ b/third_party/blink/renderer/bindings/scripts/web_idl/ir_builder.py
@@ -15,6 +15,7 @@
 from .dictionary import Dictionary
 from .dictionary import DictionaryMember
 from .enumeration import Enumeration
+from .extended_attribute import ExtendedAttribute
 from .extended_attribute import ExtendedAttributes
 from .idl_type import IdlTypeFactory
 from .includes import Includes
@@ -331,8 +332,42 @@
         return DefaultValue()
 
     def _build_extended_attributes(self, node):
+        def build_extended_attribute(node):
+            key = node.GetName()
+            values = node.GetProperty('VALUE', default=None)
+            arguments = None
+
+            # Drop constructors as they do not fit in ExtendedAttribute which
+            # doesn't support IdlType.
+            if key in ('Constructor', 'CustomConstructor', 'NamedConstructor'):
+                return None
+
+            child_nodes = node.GetChildren()
+            if child_nodes:
+                assert len(child_nodes) == 1
+                assert child_nodes[0].GetClass() == 'Arguments'
+                arguments = map(build_extattr_argument,
+                                child_nodes[0].GetChildren())
+
+            return ExtendedAttribute(
+                key=key, values=values, arguments=arguments)
+
+        def build_extattr_argument(node):
+            assert node.GetClass() == 'Argument'
+
+            child_nodes = node.GetChildren()
+            assert len(child_nodes) == 1
+            assert child_nodes[0].GetClass() == 'Type'
+
+            type_node = child_nodes[0]
+            type_children = type_node.GetChildren()
+            assert len(type_children) == 1
+
+            return (type_children[0].GetName(), node.GetName())
+
         assert node.GetClass() == 'ExtAttributes'
-        return ExtendedAttributes()
+        return ExtendedAttributes(
+            filter(None, map(build_extended_attribute, node.GetChildren())))
 
     def _build_inheritance(self, node):
         assert node.GetClass() == 'Inherit'
diff --git a/third_party/blink/renderer/core/animation/animation.h b/third_party/blink/renderer/core/animation/animation.h
index 32e4322..405e8bb2 100644
--- a/third_party/blink/renderer/core/animation/animation.h
+++ b/third_party/blink/renderer/core/animation/animation.h
@@ -99,6 +99,9 @@
   ~Animation() override;
   void Dispose();
 
+  virtual bool IsCSSAnimation() const { return false; }
+  virtual bool IsCSSTransition() const { return false; }
+
   // Returns whether the animation is finished.
   bool Update(TimingUpdateReason);
 
diff --git a/third_party/blink/renderer/core/animation/css/css_animation.cc b/third_party/blink/renderer/core/animation/css/css_animation.cc
index 07e7b2ca..dee7da2d 100644
--- a/third_party/blink/renderer/core/animation/css/css_animation.cc
+++ b/third_party/blink/renderer/core/animation/css/css_animation.cc
@@ -21,12 +21,6 @@
                            AnimationEffect* content,
                            const String& animation_name)
     : Animation(execution_context, timeline, content),
-      animation_name_(animation_name) {
-  setId(animation_name);
-}
-
-const String& CSSAnimation::animationName() const {
-  return animation_name_;
-}
+      animation_name_(animation_name) {}
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/animation/css/css_animation.h b/third_party/blink/renderer/core/animation/css/css_animation.h
index 7fa0885..1df6961 100644
--- a/third_party/blink/renderer/core/animation/css/css_animation.h
+++ b/third_party/blink/renderer/core/animation/css/css_animation.h
@@ -24,12 +24,20 @@
                AnimationEffect*,
                const String& animation_name);
 
-  const String& animationName() const;
+  bool IsCSSAnimation() const final { return true; }
+
+  const String& animationName() const { return animation_name_; }
 
  private:
   String animation_name_;
 };
 
+DEFINE_TYPE_CASTS(CSSAnimation,
+                  Animation,
+                  animation,
+                  animation->IsCSSAnimation(),
+                  animation.IsCSSAnimation());
+
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_CSS_CSS_ANIMATION_H_
diff --git a/third_party/blink/renderer/core/animation/css/css_animations.cc b/third_party/blink/renderer/core/animation/css/css_animations.cc
index 14a3788e..fff44838 100644
--- a/third_party/blink/renderer/core/animation/css/css_animations.cc
+++ b/third_party/blink/renderer/core/animation/css/css_animations.cc
@@ -225,24 +225,6 @@
 
 CSSAnimations::CSSAnimations() = default;
 
-bool CSSAnimations::IsAnimationForInspector(const Animation& animation) {
-  for (const auto& running_animation : running_animations_) {
-    if (running_animation->animation->SequenceNumber() ==
-        animation.SequenceNumber())
-      return true;
-  }
-  return false;
-}
-
-bool CSSAnimations::IsTransitionAnimationForInspector(
-    const Animation& animation) const {
-  for (const auto& it : transitions_) {
-    if (it.value.animation->SequenceNumber() == animation.SequenceNumber())
-      return true;
-  }
-  return false;
-}
-
 namespace {
 
 const KeyframeEffectModelBase* GetKeyframeEffectModelBase(
diff --git a/third_party/blink/renderer/core/animation/css/css_animations.h b/third_party/blink/renderer/core/animation/css/css_animations.h
index 3d50f5b..38a535c 100644
--- a/third_party/blink/renderer/core/animation/css/css_animations.h
+++ b/third_party/blink/renderer/core/animation/css/css_animations.h
@@ -57,9 +57,6 @@
  public:
   CSSAnimations();
 
-  bool IsAnimationForInspector(const Animation&);
-  bool IsTransitionAnimationForInspector(const Animation&) const;
-
   static const StylePropertyShorthand& PropertiesForTransitionAll();
   static bool IsAnimationAffectingProperty(const CSSProperty&);
   static bool IsAffectedByKeyframesFromScope(const Element&, const TreeScope&);
diff --git a/third_party/blink/renderer/core/animation/css/css_transition.cc b/third_party/blink/renderer/core/animation/css/css_transition.cc
index f726ebd..f4fcedf0 100644
--- a/third_party/blink/renderer/core/animation/css/css_transition.cc
+++ b/third_party/blink/renderer/core/animation/css/css_transition.cc
@@ -19,9 +19,7 @@
                              AnimationEffect* content,
                              const PropertyHandle& transition_property)
     : Animation(execution_context, timeline, content),
-      transition_property_(transition_property) {
-  setId(transitionProperty());
-}
+      transition_property_(transition_property) {}
 
 AtomicString CSSTransition::transitionProperty() const {
   return transition_property_.GetCSSPropertyName().ToAtomicString();
diff --git a/third_party/blink/renderer/core/animation/css/css_transition.h b/third_party/blink/renderer/core/animation/css/css_transition.h
index 82dced9d..9752b9ee 100644
--- a/third_party/blink/renderer/core/animation/css/css_transition.h
+++ b/third_party/blink/renderer/core/animation/css/css_transition.h
@@ -23,12 +23,23 @@
                 AnimationEffect*,
                 const PropertyHandle& transition_property);
 
+  bool IsCSSTransition() const final { return true; }
+
   AtomicString transitionProperty() const;
+  const CSSProperty& TransitionCSSProperty() const {
+    return transition_property_.GetCSSProperty();
+  }
 
  private:
   PropertyHandle transition_property_;
 };
 
+DEFINE_TYPE_CASTS(CSSTransition,
+                  Animation,
+                  animation,
+                  animation->IsCSSTransition(),
+                  animation.IsCSSTransition());
+
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_CSS_CSS_TRANSITION_H_
diff --git a/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc b/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc
index 38a03dd..9c1a440 100644
--- a/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc
+++ b/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc
@@ -461,14 +461,24 @@
 namespace {
 
 bool IsNonZeroUserUnitsValue(const CSSPrimitiveValue* value) {
-  // TODO(crbug.com/979895): This is the result of a refactoring, which might
-  // have revealed an existing bug in handling user units in math functions. Fix
-  // it if necessary.
-  const auto* numeric_literal = DynamicTo<CSSNumericLiteralValue>(value);
-  return numeric_literal &&
-         numeric_literal->GetType() ==
-             CSSPrimitiveValue::UnitType::kUserUnits &&
-         value->GetDoubleValue() != 0;
+  if (!value)
+    return false;
+  if (const auto* numeric_literal = DynamicTo<CSSNumericLiteralValue>(value)) {
+    return numeric_literal->GetType() ==
+               CSSPrimitiveValue::UnitType::kUserUnits &&
+           value->GetDoubleValue() != 0;
+  }
+  const auto& math_value = To<CSSMathFunctionValue>(*value);
+  switch (math_value.Category()) {
+    case kCalcNumber:
+      return math_value.DoubleValue() != 0;
+    case kCalcPercentNumber:
+    case kCalcLengthNumber:
+    case kCalcPercentLengthNumber:
+      return true;
+    default:
+      return false;
+  }
 }
 
 }  // namespace
diff --git a/third_party/blink/renderer/core/css/properties/css_property.h b/third_party/blink/renderer/core/css/properties/css_property.h
index 9b6005c..a3d418c 100644
--- a/third_party/blink/renderer/core/css/properties/css_property.h
+++ b/third_party/blink/renderer/core/css/properties/css_property.h
@@ -72,10 +72,10 @@
   const CSSValue* CSSValueFromComputedStyle(const ComputedStyle&,
                                             const LayoutObject*,
                                             bool allow_visited_style) const;
-  virtual std::unique_ptr<CrossThreadStyleValue>
-  CrossThreadStyleValueFromComputedStyle(const ComputedStyle& computed_style,
-                                         const LayoutObject* layout_object,
-                                         bool allow_visited_style) const;
+  std::unique_ptr<CrossThreadStyleValue> CrossThreadStyleValueFromComputedStyle(
+      const ComputedStyle& computed_style,
+      const LayoutObject* layout_object,
+      bool allow_visited_style) const;
   virtual const CSSProperty& ResolveDirectionAwareProperty(TextDirection,
                                                            WritingMode) const {
     return *this;
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h
index 6f0cb78..68f4bdc 100644
--- a/third_party/blink/renderer/core/dom/element.h
+++ b/third_party/blink/renderer/core/dom/element.h
@@ -321,9 +321,9 @@
   int scrollHeight();
 
   void scrollBy(double x, double y);
-  virtual void scrollBy(const ScrollToOptions*);
+  void scrollBy(const ScrollToOptions*);
   void scrollTo(double x, double y);
-  virtual void scrollTo(const ScrollToOptions*);
+  void scrollTo(const ScrollToOptions*);
   // This will return the |GetScrollableArea| of correspond LayoutBox. For
   // LayoutTextControlSingleLine, it will return its |InnerEditorElement|'s.
   virtual PaintLayerScrollableArea* GetScrollableArea() const;
diff --git a/third_party/blink/renderer/core/dom/events/event_target.h b/third_party/blink/renderer/core/dom/events/event_target.h
index 6b48c93..ca8bd99 100644
--- a/third_party/blink/renderer/core/dom/events/event_target.h
+++ b/third_party/blink/renderer/core/dom/events/event_target.h
@@ -194,9 +194,9 @@
   virtual bool AddEventListenerInternal(const AtomicString& event_type,
                                         EventListener*,
                                         const AddEventListenerOptionsResolved*);
-  virtual bool RemoveEventListenerInternal(const AtomicString& event_type,
-                                           const EventListener*,
-                                           const EventListenerOptions*);
+  bool RemoveEventListenerInternal(const AtomicString& event_type,
+                                   const EventListener*,
+                                   const EventListenerOptions*);
 
   // Called when an event listener has been successfully added.
   virtual void AddedEventListener(const AtomicString& event_type,
diff --git a/third_party/blink/renderer/core/dom/node.h b/third_party/blink/renderer/core/dom/node.h
index cfcd663..3db77e4 100644
--- a/third_party/blink/renderer/core/dom/node.h
+++ b/third_party/blink/renderer/core/dom/node.h
@@ -564,7 +564,7 @@
   }
 
   virtual void SetFocused(bool flag, WebFocusType);
-  virtual void SetHasFocusWithin(bool flag);
+  void SetHasFocusWithin(bool flag);
   virtual void SetDragged(bool flag);
 
   virtual int tabIndex() const;
@@ -832,7 +832,7 @@
 
   // Perform the default action for an event.
   virtual void DefaultEventHandler(Event&);
-  virtual void WillCallDefaultEventHandler(const Event&);
+  void WillCallDefaultEventHandler(const Event&);
   // Should return true if this Node has activation behavior.
   // https://dom.spec.whatwg.org/#eventtarget-activation-behavior
   virtual bool HasActivationBehavior() const;
@@ -983,8 +983,7 @@
 
   Node(TreeScope*, ConstructionType);
 
-  virtual void WillMoveToNewDocument(Document& old_document,
-                                     Document& new_document);
+  void WillMoveToNewDocument(Document& old_document, Document& new_document);
   virtual void DidMoveToNewDocument(Document& old_document);
 
   void AddedEventListener(const AtomicString& event_type,
diff --git a/third_party/blink/renderer/core/frame/visual_viewport_test.cc b/third_party/blink/renderer/core/frame/visual_viewport_test.cc
index ef25053..72d1df7 100644
--- a/third_party/blink/renderer/core/frame/visual_viewport_test.cc
+++ b/third_party/blink/renderer/core/frame/visual_viewport_test.cc
@@ -14,6 +14,7 @@
 #include "third_party/blink/public/platform/web_coalesced_input_event.h"
 #include "third_party/blink/public/platform/web_input_event.h"
 #include "third_party/blink/public/platform/web_layer_tree_view.h"
+#include "third_party/blink/public/platform/web_scroll_into_view_params.h"
 #include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
 #include "third_party/blink/public/web/web_ax_context.h"
 #include "third_party/blink/public/web/web_context_menu_data.h"
@@ -44,6 +45,7 @@
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
 #include "third_party/blink/renderer/core/scroll/scrollbar_theme_overlay.h"
+#include "third_party/blink/renderer/core/scroll/smooth_scroll_sequencer.h"
 #include "third_party/blink/renderer/core/testing/sim/sim_request.h"
 #include "third_party/blink/renderer/core/testing/sim/sim_test.h"
 #include "third_party/blink/renderer/platform/geometry/double_point.h"
@@ -2510,7 +2512,7 @@
   }
 };
 
-// Test that we correcty size the visual viewport's scrolling contents layer
+// Test that we correctly size the visual viewport's scrolling contents layer
 // when the layout viewport is smaller.
 TEST_F(VisualViewportSimTest, ScrollingContentsSmallerThanContainer) {
   WebView().MainFrameWidget()->Resize(WebSize(400, 600));
@@ -2562,6 +2564,79 @@
   }
 }
 
+class VisualViewportScrollIntoViewTest : public VisualViewportSimTest {
+ public:
+  VisualViewportScrollIntoViewTest() {}
+
+  void SetUp() override {
+    VisualViewportSimTest::SetUp();
+
+    // Setup a fixed-position element that's outside of an inset visual
+    // viewport.
+    WebView().MainFrameWidget()->Resize(WebSize(400, 600));
+    SimRequest request("https://example.com/test.html", "text/html");
+    LoadURL("https://example.com/test.html");
+    request.Complete(R"HTML(
+              <!DOCTYPE html>
+              <style>
+               #bottom {
+                    position: fixed;
+                    bottom: 0;
+                                width: 100%;
+                                height: 20px;
+                                text-align: center;
+                }
+              </style>
+              <body>
+                 <div id="bottom">Layout bottom</div>
+              </body>
+          )HTML");
+    Compositor().BeginFrame();
+
+    // Shrink the height such that the fixed element is now off screen.
+    WebView().ResizeVisualViewport(IntSize(400, 600 - 100));
+  }
+
+  // Scrolls an element by the given name into view in the |visual_viewport|
+  // using params that optionally apply to a scroll sequence.
+  void ScrollIntoView(const WebString& element_name,
+                      bool is_for_scroll_sequence) {
+    WebDocument web_doc = WebView().MainFrameImpl()->GetDocument();
+    Element* bottom_element = web_doc.GetElementById(element_name);
+    WebScrollIntoViewParams scroll_params(
+        ScrollAlignment::kAlignToEdgeIfNeeded,
+        ScrollAlignment::kAlignToEdgeIfNeeded, kProgrammaticScroll,
+        /*make_visible_in_visual_viewport=*/true, kScrollBehaviorInstant,
+        is_for_scroll_sequence);
+    WebView().GetPage()->GetVisualViewport().ScrollIntoView(
+        bottom_element->BoundingBox(), scroll_params);
+  }
+};
+
+TEST_F(VisualViewportScrollIntoViewTest,
+       ScrollingToFixedWithScrollSequenceAnimationShort) {
+  VisualViewport& visual_viewport = WebView().GetPage()->GetVisualViewport();
+  EXPECT_EQ(0.f, visual_viewport.GetScrollOffset().Height());
+  ScrollIntoView("bottom", true);
+  visual_viewport.GetSmoothScrollSequencer()->RunQueuedAnimations();
+  EXPECT_EQ(100.f, visual_viewport.GetScrollOffset().Height());
+}
+
+TEST_F(VisualViewportScrollIntoViewTest,
+       ScrollingToFixedWithoutScrollSequenceAnimationShort) {
+  VisualViewport& visual_viewport = WebView().GetPage()->GetVisualViewport();
+  EXPECT_EQ(0.f, visual_viewport.GetScrollOffset().Height());
+  ScrollIntoView("bottom", false);
+  EXPECT_EQ(100.f, visual_viewport.GetScrollOffset().Height());
+}
+
+TEST_F(VisualViewportScrollIntoViewTest, ScrollingToFixedFromJavascript) {
+  VisualViewport& visual_viewport = WebView().GetPage()->GetVisualViewport();
+  EXPECT_EQ(0.f, visual_viewport.GetScrollOffset().Height());
+  GetDocument().getElementById("bottom")->scrollIntoView();
+  EXPECT_EQ(100.f, visual_viewport.GetScrollOffset().Height());
+}
+
 TEST_P(VisualViewportTest, DeviceEmulationTransformNode) {
   InitializeWithAndroidSettings();
 
diff --git a/third_party/blink/renderer/core/html/forms/input_type.h b/third_party/blink/renderer/core/html/forms/input_type.h
index 1f2097a7..e427d8e 100644
--- a/third_party/blink/renderer/core/html/forms/input_type.h
+++ b/third_party/blink/renderer/core/html/forms/input_type.h
@@ -132,10 +132,10 @@
   double Minimum() const;
   double Maximum() const;
   bool StepMismatch(const String&) const;
-  virtual bool GetAllowedValueStep(Decimal*) const;
+  bool GetAllowedValueStep(Decimal*) const;
   virtual StepRange CreateStepRange(AnyStepHandling) const;
-  virtual void StepUp(double, ExceptionState&);
-  virtual void StepUpFromLayoutObject(int);
+  void StepUp(double, ExceptionState&);
+  void StepUpFromLayoutObject(int);
   virtual String BadInputText() const;
   virtual String RangeOverflowText(const Decimal& maximum) const;
   virtual String RangeUnderflowText(const Decimal& minimum) const;
diff --git a/third_party/blink/renderer/core/html/media/video_auto_fullscreen_test.cc b/third_party/blink/renderer/core/html/media/video_auto_fullscreen_test.cc
index c8505727..25e4b63 100644
--- a/third_party/blink/renderer/core/html/media/video_auto_fullscreen_test.cc
+++ b/third_party/blink/renderer/core/html/media/video_auto_fullscreen_test.cc
@@ -24,6 +24,7 @@
  public:
   WebMediaPlayer* CreateMediaPlayer(const WebMediaPlayerSource&,
                                     WebMediaPlayerClient*,
+                                    blink::MediaInspectorContext*,
                                     WebMediaPlayerEncryptedMediaClient*,
                                     WebContentDecryptionModule*,
                                     const WebString& sink_id,
diff --git a/third_party/blink/renderer/core/input/event_handler.cc b/third_party/blink/renderer/core/input/event_handler.cc
index 4a3e305..ecdf4eb 100644
--- a/third_party/blink/renderer/core/input/event_handler.cc
+++ b/third_party/blink/renderer/core/input/event_handler.cc
@@ -1533,6 +1533,13 @@
   return scroll_manager_->HandleGestureScrollEvent(gesture_event);
 }
 
+WebInputEventResult EventHandler::HandleGestureScrollEnd(
+    const WebGestureEvent& gesture_event) {
+  if (!frame_->GetPage())
+    return WebInputEventResult::kNotHandled;
+  return scroll_manager_->HandleGestureScrollEnd(gesture_event);
+}
+
 void EventHandler::SetMouseDownMayStartAutoscroll() {
   mouse_event_manager_->SetMouseDownMayStartAutoscroll();
 }
diff --git a/third_party/blink/renderer/core/input/event_handler.h b/third_party/blink/renderer/core/input/event_handler.h
index 26a8dca..f153627 100644
--- a/third_party/blink/renderer/core/input/event_handler.h
+++ b/third_party/blink/renderer/core/input/event_handler.h
@@ -201,6 +201,7 @@
   // Handle the provided scroll gesture event, propagating down to child frames
   // as necessary.
   WebInputEventResult HandleGestureScrollEvent(const WebGestureEvent&);
+  WebInputEventResult HandleGestureScrollEnd(const WebGestureEvent&);
   bool IsScrollbarHandlingGestures() const;
 
   bool BestClickableNodeForHitTestResult(const HitTestLocation& location,
diff --git a/third_party/blink/renderer/core/input/scroll_manager.cc b/third_party/blink/renderer/core/input/scroll_manager.cc
index eb72bffb..4c6de7e 100644
--- a/third_party/blink/renderer/core/input/scroll_manager.cc
+++ b/third_party/blink/renderer/core/input/scroll_manager.cc
@@ -113,15 +113,6 @@
   }
 }
 
-Node* ScrollManager::GetScrollEventTarget() {
-  // Send the overscroll event to the node that scrolling is latched to which
-  // is either previously scrolled node or the last node in the scroll chain.
-  Node* scroll_target = previous_gesture_scrolled_node_;
-  if (!scroll_target && !current_scroll_chain_.IsEmpty())
-    scroll_target = DOMNodeIds::NodeForId(current_scroll_chain_.front());
-  return scroll_target;
-}
-
 void ScrollManager::StopAutoscroll() {
   if (AutoscrollController* controller = GetAutoscrollController())
     controller->StopAutoscroll();
@@ -326,12 +317,11 @@
     }
 
     ScrollableArea::ScrollCallback callback;
-    if (RuntimeEnabledFeatures::UpdateHoverAtBeginFrameEnabled() ||
-        RuntimeEnabledFeatures::OverscrollCustomizationEnabled()) {
+    if (RuntimeEnabledFeatures::UpdateHoverAtBeginFrameEnabled()) {
       callback = ScrollableArea::ScrollCallback(WTF::Bind(
           [](WeakPersistent<ScrollableArea> area) {
             if (area)
-              area->OnScrollFinished();
+              area->MarkHoverStateDirty();
           },
           WrapWeakPersistent(scrollable_area)));
     }
@@ -635,7 +625,13 @@
     return WebInputEventResult::kHandledSystem;
 
   if (RuntimeEnabledFeatures::OverscrollCustomizationEnabled()) {
-    if (Node* overscroll_target = GetScrollEventTarget()) {
+    // Send the overscroll event to the node that scrolling is latched to which
+    // is either previously scrolled node or the last node in the scroll chain.
+    Node* overscroll_target = previous_gesture_scrolled_node_;
+    if (!overscroll_target && !current_scroll_chain_.IsEmpty())
+      overscroll_target = DOMNodeIds::NodeForId(current_scroll_chain_.front());
+
+    if (overscroll_target) {
       overscroll_target->GetDocument().EnqueueOverscrollEventForNode(
           overscroll_target, delta.Width(), delta.Height());
     }
@@ -696,9 +692,16 @@
     snap_at_gesture_scroll_end = SnapAtGestureScrollEnd();
     NotifyScrollPhaseEndForCustomizedScroll();
 
-    if (RuntimeEnabledFeatures::OverscrollCustomizationEnabled() &&
-        !snap_at_gesture_scroll_end) {
-      if (Node* scroll_end_target = GetScrollEventTarget()) {
+    if (RuntimeEnabledFeatures::OverscrollCustomizationEnabled()) {
+      // Send the scrollend event to the node that scrolling is latched to
+      // which is either previously scrolled node or the last node in the
+      // scroll chain.
+      DCHECK(!current_scroll_chain_.IsEmpty());
+      if (previous_gesture_scrolled_node_) {
+        previous_gesture_scrolled_node_->GetDocument()
+            .EnqueueScrollEndEventForNode(previous_gesture_scrolled_node_);
+      } else if (Node* scroll_end_target =
+                     DOMNodeIds::NodeForId(current_scroll_chain_.front())) {
         scroll_end_target->GetDocument().EnqueueScrollEndEventForNode(
             scroll_end_target);
       }
@@ -792,12 +795,6 @@
 }
 
 void ScrollManager::ScrollEndForSnapFling() {
-  if (RuntimeEnabledFeatures::OverscrollCustomizationEnabled()) {
-    if (Node* scroll_end_target = GetScrollEventTarget()) {
-      scroll_end_target->GetDocument().EnqueueScrollEndEventForNode(
-          scroll_end_target);
-    }
-  }
   if (current_scroll_chain_.IsEmpty()) {
     NotifyScrollPhaseEndForCustomizedScroll();
     ClearGestureScrollState();
diff --git a/third_party/blink/renderer/core/input/scroll_manager.h b/third_party/blink/renderer/core/input/scroll_manager.h
index 7f2e1e7..5ba2d85 100644
--- a/third_party/blink/renderer/core/input/scroll_manager.h
+++ b/third_party/blink/renderer/core/input/scroll_manager.h
@@ -119,8 +119,6 @@
   WebInputEventResult PassScrollGestureEvent(const WebGestureEvent&,
                                              LayoutObject*);
 
-  Node* GetScrollEventTarget();
-
   void ClearGestureScrollState();
 
   void CustomizedScroll(ScrollState&);
diff --git a/third_party/blink/renderer/core/inspector/inspector_animation_agent.cc b/third_party/blink/renderer/core/inspector/inspector_animation_agent.cc
index 888a449..893eb8e 100644
--- a/third_party/blink/renderer/core/inspector/inspector_animation_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_animation_agent.cc
@@ -10,7 +10,9 @@
 #include "third_party/blink/renderer/core/animation/animation.h"
 #include "third_party/blink/renderer/core/animation/animation_effect.h"
 #include "third_party/blink/renderer/core/animation/computed_effect_timing.h"
+#include "third_party/blink/renderer/core/animation/css/css_animation.h"
 #include "third_party/blink/renderer/core/animation/css/css_animations.h"
+#include "third_party/blink/renderer/core/animation/css/css_transition.h"
 #include "third_party/blink/renderer/core/animation/effect_model.h"
 #include "third_party/blink/renderer/core/animation/element_animations.h"
 #include "third_party/blink/renderer/core/animation/keyframe_effect.h"
@@ -34,6 +36,21 @@
 
 namespace blink {
 
+namespace {
+
+String AnimationDisplayName(const Animation& animation) {
+  if (!animation.id().IsEmpty())
+    return animation.id();
+  else if (animation.IsCSSAnimation())
+    return ToCSSAnimation(animation).animationName();
+  else if (animation.IsCSSTransition())
+    return ToCSSTransition(animation).transitionProperty();
+  else
+    return animation.id();
+}
+
+}  // namespace
+
 using protocol::Response;
 
 InspectorAnimationAgent::InspectorAnimationAgent(
@@ -65,7 +82,6 @@
   enabled_.Clear();
   instrumenting_agents_->RemoveInspectorAnimationAgent(this);
   id_to_animation_.clear();
-  id_to_animation_type_.clear();
   id_to_animation_clone_.clear();
   cleared_animations_.clear();
   return Response::OK();
@@ -74,7 +90,6 @@
 void InspectorAnimationAgent::DidCommitLoadForLocalFrame(LocalFrame* frame) {
   if (frame == inspected_frames_->Root()) {
     id_to_animation_.clear();
-    id_to_animation_type_.clear();
     id_to_animation_clone_.clear();
     cleared_animations_.clear();
   }
@@ -145,47 +160,32 @@
 
 std::unique_ptr<protocol::Animation::Animation>
 InspectorAnimationAgent::BuildObjectForAnimation(blink::Animation& animation) {
-  String animation_type;
+  String animation_type = AnimationType::WebAnimation;
   std::unique_ptr<protocol::Animation::AnimationEffect> animation_effect_object;
 
-  if (!animation.effect()) {
-    animation_type = AnimationType::WebAnimation;
-  } else {
-    const Element* element = ToKeyframeEffect(animation.effect())->target();
-    std::unique_ptr<protocol::Animation::KeyframesRule> keyframe_rule;
-
-    if (!element) {
-      animation_type = AnimationType::WebAnimation;
-    } else {
-      CSSAnimations& css_animations =
-          element->GetElementAnimations()->CssAnimations();
-
-      if (css_animations.IsTransitionAnimationForInspector(animation)) {
-        // CSS Transitions
-        animation_type = AnimationType::CSSTransition;
-      } else {
-        // Keyframe based animations
-        keyframe_rule = BuildObjectForAnimationKeyframes(
-            ToKeyframeEffect(animation.effect()));
-        animation_type = css_animations.IsAnimationForInspector(animation)
-                             ? AnimationType::CSSAnimation
-                             : AnimationType::WebAnimation;
-      }
-    }
-
+  if (animation.effect()) {
     animation_effect_object =
         BuildObjectForAnimationEffect(ToKeyframeEffect(animation.effect()));
-    animation_effect_object->setKeyframesRule(std::move(keyframe_rule));
+
+    if (animation.IsCSSTransition()) {
+      animation_type = AnimationType::CSSTransition;
+    } else {
+      animation_effect_object->setKeyframesRule(
+          BuildObjectForAnimationKeyframes(
+              ToKeyframeEffect(animation.effect())));
+
+      if (animation.IsCSSAnimation())
+        animation_type = AnimationType::CSSAnimation;
+    }
   }
 
   String id = String::Number(animation.SequenceNumber());
   id_to_animation_.Set(id, &animation);
-  id_to_animation_type_.Set(id, animation_type);
 
   std::unique_ptr<protocol::Animation::Animation> animation_object =
       protocol::Animation::Animation::create()
           .setId(id)
-          .setName(animation.id())
+          .setName(AnimationDisplayName(animation))
           .setPausedState(animation.Paused())
           .setPlayState(animation.playState())
           .setPlaybackRate(animation.playbackRate())
@@ -343,7 +343,6 @@
       clone->cancel();
     id_to_animation_clone_.erase(animation_id);
     id_to_animation_.erase(animation_id);
-    id_to_animation_type_.erase(animation_id);
     cleared_animations_.insert(animation_id);
   }
   return Response::OK();
@@ -417,26 +416,28 @@
       &GetCSSPropertyTransitionProperty(),
       &GetCSSPropertyTransitionTimingFunction(),
   };
-  String type =
-      id_to_animation_type_.at(String::Number(animation.SequenceNumber()));
-  DCHECK_NE(type, AnimationType::WebAnimation);
 
   KeyframeEffect* effect = ToKeyframeEffect(animation.effect());
   Vector<const CSSProperty*> css_properties;
-  if (type == AnimationType::CSSAnimation) {
+  if (animation.IsCSSAnimation()) {
     for (const CSSProperty* property : g_animation_properties)
       css_properties.push_back(property);
-  } else {
+  } else if (animation.IsCSSTransition()) {
     for (const CSSProperty* property : g_transition_properties)
       css_properties.push_back(property);
-    css_properties.push_back(&CSSProperty::Get(cssPropertyID(animation.id())));
+    css_properties.push_back(
+        &ToCSSTransition(animation).TransitionCSSProperty());
+  } else {
+    NOTREACHED();
   }
 
   Element* element = effect->target();
   HeapVector<Member<CSSStyleDeclaration>> styles =
       css_agent_->MatchingStyles(element);
   Digestor digestor(kHashAlgorithmSha1);
-  digestor.UpdateUtf8(type);
+  digestor.UpdateUtf8(animation.IsCSSTransition()
+                          ? AnimationType::CSSTransition
+                          : AnimationType::CSSAnimation);
   digestor.UpdateUtf8(animation.id());
   for (const CSSProperty* property : css_properties) {
     CSSStyleDeclaration* style =
diff --git a/third_party/blink/renderer/core/inspector/inspector_animation_agent.h b/third_party/blink/renderer/core/inspector/inspector_animation_agent.h
index 623a2462e..b804454 100644
--- a/third_party/blink/renderer/core/inspector/inspector_animation_agent.h
+++ b/third_party/blink/renderer/core/inspector/inspector_animation_agent.h
@@ -87,7 +87,6 @@
   v8_inspector::V8InspectorSession* v8_session_;
   HeapHashMap<String, Member<blink::Animation>> id_to_animation_;
   HeapHashMap<String, Member<blink::Animation>> id_to_animation_clone_;
-  HashMap<String, String> id_to_animation_type_;
   bool is_cloning_;
   HashSet<String> cleared_animations_;
   InspectorAgentState::Boolean enabled_;
diff --git a/third_party/blink/renderer/core/layout/layout_box.h b/third_party/blink/renderer/core/layout/layout_box.h
index 7e046d0d..7df809e 100644
--- a/third_party/blink/renderer/core/layout/layout_box.h
+++ b/third_party/blink/renderer/core/layout/layout_box.h
@@ -1603,7 +1603,7 @@
       const Length& logical_width_length,
       LayoutUnit available_logical_width,
       LayoutUnit border_and_padding) const;
-  virtual LayoutUnit ComputeIntrinsicLogicalContentHeightUsing(
+  LayoutUnit ComputeIntrinsicLogicalContentHeightUsing(
       const Length& logical_height_length,
       LayoutUnit intrinsic_content_height,
       LayoutUnit border_and_padding) const;
diff --git a/third_party/blink/renderer/core/layout/layout_flexible_box_test.cc b/third_party/blink/renderer/core/layout/layout_flexible_box_test.cc
index 781b9c7e..8a84ff2 100644
--- a/third_party/blink/renderer/core/layout/layout_flexible_box_test.cc
+++ b/third_party/blink/renderer/core/layout/layout_flexible_box_test.cc
@@ -4,7 +4,6 @@
 
 #include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
 
-#include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
 #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
 
@@ -463,49 +462,4 @@
   ExpectSameAsRowVRL();
 }
 
-TEST_P(LayoutFlexibleBoxTest, ResizedFlexChildRequiresVisualOverflowRecalc) {
-  SetBodyInnerHTML(R"HTML(
-    <style>
-      #parent {
-        display: flex;
-        flex-direction: column;
-        width: 100px;
-        height: 1000px;
-      }
-      #child1 {
-        flex-grow: 1;
-        width: 100px;
-        will-change: transform;
-      }
-      #overflow-child {
-        width: 100px;
-        height: 950px;
-        box-shadow: 5px 10px;
-      }
-      #child2 {
-        width: 100px;
-      }
-    </style>
-    <div id="parent">
-      <div id="child1">
-        <div id="overflow-child"></div>
-      </div>
-      <div id="child2"></div>
-    </div>
-  )HTML");
-  auto* child1_element = GetElementById("child1");
-  auto* child2_element = GetElementById("child2");
-  child2_element->setAttribute(html_names::kStyleAttr, "height: 100px;");
-  GetDocument().View()->UpdateLifecycleToLayoutClean();
-
-  auto* child1_box = ToLayoutBox(child1_element->GetLayoutObject());
-  ASSERT_TRUE(child1_box->HasSelfPaintingLayer());
-  EXPECT_TRUE(child1_box->Layer()->NeedsVisualOverflowRecalcForTesting());
-
-  UpdateAllLifecyclePhasesForTest();
-
-  EXPECT_EQ(child1_box->PhysicalVisualOverflowRect(),
-            PhysicalRect(0, 0, 105, 960));
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc
index 5fc76c2..15c2d41 100644
--- a/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -1028,7 +1028,9 @@
     DCHECK(!object->IsSetNeedsLayoutForbidden());
 #endif
 
-    object->MarkSelfPaintingLayerForVisualOverflowRecalc();
+    if (object->HasLayer() &&
+        ToLayoutBoxModelObject(object)->Layer()->IsSelfPaintingLayer())
+      ToLayoutBoxModelObject(object)->Layer()->SetNeedsVisualOverflowRecalc();
 
     if (layouter) {
       layouter->RecordObjectMarkedForLayout(object);
@@ -1036,6 +1038,7 @@
       if (object == layouter->Root()) {
         if (auto* painting_layer = PaintingLayer())
           painting_layer->SetNeedsVisualOverflowRecalc();
+
         return;
       }
     }
@@ -1943,7 +1946,12 @@
                  : object->Container();
     if (object) {
       object->SetChildNeedsLayoutOverflowRecalc();
-      object->MarkSelfPaintingLayerForVisualOverflowRecalc();
+
+      if (object->HasLayer()) {
+        auto* box_model_object = ToLayoutBoxModelObject(object);
+        if (box_model_object->HasSelfPaintingLayer())
+          box_model_object->Layer()->SetNeedsVisualOverflowRecalc();
+      }
     }
 
   } while (object);
@@ -1953,8 +1961,12 @@
   bool needed_recalc = SelfNeedsLayoutOverflowRecalc();
   SetSelfNeedsLayoutOverflowRecalc();
   SetShouldCheckForPaintInvalidation();
-  MarkSelfPaintingLayerForVisualOverflowRecalc();
 
+  if (HasLayer()) {
+    auto* box_model_object = ToLayoutBoxModelObject(this);
+    if (box_model_object->HasSelfPaintingLayer())
+      box_model_object->Layer()->SetNeedsVisualOverflowRecalc();
+  }
   if (!needed_recalc)
     MarkContainerChainForOverflowRecalcIfNeeded();
 }
@@ -4063,14 +4075,6 @@
       ->FlipForWritingMode(position, width);
 }
 
-void LayoutObject::MarkSelfPaintingLayerForVisualOverflowRecalc() {
-  if (HasLayer()) {
-    auto* box_model_object = ToLayoutBoxModelObject(this);
-    if (box_model_object->HasSelfPaintingLayer())
-      box_model_object->Layer()->SetNeedsVisualOverflowRecalc();
-  }
-}
-
 }  // namespace blink
 
 #if DCHECK_IS_ON()
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h
index 123edca..b6d7e95 100644
--- a/third_party/blink/renderer/core/layout/layout_object.h
+++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -1405,7 +1405,6 @@
   // when the width of the LayoutObject changes as this impacts children with
   // 'width' set to auto.
   virtual void UpdateLayout() = 0;
-  virtual bool UpdateImageLoadingPriorities() { return false; }
 
   void HandleSubtreeModifications();
   virtual void SubtreeDidChange() {}
@@ -2033,10 +2032,8 @@
   // Called when the previous visual rect(s) is no longer valid.
   virtual void ClearPreviousVisualRects();
 
-  void SetSelfNeedsLayoutForAvailableSpace(bool flag) {
-    bitfields_.SetSelfNeedsLayoutForAvailableSpace(flag);
-    if (flag)
-      MarkSelfPaintingLayerForVisualOverflowRecalc();
+  void SetSelfNeedsLayoutForAvailableSpace(bool b) {
+    bitfields_.SetSelfNeedsLayoutForAvailableSpace(b);
   }
 
   PaintInvalidationReason FullPaintInvalidationReason() const {
@@ -2729,8 +2726,6 @@
       LayoutUnit width,
       const LayoutBox* box_for_flipping) const;
 
-  void MarkSelfPaintingLayerForVisualOverflowRecalc();
-
   // This is set by Set[Subtree]ShouldDoFullPaintInvalidation, and cleared
   // during PrePaint in this object's InvalidatePaint(). It's different from
   // DisplayItemClient::GetPaintInvalidationReason() which is set during
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
index 6b91331..1b86d63 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
@@ -71,20 +71,6 @@
   USING_FAST_MALLOC(NGConstraintSpace);
 
  public:
-  enum ConstraintSpaceFlags {
-    kOrthogonalWritingModeRoot = 1 << 0,
-    kIsFixedBlockSizeIndefinite = 1 << 1,
-    kIntermediateLayout = 1 << 2,
-    kSeparateLeadingFragmentainerMargins = 1 << 3,
-    kNewFormattingContext = 1 << 4,
-    kAnonymous = 1 << 5,
-    kUseFirstLineStyle = 1 << 6,
-    kAncestorHasClearancePastAdjoiningFloats = 1 << 7,
-
-    // Size of bitfield used to store the flags.
-    kNumberOfConstraintSpaceFlags = 8
-  };
-
   // To ensure that the bfc_offset_, rare_data_ union doesn't get polluted,
   // always initialize the bfc_offset_.
   NGConstraintSpace() : bfc_offset_() {}
@@ -158,7 +144,7 @@
   }
 
   bool IsOrthogonalWritingModeRoot() const {
-    return HasFlag(kOrthogonalWritingModeRoot);
+    return bitfields_.is_orthogonal_writing_mode_root;
   }
 
   // The available space size.
@@ -266,7 +252,9 @@
 
   // Whether the current constraint space is for the newly established
   // Formatting Context.
-  bool IsNewFormattingContext() const { return HasFlag(kNewFormattingContext); }
+  bool IsNewFormattingContext() const {
+    return bitfields_.is_new_formatting_context;
+  }
 
   // Return true if we are to separate (i.e. honor, rather than collapse)
   // block-start margins at the beginning of fragmentainers. This only makes a
@@ -274,20 +262,20 @@
   // block-start margins at the beginning of a fragmentainers are to be
   // truncated to 0 if they occur after a soft (unforced) break.
   bool HasSeparateLeadingFragmentainerMargins() const {
-    return HasFlag(kSeparateLeadingFragmentainerMargins);
+    return bitfields_.has_separate_leading_fragmentainer_margins;
   }
 
   // Whether the fragment produced from layout should be anonymous, (e.g. it
   // may be a column in a multi-column layout). In such cases it shouldn't have
   // any borders or padding.
-  bool IsAnonymous() const { return HasFlag(kAnonymous); }
+  bool IsAnonymous() const { return bitfields_.is_anonymous; }
 
   // Whether to use the ':first-line' style or not.
   // Note, this is not about the first line of the content to layout, but
   // whether the constraint space itself is on the first line, such as when it's
   // an inline block.
   // Also note this is true only when the document has ':first-line' rules.
-  bool UseFirstLineStyle() const { return HasFlag(kUseFirstLineStyle); }
+  bool UseFirstLineStyle() const { return bitfields_.use_first_line_style; }
 
   // Returns true if an ancestor had clearance past adjoining floats.
   //
@@ -296,7 +284,7 @@
   // margins are adjoining or not), and without this extra bit of information
   // can get into a bad state.
   bool AncestorHasClearancePastAdjoiningFloats() const {
-    return HasFlag(kAncestorHasClearancePastAdjoiningFloats);
+    return bitfields_.ancestor_has_clearance_past_adjoining_floats;
   }
 
   // Some layout modes “stretch” their children to a fixed size (e.g. flex,
@@ -312,7 +300,7 @@
 
   // Whether a fixed block-size should be considered indefinite.
   bool IsFixedBlockSizeIndefinite() const {
-    return HasFlag(kIsFixedBlockSizeIndefinite);
+    return bitfields_.is_fixed_block_size_indefinite;
   }
 
   // Whether an auto inline-size should be interpreted as shrink-to-fit
@@ -322,7 +310,9 @@
   // Whether this constraint space is used for an intermediate layout in a
   // multi-pass layout. In such a case, we should not copy back the resulting
   // layout data to the legacy tree or create a paint fragment from it.
-  bool IsIntermediateLayout() const { return HasFlag(kIntermediateLayout); }
+  bool IsIntermediateLayout() const {
+    return bitfields_.is_intermediate_layout;
+  }
 
   // If specified a layout should produce a Fragment which fragments at the
   // blockSize if possible.
@@ -595,20 +585,40 @@
           adjoining_object_types(static_cast<unsigned>(kAdjoiningNone)),
           writing_mode(static_cast<unsigned>(writing_mode)),
           direction(static_cast<unsigned>(TextDirection::kLtr)),
+          is_anonymous(false),
+          is_new_formatting_context(false),
+          is_orthogonal_writing_mode_root(false),
+          is_intermediate_layout(false),
+          is_fixed_block_size_indefinite(false),
+          use_first_line_style(false),
+          has_separate_leading_fragmentainer_margins(false),
+          ancestor_has_clearance_past_adjoining_floats(false),
           is_shrink_to_fit(false),
           is_fixed_inline_size(false),
           is_fixed_block_size(false),
           is_in_restricted_block_size_table_cell(false),
           table_cell_child_layout_phase(static_cast<unsigned>(
               NGTableCellChildLayoutPhase::kNotTableCellChild)),
-          flags(),
           percentage_inline_storage(kSameAsAvailable),
           percentage_block_storage(kSameAsAvailable),
           replaced_percentage_block_storage(kSameAsAvailable) {}
 
     bool MaySkipLayout(const Bitfields& other) const {
       return adjoining_object_types == other.adjoining_object_types &&
-             writing_mode == other.writing_mode && flags == other.flags &&
+             writing_mode == other.writing_mode &&
+             direction == other.direction &&
+             is_anonymous == other.is_anonymous &&
+             is_new_formatting_context == other.is_new_formatting_context &&
+             is_orthogonal_writing_mode_root ==
+                 other.is_orthogonal_writing_mode_root &&
+             is_intermediate_layout == other.is_intermediate_layout &&
+             is_fixed_block_size_indefinite ==
+                 other.is_fixed_block_size_indefinite &&
+             use_first_line_style == other.use_first_line_style &&
+             has_separate_leading_fragmentainer_margins ==
+                 other.has_separate_leading_fragmentainer_margins &&
+             ancestor_has_clearance_past_adjoining_floats ==
+                 other.ancestor_has_clearance_past_adjoining_floats &&
              baseline_requests == other.baseline_requests;
     }
 
@@ -627,6 +637,18 @@
     unsigned writing_mode : 3;
     unsigned direction : 1;
 
+    unsigned is_anonymous : 1;
+    unsigned is_new_formatting_context : 1;
+    unsigned is_orthogonal_writing_mode_root : 1;
+    unsigned is_intermediate_layout : 1;
+
+    unsigned is_fixed_block_size_indefinite : 1;
+    unsigned use_first_line_style : 1;
+    unsigned has_separate_leading_fragmentainer_margins : 1;
+    unsigned ancestor_has_clearance_past_adjoining_floats : 1;
+
+    unsigned baseline_requests : NGBaselineRequestList::kSerializedBits;
+
     // Size constraints.
     unsigned is_shrink_to_fit : 1;
     unsigned is_fixed_inline_size : 1;
@@ -634,18 +656,11 @@
     unsigned is_in_restricted_block_size_table_cell : 1;
     unsigned table_cell_child_layout_phase : 2;  // NGTableCellChildLayoutPhase
 
-    unsigned flags : kNumberOfConstraintSpaceFlags;  // ConstraintSpaceFlags
-    unsigned baseline_requests : NGBaselineRequestList::kSerializedBits;
-
     unsigned percentage_inline_storage : 2;           // NGPercentageStorage
     unsigned percentage_block_storage : 2;            // NGPercentageStorage
     unsigned replaced_percentage_block_storage : 2;   // NGPercentageStorage
   };
 
-  inline bool HasFlag(ConstraintSpaceFlags mask) const {
-    return bitfields_.flags & static_cast<unsigned>(mask);
-  }
-
   inline bool HasRareData() const { return bitfields_.has_rare_data; }
 
   RareData* EnsureRareData() {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
index 4f216817..fffe7f1d 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
@@ -30,8 +30,8 @@
                                  out_writing_mode,
                                  is_new_fc) {
     // Propagate the intermediate layout bit to the child constraint space.
-    if (parent_space.IsIntermediateLayout())
-      space_.bitfields_.flags |= NGConstraintSpace::kIntermediateLayout;
+    space_.bitfields_.is_intermediate_layout =
+        parent_space.IsIntermediateLayout();
   }
 
   // The setters on this builder are in the writing mode of parent_writing_mode.
@@ -51,11 +51,9 @@
         is_new_fc_(is_new_fc),
         force_orthogonal_writing_mode_root_(
             force_orthogonal_writing_mode_root) {
-    if (is_new_fc_)
-      space_.bitfields_.flags |= NGConstraintSpace::kNewFormattingContext;
-
-    if (!is_in_parallel_flow_ || force_orthogonal_writing_mode_root_)
-      space_.bitfields_.flags |= NGConstraintSpace::kOrthogonalWritingModeRoot;
+    space_.bitfields_.is_new_formatting_context = is_new_fc_;
+    space_.bitfields_.is_orthogonal_writing_mode_root =
+        !is_in_parallel_flow_ || force_orthogonal_writing_mode_root_;
   }
 
   // If inline size is indefinite, use the fallback size for available inline
@@ -154,7 +152,7 @@
 
   NGConstraintSpaceBuilder& SetIsFixedBlockSizeIndefinite(bool b) {
     if (LIKELY(is_in_parallel_flow_ || !force_orthogonal_writing_mode_root_))
-      SetFlag(NGConstraintSpace::kIsFixedBlockSizeIndefinite, b);
+      space_.bitfields_.is_fixed_block_size_indefinite = b;
 
     return *this;
   }
@@ -165,7 +163,7 @@
   }
 
   NGConstraintSpaceBuilder& SetIsIntermediateLayout(bool b) {
-    SetFlag(NGConstraintSpace::kIntermediateLayout, b);
+    space_.bitfields_.is_intermediate_layout = b;
     return *this;
   }
 
@@ -183,22 +181,22 @@
   }
 
   NGConstraintSpaceBuilder& SetSeparateLeadingFragmentainerMargins(bool b) {
-    SetFlag(NGConstraintSpace::kSeparateLeadingFragmentainerMargins, b);
+    space_.bitfields_.has_separate_leading_fragmentainer_margins = b;
     return *this;
   }
 
   NGConstraintSpaceBuilder& SetIsAnonymous(bool b) {
-    SetFlag(NGConstraintSpace::kAnonymous, b);
+    space_.bitfields_.is_anonymous = b;
     return *this;
   }
 
   NGConstraintSpaceBuilder& SetUseFirstLineStyle(bool b) {
-    SetFlag(NGConstraintSpace::kUseFirstLineStyle, b);
+    space_.bitfields_.use_first_line_style = b;
     return *this;
   }
 
   NGConstraintSpaceBuilder& SetAncestorHasClearancePastAdjoiningFloats() {
-    SetFlag(NGConstraintSpace::kAncestorHasClearancePastAdjoiningFloats, true);
+    space_.bitfields_.ancestor_has_clearance_past_adjoining_floats = true;
     return *this;
   }
 
@@ -312,7 +310,7 @@
 #endif
 
     DCHECK(!is_new_fc_ || !space_.bitfields_.adjoining_object_types);
-    DCHECK_EQ(space_.HasFlag(NGConstraintSpace::kOrthogonalWritingModeRoot),
+    DCHECK_EQ(space_.bitfields_.is_orthogonal_writing_mode_root,
               !is_in_parallel_flow_ || force_orthogonal_writing_mode_root_);
 
     DCHECK(!force_orthogonal_writing_mode_root_ || is_in_parallel_flow_)
@@ -325,12 +323,6 @@
   }
 
  private:
-  void SetFlag(NGConstraintSpace::ConstraintSpaceFlags mask, bool value) {
-    space_.bitfields_.flags =
-        (space_.bitfields_.flags & ~static_cast<unsigned>(mask)) |
-        (-(int32_t)value & static_cast<unsigned>(mask));
-  }
-
   NGConstraintSpace space_;
 
   // Orthogonal writing mode roots may need a fallback, to prevent available
diff --git a/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
index ae70642..3ecba77 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
@@ -361,7 +361,6 @@
     cross_axis_offset = border_scrollbar_padding_.inline_start;
   }
   FlexLine* line;
-  LayoutUnit max_main_axis_extent;
   while (
       (line = algorithm_->ComputeNextFlexLine(border_box_size_.inline_size))) {
     line->SetContainerMainInnerSize(
@@ -415,21 +414,15 @@
     // cross_axis_offset is updated in each iteration of the loop, for passing
     // in to the next iteration.
     line->ComputeLineItemsPosition(main_axis_offset, cross_axis_offset);
-    max_main_axis_extent =
-        std::max(max_main_axis_extent, line->main_axis_extent);
   }
-  LayoutUnit intrinsic_block_content_size =
-      is_column_ ? max_main_axis_extent
-                 : cross_axis_offset - border_scrollbar_padding_.block_start;
-  LayoutUnit intrinsic_block_size =
-      intrinsic_block_content_size + border_scrollbar_padding_.BlockSum();
+
+  LayoutUnit intrinsic_block_size = algorithm_->IntrinsicContentBlockSize() +
+                                    border_scrollbar_padding_.BlockSum();
   LayoutUnit block_size = ComputeBlockSizeForFragment(
       ConstraintSpace(), Node(), border_padding_, intrinsic_block_size);
 
+  container_builder_.SetIntrinsicBlockSize(intrinsic_block_size);
   container_builder_.SetBlockSize(block_size);
-  container_builder_.SetIntrinsicBlockSize(
-      algorithm_->IntrinsicContentBlockSize() +
-      border_scrollbar_padding_.BlockSum());
 
   GiveLinesAndItemsFinalPositionAndSize();
 
diff --git a/third_party/blink/renderer/core/page/context_menu_controller_test.cc b/third_party/blink/renderer/core/page/context_menu_controller_test.cc
index 1c840bb..7746066a 100644
--- a/third_party/blink/renderer/core/page/context_menu_controller_test.cc
+++ b/third_party/blink/renderer/core/page/context_menu_controller_test.cc
@@ -45,6 +45,7 @@
 
   WebMediaPlayer* CreateMediaPlayer(const WebMediaPlayerSource&,
                                     WebMediaPlayerClient*,
+                                    blink::MediaInspectorContext*,
                                     WebMediaPlayerEncryptedMediaClient*,
                                     WebContentDecryptionModule*,
                                     const WebString& sink_id,
diff --git a/third_party/blink/renderer/core/paint/paint_layer.h b/third_party/blink/renderer/core/paint/paint_layer.h
index d5c21ddc..8ed44402 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.h
+++ b/third_party/blink/renderer/core/paint/paint_layer.h
@@ -1108,10 +1108,6 @@
 
   void DirtyStackingContextZOrderLists();
 
-  bool NeedsVisualOverflowRecalcForTesting() const {
-    return needs_visual_overflow_recalc_;
-  }
-
   PhysicalOffset OffsetForInFlowRelPosition() const {
     return rare_data_ ? rare_data_->offset_for_in_flow_rel_position
                       : PhysicalOffset();
diff --git a/third_party/blink/renderer/core/scroll/scrollable_area.cc b/third_party/blink/renderer/core/scroll/scrollable_area.cc
index 93340f2a..a876957 100644
--- a/third_party/blink/renderer/core/scroll/scrollable_area.cc
+++ b/third_party/blink/renderer/core/scroll/scrollable_area.cc
@@ -300,13 +300,12 @@
   CancelScrollAnimation();
 
   ScrollCallback callback = std::move(on_finish);
-  if (RuntimeEnabledFeatures::UpdateHoverAtBeginFrameEnabled() ||
-      RuntimeEnabledFeatures::OverscrollCustomizationEnabled()) {
+  if (RuntimeEnabledFeatures::UpdateHoverAtBeginFrameEnabled()) {
     callback = ScrollCallback(WTF::Bind(
         [](ScrollCallback original_callback,
            WeakPersistent<ScrollableArea> area) {
           if (area)
-            area->OnScrollFinished();
+            area->MarkHoverStateDirty();
           if (original_callback)
             std::move(original_callback).Run();
         },
@@ -818,19 +817,13 @@
       scrollable_element_id.GetInternalValue(), element_id_namespace);
 }
 
-void ScrollableArea::OnScrollFinished() {
+void ScrollableArea::MarkHoverStateDirty() {
   if (GetLayoutBox()) {
-    if (RuntimeEnabledFeatures::OverscrollCustomizationEnabled()) {
-      if (Node* node = GetLayoutBox()->GetNode())
-        node->GetDocument().EnqueueScrollEndEventForNode(node);
-    }
-    if (RuntimeEnabledFeatures::UpdateHoverAtBeginFrameEnabled()) {
-      GetLayoutBox()
-          ->GetFrame()
-          ->LocalFrameRoot()
-          .GetEventHandler()
-          .MarkHoverStateDirty();
-    }
+    GetLayoutBox()
+        ->GetFrame()
+        ->LocalFrameRoot()
+        .GetEventHandler()
+        .MarkHoverStateDirty();
   }
 }
 
diff --git a/third_party/blink/renderer/core/scroll/scrollable_area.h b/third_party/blink/renderer/core/scroll/scrollable_area.h
index b380848b..0ea6877 100644
--- a/third_party/blink/renderer/core/scroll/scrollable_area.h
+++ b/third_party/blink/renderer/core/scroll/scrollable_area.h
@@ -416,7 +416,7 @@
 
   virtual ScrollbarTheme& GetPageScrollbarTheme() const = 0;
 
-  void OnScrollFinished();
+  virtual void MarkHoverStateDirty();
 
   float ScrollStep(ScrollGranularity, ScrollbarOrientation) const;
 
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.cc b/third_party/blink/renderer/modules/accessibility/ax_object.cc
index d6a8c88..249d5e4d 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_object.cc
@@ -1425,7 +1425,7 @@
 }
 
 bool AXObject::HasIndirectChildren() const {
-  return IsTableCol() || RoleValue() == ax::mojom::Role::kTableHeaderContainer;
+  return RoleValue() == ax::mojom::Role::kTableHeaderContainer;
 }
 
 bool AXObject::CanSetSelectedAttribute() const {
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.h b/third_party/blink/renderer/modules/accessibility/ax_object.h
index efe16d1..129600f6d 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_object.h
@@ -384,7 +384,7 @@
 
   void TokenVectorFromAttribute(Vector<String>&, const QualifiedName&) const;
 
-  virtual void GetSparseAXAttributes(AXSparseAttributeClient&) const;
+  void GetSparseAXAttributes(AXSparseAttributeClient&) const;
 
   // Determine subclass type.
   virtual bool IsAXNodeObject() const { return false; }
@@ -398,7 +398,6 @@
   // Check object role or purpose.
   virtual ax::mojom::Role RoleValue() const { return role_; }
   bool IsARIATextControl() const;
-  virtual bool IsARIARow() const { return false; }
   virtual bool IsAnchor() const { return false; }
   bool IsButton() const;
   bool IsCanvas() const { return RoleValue() == ax::mojom::Role::kCanvas; }
@@ -435,7 +434,7 @@
     return false;
   }  // contenteditable or role=textbox
   virtual bool IsPasswordField() const { return false; }
-  virtual bool IsPasswordFieldAndShouldHideValue() const;
+  bool IsPasswordFieldAndShouldHideValue() const;
   bool IsPresentational() const {
     return RoleValue() == ax::mojom::Role::kNone ||
            RoleValue() == ax::mojom::Role::kPresentational;
@@ -498,7 +497,7 @@
   virtual bool IsVisited() const { return false; }
 
   // Check whether certain properties can be modified.
-  virtual bool CanSetFocusAttribute() const;
+  bool CanSetFocusAttribute() const;
   bool CanSetValueAttribute() const;
 
   // Whether objects are ignored, i.e. hidden from the AT.
@@ -553,7 +552,7 @@
   typedef HeapVector<NameSource> NameSources;
   // Retrieves the accessible name of the object and a list of all potential
   // sources for the name, indicating which were used.
-  virtual String GetName(NameSources*) const;
+  String GetName(NameSources*) const;
 
   typedef HeapVector<DescriptionSource> DescriptionSources;
   // Takes the result of nameFrom from calling |name|, above, and retrieves the
@@ -888,9 +887,8 @@
   virtual bool NeedsToUpdateChildren() const { return false; }
   virtual void SetNeedsToUpdateChildren() {}
   virtual void ClearChildren();
-  virtual void DetachFromParent() { parent_ = nullptr; }
-  virtual AXObject* ScrollBar(AccessibilityOrientation) { return nullptr; }
-  virtual void AddAccessibleNodeChildren();
+  void DetachFromParent() { parent_ = nullptr; }
+  void AddAccessibleNodeChildren();
   virtual void SelectedOptions(AXObjectVector&) const {}
 
   // Properties of the object's owning document or page.
@@ -898,7 +896,7 @@
 
   // DOM and layout tree access.
   virtual Node* GetNode() const { return nullptr; }
-  virtual Element* GetElement() const;  // Same as GetNode, if it's an Element.
+  Element* GetElement() const;  // Same as GetNode, if it's an Element.
   virtual LayoutObject* GetLayoutObject() const { return nullptr; }
   virtual Document* GetDocument() const;
   virtual LocalFrameView* DocumentFrameView() const;
@@ -916,11 +914,10 @@
   void SetScrollOffset(const IntPoint&) const;
 
   // Tables and grids.
-  virtual bool IsTableLikeRole() const;
-  virtual bool IsTableRowLikeRole() const;
-  virtual bool IsTableCellLikeRole() const;
+  bool IsTableLikeRole() const;
+  bool IsTableRowLikeRole() const;
+  bool IsTableCellLikeRole() const;
   virtual bool IsDataTable() const { return false; }
-  virtual bool IsTableCol() const { return false; }
 
   // For a table.
   virtual unsigned ColumnCount() const;
@@ -934,10 +931,10 @@
   virtual unsigned RowIndex() const;
   virtual unsigned ColumnSpan() const;
   virtual unsigned RowSpan() const;
-  virtual unsigned AriaColumnIndex() const;
-  virtual unsigned AriaRowIndex() const;
-  virtual int AriaColumnCount() const;
-  virtual int AriaRowCount() const;
+  unsigned AriaColumnIndex() const;
+  unsigned AriaRowIndex() const;
+  int AriaColumnCount() const;
+  int AriaRowCount() const;
   virtual ax::mojom::SortDirection GetSortDirection() const {
     return ax::mojom::SortDirection::kNone;
   }
@@ -980,8 +977,8 @@
   // to keep track of nodes that gain or lose accessibility focus, but
   // this isn't exposed to the open web so they're explicitly marked as
   // internal so it's clear that these should not dispatch DOM events.
-  virtual bool InternalClearAccessibilityFocusAction();
-  virtual bool InternalSetAccessibilityFocusAction();
+  bool InternalClearAccessibilityFocusAction();
+  bool InternalSetAccessibilityFocusAction();
 
   // Native implementations of actions that aren't handled by AOM
   // event listeners. These all return true if handled.
@@ -989,16 +986,16 @@
   virtual bool OnNativeClickAction();
   virtual bool OnNativeFocusAction();
   virtual bool OnNativeIncrementAction();
-  virtual bool OnNativeScrollToGlobalPointAction(const IntPoint&) const;
-  virtual bool OnNativeScrollToMakeVisibleAction() const;
-  virtual bool OnNativeScrollToMakeVisibleWithSubFocusAction(
+  bool OnNativeScrollToGlobalPointAction(const IntPoint&) const;
+  bool OnNativeScrollToMakeVisibleAction() const;
+  bool OnNativeScrollToMakeVisibleWithSubFocusAction(
       const IntRect&,
       blink::ScrollAlignment horizontal_scroll_alignment,
       blink::ScrollAlignment vertical_scroll_alignment) const;
   virtual bool OnNativeSetSelectedAction(bool);
   virtual bool OnNativeSetSequentialFocusNavigationStartingPointAction();
   virtual bool OnNativeSetValueAction(const String&);
-  virtual bool OnNativeShowContextMenuAction();
+  bool OnNativeShowContextMenuAction();
 
   // Notifications that this object may have changed.
   virtual void ChildrenChanged() {}
@@ -1087,7 +1084,7 @@
     return nullptr;
   }
 
-  virtual bool CanSetSelectedAttribute() const;
+  bool CanSetSelectedAttribute() const;
   const AXObject* InertRoot() const;
 
   // Returns true if the event was handled.
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.cc b/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.cc
index 1d442f7d..623bc5c8 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.cc
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "services/service_manager/public/cpp/interface_provider.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
 #include "third_party/blink/renderer/modules/background_fetch/background_fetch_options.h"
 #include "third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h"
 #include "third_party/blink/renderer/modules/background_fetch/background_fetch_type_converters.h"
@@ -93,14 +94,14 @@
 
 mojom::blink::BackgroundFetchService* BackgroundFetchBridge::GetService() {
   if (!background_fetch_service_) {
-    auto request = mojo::MakeRequest(
-        &background_fetch_service_,
+    auto receiver = background_fetch_service_.BindNewPipeAndPassReceiver(
         GetSupplementable()->GetExecutionContext()->GetTaskRunner(
             TaskType::kBackgroundFetch));
-    if (auto* interface_provider = GetSupplementable()
-                                       ->GetExecutionContext()
-                                       ->GetInterfaceProvider()) {
-      interface_provider->GetInterface(std::move(request));
+    if (auto* browser_interface_broker_proxy =
+            GetSupplementable()
+                ->GetExecutionContext()
+                ->GetBrowserInterfaceBrokerProxy()) {
+      browser_interface_broker_proxy->GetInterface(std::move(receiver));
     }
   }
   return background_fetch_service_.get();
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.h b/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.h
index 0d655c0..f88536db 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.h
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/public/mojom/background_fetch/background_fetch.mojom-blink.h"
 #include "third_party/blink/renderer/modules/service_worker/service_worker_registration.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
@@ -79,7 +80,7 @@
       mojom::blink::BackgroundFetchError error,
       mojom::blink::BackgroundFetchRegistrationPtr registration_ptr);
 
-  mojom::blink::BackgroundFetchServicePtr background_fetch_service_;
+  mojo::Remote<mojom::blink::BackgroundFetchService> background_fetch_service_;
 
   DISALLOW_COPY_AND_ASSIGN(BackgroundFetchBridge);
 };
diff --git a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
index 6dc2791..2aaecb0 100644
--- a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
+++ b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
@@ -80,7 +80,8 @@
         installed_scripts_manager_params,
     mojo::ScopedMessagePipeHandle content_settings_handle,
     mojo::ScopedMessagePipeHandle cache_storage,
-    mojo::ScopedMessagePipeHandle interface_provider) {
+    mojo::ScopedMessagePipeHandle interface_provider,
+    mojo::ScopedMessagePipeHandle browser_interface_broker) {
   return std::make_unique<WebEmbeddedWorkerImpl>(
       std::move(client), std::move(installed_scripts_manager_params),
       std::make_unique<ServiceWorkerContentSettingsProxy>(
@@ -92,7 +93,10 @@
                                         mojom::blink::CacheStorage::Version_),
       service_manager::mojom::blink::InterfaceProviderPtrInfo(
           std::move(interface_provider),
-          service_manager::mojom::blink::InterfaceProvider::Version_));
+          service_manager::mojom::blink::InterfaceProvider::Version_),
+      mojo::PendingRemote<mojom::blink::BrowserInterfaceBroker>(
+          std::move(browser_interface_broker),
+          mojom::blink::BrowserInterfaceBroker::Version_));
 }
 
 // static
@@ -104,7 +108,8 @@
       client, nullptr /* installed_scripts_manager_params */,
       std::make_unique<ServiceWorkerContentSettingsProxy>(
           nullptr /* host_info */),
-      nullptr /* cache_storage_info */, nullptr /* interface_provider_info */);
+      nullptr /* cache_storage_info */, nullptr /* interface_provider_info */,
+      mojo::NullRemote() /* browser_interface_broker */);
   worker_impl->installed_scripts_manager_ =
       std::move(installed_scripts_manager);
   return worker_impl;
@@ -117,12 +122,15 @@
     std::unique_ptr<ServiceWorkerContentSettingsProxy> content_settings_client,
     mojom::blink::CacheStoragePtrInfo cache_storage_info,
     service_manager::mojom::blink::InterfaceProviderPtrInfo
-        interface_provider_info)
+        interface_provider_info,
+    mojo::PendingRemote<mojom::blink::BrowserInterfaceBroker>
+        browser_interface_broker)
     : worker_context_client_(client),
       content_settings_client_(std::move(content_settings_client)),
       pause_after_download_state_(kDontPauseAfterDownload),
       cache_storage_info_(std::move(cache_storage_info)),
-      interface_provider_info_(std::move(interface_provider_info)) {
+      interface_provider_info_(std::move(interface_provider_info)),
+      browser_interface_broker_(std::move(browser_interface_broker)) {
   if (installed_scripts_manager_params) {
     DCHECK(installed_scripts_manager_params->manager_request.is_valid());
     DCHECK(installed_scripts_manager_params->manager_host_ptr.is_valid());
@@ -289,8 +297,7 @@
       std::move(worker_settings),
       static_cast<V8CacheOptions>(worker_start_data_.v8_cache_options),
       nullptr /* worklet_module_respones_map */,
-      std::move(interface_provider_info_),
-      mojo::NullRemote() /* TODO(crbug.com/985112) pass a real BIB */,
+      std::move(interface_provider_info_), std::move(browser_interface_broker_),
       BeginFrameProviderParams(), nullptr /* parent_feature_policy */,
       base::UnguessableToken() /* agent_cluster_id */);
 
diff --git a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h
index 00d53a5..734b269 100644
--- a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h
+++ b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h
@@ -68,7 +68,8 @@
       std::unique_ptr<WebServiceWorkerInstalledScriptsManagerParams>,
       std::unique_ptr<ServiceWorkerContentSettingsProxy>,
       mojom::blink::CacheStoragePtrInfo,
-      service_manager::mojom::blink::InterfaceProviderPtrInfo);
+      service_manager::mojom::blink::InterfaceProviderPtrInfo,
+      mojo::PendingRemote<mojom::blink::BrowserInterfaceBroker>);
   ~WebEmbeddedWorkerImpl() override;
 
   // WebEmbeddedWorker overrides.
@@ -132,6 +133,9 @@
   service_manager::mojom::blink::InterfaceProviderPtrInfo
       interface_provider_info_;
 
+  mojo::PendingRemote<mojom::blink::BrowserInterfaceBroker>
+      browser_interface_broker_;
+
   DISALLOW_COPY_AND_ASSIGN(WebEmbeddedWorkerImpl);
 };
 
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor.cc b/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor.cc
index 9703ade..de71c6e07 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor.cc
@@ -10,7 +10,6 @@
 #include <limits>
 #include <string>
 #include <utility>
-#include <vector>
 
 #include "base/feature_list.h"
 #include "base/metrics/field_trial.h"
@@ -18,8 +17,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/optional.h"
 #include "base/single_thread_task_runner.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/task/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
@@ -33,6 +30,7 @@
 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
 #include "third_party/blink/renderer/platform/scheduler/public/worker_pool.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
 #include "third_party/webrtc/api/audio/echo_canceller3_config.h"
 #include "third_party/webrtc/api/audio/echo_canceller3_config_json.h"
 #include "third_party/webrtc/api/audio/echo_canceller3_factory.h"
@@ -462,7 +460,7 @@
   // supported.
   int channels = std::min(2, audio_bus->channels());
 
-  std::vector<const float*> channel_ptrs(channels);
+  Vector<const float*> channel_ptrs(channels);
   for (int i = 0; i < channels; ++i)
     channel_ptrs[i] = audio_bus->channel(i);
 
diff --git a/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.cc b/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.cc
index c293359..c328b94 100644
--- a/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.cc
+++ b/third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.cc
@@ -55,10 +55,9 @@
     const scoped_refptr<media::VideoFrame> frame =
         media::VideoFrame::CreateColorFrame(format_.frame_size, 0, 0, 0,
                                             base::TimeDelta());
-    // TODO(crbug.com/964947): Remove the rebind of |frame_callback_|.
     PostCrossThreadTask(
         *io_task_runner(), FROM_HERE,
-        CrossThreadBindRepeating(frame_callback_, frame, base::TimeTicks()));
+        CrossThreadBindOnce(frame_callback_, frame, base::TimeTicks()));
   }
 }
 
@@ -97,11 +96,9 @@
     scoped_refptr<media::VideoFrame> frame) {
   DCHECK(!is_stopped_for_restart_);
   DCHECK(!frame_callback_.is_null());
-  // TODO(crbug.com/964947): Remove the rebind of |frame_callback_|.
-  PostCrossThreadTask(
-      *io_task_runner(), FROM_HERE,
-      CrossThreadBindRepeating(frame_callback_, std::move(frame),
-                               base::TimeTicks()));
+  PostCrossThreadTask(*io_task_runner(), FROM_HERE,
+                      CrossThreadBindOnce(frame_callback_, std::move(frame),
+                                          base::TimeTicks()));
 }
 
 void MockMediaStreamVideoSource::StopSourceForRestartImpl() {
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
index 3a19ebf..71d7734b 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
+++ b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
@@ -8,6 +8,7 @@
 
 #include <algorithm>
 #include <utility>
+#include <vector>
 
 #include "base/location.h"
 #include "base/logging.h"
@@ -28,6 +29,7 @@
 #include "third_party/blink/public/platform/web_media_stream_track.h"
 #include "third_party/blink/public/platform/web_screen_info.h"
 #include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/public/platform/web_vector.h"
 #include "third_party/blink/public/web/modules/mediastream/media_stream_constraints_util.h"
 #include "third_party/blink/public/web/modules/mediastream/media_stream_video_track.h"
 #include "third_party/blink/public/web/modules/mediastream/processed_local_audio_source.h"
@@ -93,11 +95,11 @@
   MediaStreamType* stream_type = &track_controls->stream_type;
   *stream_type = MediaStreamType::NO_SERVICE;
 
-  std::string source_constraint =
+  String source_constraint =
       constraints.Basic().media_stream_source.Exact().empty()
-          ? std::string()
-          : constraints.Basic().media_stream_source.Exact()[0].Utf8();
-  if (!source_constraint.empty()) {
+          ? String()
+          : String(constraints.Basic().media_stream_source.Exact()[0]);
+  if (!source_constraint.IsEmpty()) {
     if (source_constraint == blink::kMediaStreamSourceTab) {
       *stream_type = MediaStreamType::GUM_TAB_AUDIO_CAPTURE;
     } else if (source_constraint == blink::kMediaStreamSourceDesktop ||
@@ -128,11 +130,11 @@
   MediaStreamType* stream_type = &track_controls->stream_type;
   *stream_type = MediaStreamType::NO_SERVICE;
 
-  std::string source_constraint =
+  String source_constraint =
       constraints.Basic().media_stream_source.Exact().empty()
-          ? std::string()
-          : constraints.Basic().media_stream_source.Exact()[0].Utf8();
-  if (!source_constraint.empty()) {
+          ? String()
+          : String(constraints.Basic().media_stream_source.Exact()[0]);
+  if (!source_constraint.IsEmpty()) {
     if (source_constraint == blink::kMediaStreamSourceTab) {
       *stream_type = MediaStreamType::GUM_TAB_VIDEO_CAPTURE;
     } else if (source_constraint == blink::kMediaStreamSourceDesktop ||
@@ -571,7 +573,7 @@
     // will contain the same non-reconfigurable settings that limit the
     // associated capabilities.
     blink::MediaStreamAudioSource* audio_source = nullptr;
-    auto it =
+    auto* it =
         std::find_if(local_sources_.begin(), local_sources_.end(),
                      [&device](const blink::WebMediaStreamSource& web_source) {
                        DCHECK(!web_source.IsNull());
@@ -643,7 +645,7 @@
 
   // Create a copy of the blink::WebMediaStreamSource objects that are
   // associated to the same audio device capture based on its device ID.
-  std::vector<blink::WebMediaStreamSource> matching_sources;
+  Vector<blink::WebMediaStreamSource> matching_sources;
   std::copy_if(local_sources_.begin(), local_sources_.end(),
                std::back_inserter(matching_sources),
                [&device_id](const blink::WebMediaStreamSource& web_source) {
@@ -653,7 +655,7 @@
 
   // Return the session ID associated to the source that has the same settings
   // that have been previously selected, if one exists.
-  if (!matching_sources.empty()) {
+  if (!matching_sources.IsEmpty()) {
     for (auto& matching_source : matching_sources) {
       blink::MediaStreamAudioSource* audio_source =
           static_cast<blink::MediaStreamAudioSource*>(
@@ -932,7 +934,7 @@
     const String& result_name) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
-  for (auto it = pending_local_sources_.begin();
+  for (auto* it = pending_local_sources_.begin();
        it != pending_local_sources_.end(); ++it) {
     blink::WebPlatformMediaStreamSource* const source_extra_data =
         it->GetPlatformSource();
@@ -1205,17 +1207,19 @@
       ToStdVector(current_request_info_->video_devices()),
       weak_factory_.GetWeakPtr());
 
-  blink::WebVector<blink::WebMediaStreamTrack> audio_tracks(
+  Vector<blink::WebMediaStreamTrack> audio_tracks(
       current_request_info_->audio_devices().size());
   CreateAudioTracks(current_request_info_->audio_devices(), &audio_tracks);
 
-  blink::WebVector<blink::WebMediaStreamTrack> video_tracks(
+  Vector<blink::WebMediaStreamTrack> video_tracks(
       current_request_info_->video_devices().size());
   CreateVideoTracks(current_request_info_->video_devices(), &video_tracks);
 
   String blink_id = label;
-  current_request_info_->web_stream()->Initialize(blink_id, audio_tracks,
-                                                  video_tracks);
+  current_request_info_->web_stream()->Initialize(
+      blink_id,
+      WebVector<WebMediaStreamTrack>(audio_tracks.data(), audio_tracks.size()),
+      WebVector<WebMediaStreamTrack>(video_tracks.data(), video_tracks.size()));
 
   // Wait for the tracks to be started successfully or to fail.
   current_request_info_->CallbackOnTracksStarted(
@@ -1225,7 +1229,7 @@
 
 void UserMediaProcessor::CreateVideoTracks(
     const Vector<MediaStreamDevice>& devices,
-    blink::WebVector<blink::WebMediaStreamTrack>* webkit_tracks) {
+    Vector<blink::WebMediaStreamTrack>* webkit_tracks) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(current_request_info_);
   DCHECK_EQ(devices.size(), webkit_tracks->size());
@@ -1240,7 +1244,7 @@
 
 void UserMediaProcessor::CreateAudioTracks(
     const Vector<MediaStreamDevice>& devices,
-    blink::WebVector<blink::WebMediaStreamTrack>* webkit_tracks) {
+    Vector<blink::WebMediaStreamTrack>* webkit_tracks) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(current_request_info_);
   DCHECK_EQ(devices.size(), webkit_tracks->size());
@@ -1479,7 +1483,7 @@
     const blink::WebMediaStreamSource& source) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
-  for (auto device_it = local_sources_.begin();
+  for (auto* device_it = local_sources_.begin();
        device_it != local_sources_.end(); ++device_it) {
     if (IsSameSource(*device_it, source)) {
       local_sources_.erase(device_it);
@@ -1488,7 +1492,7 @@
   }
 
   // Check if the source was pending.
-  for (auto device_it = pending_local_sources_.begin();
+  for (auto* device_it = pending_local_sources_.begin();
        device_it != pending_local_sources_.end(); ++device_it) {
     if (IsSameSource(*device_it, source)) {
       blink::WebPlatformMediaStreamSource* const source_extra_data =
@@ -1560,7 +1564,7 @@
   request_completed_cb_.Reset();
 
   // Loop through all current local sources and stop the sources.
-  auto it = local_sources_.begin();
+  auto* it = local_sources_.begin();
   while (it != local_sources_.end()) {
     StopLocalSource(*it, true);
     it = local_sources_.erase(it);
@@ -1603,7 +1607,7 @@
 }
 
 bool UserMediaProcessor::HasActiveSources() const {
-  return !local_sources_.empty();
+  return !local_sources_.IsEmpty();
 }
 
 const blink::mojom::blink::MediaStreamDispatcherHostPtr&
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_processor.h b/third_party/blink/renderer/modules/mediastream/user_media_processor.h
index 47d04c6..fcb8d5cc 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_processor.h
+++ b/third_party/blink/renderer/modules/mediastream/user_media_processor.h
@@ -6,9 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_USER_MEDIA_PROCESSOR_H_
 
 #include <memory>
-#include <string>
 #include <utility>
-#include <vector>
 
 #include "base/callback_forward.h"
 #include "base/macros.h"
@@ -19,7 +17,6 @@
 #include "third_party/blink/public/mojom/mediastream/media_devices.mojom-blink.h"
 #include "third_party/blink/public/mojom/mediastream/media_stream.mojom-blink.h"
 #include "third_party/blink/public/platform/modules/mediastream/web_platform_media_stream_source.h"
-#include "third_party/blink/public/platform/web_vector.h"
 #include "third_party/blink/public/web/web_user_media_request.h"
 #include "third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
@@ -140,7 +137,7 @@
 
  private:
   class RequestInfo;
-  using LocalStreamSources = std::vector<blink::WebMediaStreamSource>;
+  using LocalStreamSources = Vector<blink::WebMediaStreamSource>;
 
   void OnStreamGenerated(int request_id,
                          blink::mojom::blink::MediaStreamRequestResult result,
@@ -185,13 +182,11 @@
 
   void StartTracks(const String& label);
 
-  void CreateVideoTracks(
-      const Vector<blink::MediaStreamDevice>& devices,
-      blink::WebVector<blink::WebMediaStreamTrack>* webkit_tracks);
+  void CreateVideoTracks(const Vector<blink::MediaStreamDevice>& devices,
+                         Vector<blink::WebMediaStreamTrack>* webkit_tracks);
 
-  void CreateAudioTracks(
-      const Vector<blink::MediaStreamDevice>& devices,
-      blink::WebVector<blink::WebMediaStreamTrack>* webkit_tracks);
+  void CreateAudioTracks(const Vector<blink::MediaStreamDevice>& devices,
+                         Vector<blink::WebMediaStreamTrack>* webkit_tracks);
 
   // Callback function triggered when all native versions of the
   // underlying media sources and tracks have been created and started.
diff --git a/third_party/blink/renderer/modules/modules_initializer.cc b/third_party/blink/renderer/modules/modules_initializer.cc
index ed6e4041..b3d54123 100644
--- a/third_party/blink/renderer/modules/modules_initializer.cc
+++ b/third_party/blink/renderer/modules/modules_initializer.cc
@@ -273,8 +273,10 @@
       HTMLMediaElementEncryptedMedia::From(html_media_element);
   WebString sink_id(
       HTMLMediaElementAudioOutputDevice::sinkId(html_media_element));
+  MediaInspectorContextImpl* context_impl =
+      MediaInspectorContextImpl::FromHtmlMediaElement(html_media_element);
   return base::WrapUnique(web_frame_client->CreateMediaPlayer(
-      source, media_player_client, &encrypted_media,
+      source, media_player_client, context_impl, &encrypted_media,
       encrypted_media.ContentDecryptionModule(), sink_id, view));
 }
 
diff --git a/third_party/blink/renderer/platform/image-decoders/png/png_image_reader.cc b/third_party/blink/renderer/platform/image-decoders/png/png_image_reader.cc
index dfe6bdf..54c4299e 100644
--- a/third_party/blink/renderer/platform/image-decoders/png/png_image_reader.cc
+++ b/third_party/blink/renderer/platform/image-decoders/png/png_image_reader.cc
@@ -688,8 +688,18 @@
     return false;
   if (!frame_width || !frame_height)
     return false;
-  if (x_offset + frame_width > width_ || y_offset + frame_height > height_)
-    return false;
+  {
+    png_uint_32 frame_right;
+    if (!base::CheckAdd(x_offset, frame_width).AssignIfValid(&frame_right) ||
+        frame_right > width_)
+      return false;
+  }
+  {
+    png_uint_32 frame_bottom;
+    if (!base::CheckAdd(y_offset, frame_height).AssignIfValid(&frame_bottom) ||
+        frame_bottom > height_)
+      return false;
+  }
 
   new_frame_.frame_rect =
       IntRect(x_offset, y_offset, frame_width, frame_height);
diff --git a/third_party/blink/web_tests/MSANExpectations b/third_party/blink/web_tests/MSANExpectations
index 13ac6f1..2b13dab 100644
--- a/third_party/blink/web_tests/MSANExpectations
+++ b/third_party/blink/web_tests/MSANExpectations
@@ -52,6 +52,12 @@
 
 crbug.com/810963 [ Linux ] external/wpt/dom/interfaces.html [ Timeout ]
 
+crbug.com/993468 [ Linux ] external/wpt/html/interaction/focus/sequential-focus-navigation-and-the-tabindex-attribute/focus-tabindex-zero.html [ Timeout ]
+crbug.com/993468 [ Linux ] external/wpt/html/semantics/document-metadata/the-link-element/stylesheet-not-removed-until-next-stylesheet-loads.html [ Timeout ]
+crbug.com/993468 [ Linux ] external/wpt/infrastructure/reftest/reftest_ref_timeout.html [ Timeout ]
+crbug.com/993468 [ Linux ] external/wpt/vibration/idlharness.window.html [ Timeout ]
+crbug.com/993468 [ Linux ] external/wpt/xslt/idlharness.tentative.window.html [ Timeout ]
+
 # Intentionally failed allocations, via partitionAllocGenericFlags()
 crbug.com/577889 [ Linux ] fast/js/typed-array-allocation-failure.html [ Crash ]
 
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index f9956169..5e50d8c 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -241,6 +241,11 @@
 crbug.com/857490 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-fling-with-page-scale.html [ Skip ]
 crbug.com/857490 virtual/scroll_customization/fast/scroll-behavior/scroll-customization/touch-scroll-customization.html [ Skip ]
 
+# Currently on main thread scrolling path, scrollend gets fired without waiting for scroll/fling snap animation. (The virtual/threaded version of the test passes.)
+crbug.com/907601 fast/scrolling/events/scrollend-event-fired-after-snap.html [ Skip ]
+crbug.com/907601 virtual/scroll_customization/fast/scrolling/events/scrollend-event-fired-after-snap.html [ Skip ]
+crbug.com/907601 external/wpt/dom/events/scrolling/scrollend-event-fired-after-snap.html [ Skip ]
+
 crbug.com/980969 [ Mac ] http/tests/input/discard-events-to-unstable-iframe.html [ Pass Failure ]
 
 # Display locking, run highlight-display-locked.js only with display locking.
@@ -1879,10 +1884,8 @@
 
 ### virtual/layout_ng_experimental/css3/flexbox/
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/auto-height-column-with-border-and-padding.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/auto-height-with-flex.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/box-sizing-min-max-sizes.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/columns-height-set-via-top-bottom.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/content-height-with-scrollbars.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-align-baseline.html [ Skip ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-align-column.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-align-end.html [ Failure ]
@@ -1900,7 +1903,6 @@
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-order.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flexbox-baseline-margins.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flexbox-baseline.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flexbox-height-with-overflow-auto.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flexbox-overflow-auto.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flexitem.html [ Crash Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/inline-flexbox-wrap-vertically-width-calculation.html [ Failure ]
@@ -1913,13 +1915,11 @@
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/multiline-reverse-wrap-overflow.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/multiline.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/negative-overflow.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/nested-stretch.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/order-painting.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/overflow-auto-resizes-correctly.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/overflow-keep-scrollpos.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/percentage-height-replaced-element.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/position-absolute-child.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/preferred-widths.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/relayout-align-items.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/relpos-with-percentage-top.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/stretch-input-in-column.html [ Failure ]
@@ -1930,7 +1930,6 @@
 
 ### virtual/layout_ng_experimental/css3/flexbox/mozilla/
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/mozilla/flexbox-items-as-stacking-contexts-2.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/mozilla/flexbox-sizing-vert-1.xhtml [ Failure ]
 
 ### virtual/layout_ng_experimental/external/wpt/css/css-flexbox/
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/Flexible-order.html [ Failure ]
@@ -1986,14 +1985,12 @@
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_align-self-flexstart.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_align-self-stretch.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_direction-column-reverse.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_direction-column.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_flow-column-reverse-wrap-reverse.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_flow-column-reverse-wrap.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_flow-column-wrap-reverse.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_flow-row-wrap-reverse.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_inline.html [ Failure ]
 crbug.com/467127 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_justifycontent-center-overflow.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_margin-collapse.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_order-box.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_order.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_quirks_body.html [ Failure ]
@@ -2015,7 +2012,6 @@
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/scrollbars.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/table-as-item-auto-min-width.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/ttwf-reftest-flex-direction-column-reverse.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/ttwf-reftest-flex-direction-column.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/ttwf-reftest-flex-inline.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/ttwf-reftest-flex-order.html [ Failure ]
 crbug.com/467127 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/ttwf-reftest-flex-wrap-reverse.html [ Failure ]
@@ -3246,7 +3242,6 @@
 # Various menulist appearance failures in WPT
 crbug.com/968164 external/wpt/css/css-ui/appearance-menulist-button-002.html [ Failure ]
 crbug.com/968164 external/wpt/css/css-ui/webkit-appearance-menulist-001.html [ Failure ]
-crbug.com/968164 external/wpt/css/css-ui/webkit-appearance-menulist-button-001.html [ Failure ]
 
 # Implement text-decoration-thickness and text-decoration-offset
 crbug.com/785230 external/wpt/css/css-text-decor/text-underline-offset-002.html [ Failure ]
@@ -3262,6 +3257,11 @@
 crbug.com/991295 external/wpt/web-animations/timing-model/timelines/document-timelines.html [ Pass Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Linux ] external/wpt/css/css-ui/appearance-textfield-001.html [ Failure ]
+crbug.com/626703 [ Mac ] external/wpt/css/css-ui/appearance-textfield-001.html [ Failure ]
+crbug.com/626703 [ Win ] external/wpt/css/css-ui/appearance-textfield-001.html [ Failure ]
+crbug.com/626703 [ Linux ] external/wpt/css/css-ui/webkit-appearance-textfield-001.html [ Failure ]
+crbug.com/626703 [ Win ] external/wpt/css/css-ui/webkit-appearance-textfield-001.html [ Failure ]
 crbug.com/626703 [ Win7 ] external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-http/img-tag/keep-origin-redirect/same-origin-insecure.http.html [ Timeout ]
 crbug.com/626703 [ Win7 ] external/wpt/referrer-policy/unset-referrer-policy/http-rp/same-origin/http-http/img-tag/swap-origin-redirect/insecure-protocol.http.html [ Timeout ]
 crbug.com/626703 [ Win7 ] external/wpt/referrer-policy/unsafe-url/attr-referrer/cross-origin/http-http/img-tag/no-redirect/generic.http.html [ Timeout ]
@@ -3591,26 +3591,16 @@
 crbug.com/626703 [ Retina ] external/wpt/preload/onerror-event.html [ Timeout ]
 crbug.com/626703 external/wpt/css/css-writing-modes/text-combine-upright-digits-001-manual.html [ Skip ]
 crbug.com/626703 external/wpt/web-animations/timing-model/timelines/update-and-send-events-replacement.html [ Timeout ]
-crbug.com/626703 external/wpt/css/css-ui/webkit-appearance-radio-001.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-ui/webkit-appearance-square-button-001.html [ Failure ]
 crbug.com/626703 external/wpt/webrtc/RTCRtpTransceiver.https.html [ Crash Timeout ]
-crbug.com/626703 external/wpt/css/css-ui/webkit-appearance-push-button-001.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-writing-modes/text-combine-upright-all-001-manual.html [ Skip ]
-crbug.com/626703 external/wpt/css/css-ui/webkit-appearance-textarea-001.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-writing-modes/text-combine-upright-digits-002-manual.html [ Skip ]
-crbug.com/626703 external/wpt/css/css-ui/webkit-appearance-checkbox-001.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-ui/webkit-appearance-progress-bar-001.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-ui/webkit-appearance-button-bevel-001.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-writing-modes/text-combine-upright-all-002-manual.html [ Skip ]
-crbug.com/626703 external/wpt/css/css-ui/webkit-appearance-meter-001.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-ui/webkit-appearance-searchfield-001.html [ Failure ]
 crbug.com/626703 virtual/streaming-preload/external/wpt/html/semantics/scripting-1/the-script-element/json-module/parse-error.html [ Timeout ]
 crbug.com/626703 external/wpt/css/css-ui/webkit-appearance-auto-001.html [ Failure ]
 crbug.com/626703 external/wpt/web-animations/interfaces/Animation/persist.html [ Timeout ]
-crbug.com/626703 external/wpt/css/css-ui/webkit-appearance-listbox-001.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-writing-modes/text-combine-upright-digits-004-manual.html [ Skip ]
 crbug.com/626703 external/wpt/html/semantics/scripting-1/the-script-element/json-module/parse-error.html [ Timeout ]
-crbug.com/626703 external/wpt/css/css-ui/webkit-appearance-slider-horizontal-001.html [ Failure ]
 crbug.com/626703 [ Mac10.13 ] external/wpt/preload/preload-with-type.html [ Failure Timeout ]
 crbug.com/626703 [ Retina ] external/wpt/preload/preload-with-type.html [ Timeout ]
 crbug.com/626703 [ Mac10.13 ] external/wpt/preload/onload-event.html [ Failure Timeout ]
@@ -6286,9 +6276,6 @@
 crbug.com/974334 [ Mac ] external/wpt/html/cross-origin/null.tentative.html [ Failure ]
 crbug.com/974334 [ Mac ] external/wpt/html/cross-origin/usecredentials.tentative.html [ Failure ]
 
-# Flaky on Linux, failing on macOS
-crbug.com/984926 [ Linux Mac ] http/tests/devtools/elements/highlight/highlight-node-vertical-rl.js [ Pass Failure ]
-
 # Sheriff 2019-06-20
 crbug.com/977153 [ Mac ] fast/forms/validation-bubble-appearance-wrap.html [ Pass Failure ]
 crbug.com/976045 fast/scrolling/unscrollable-layer-subpixel-size-with-negative-overflow.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
index dee4514..b22b82c 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -87267,6 +87267,18 @@
      {}
     ]
    ],
+   "css/css-ui/appearance-textfield-001.html": [
+    [
+     "css/css-ui/appearance-textfield-001.html",
+     [
+      [
+       "/css/css-ui/appearance-textfield-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-ui/box-sizing-001.html": [
     [
      "css/css-ui/box-sizing-001.html",
@@ -88383,6 +88395,18 @@
      {}
     ]
    ],
+   "css/css-ui/webkit-appearance-textfield-001.html": [
+    [
+     "css/css-ui/webkit-appearance-textfield-001.html",
+     [
+      [
+       "/css/css-ui/appearance-textfield-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-values/angle-units-001.html": [
     [
      "css/css-values/angle-units-001.html",
@@ -145532,6 +145556,9 @@
    "css/css-ui/appearance-serialization-expected.txt": [
     []
    ],
+   "css/css-ui/appearance-textfield-001-ref.html": [
+    []
+   ],
    "css/css-ui/inheritance-expected.txt": [
     []
    ],
@@ -393324,6 +393351,14 @@
    "5c55ff9fbf6fd993aaf51114c175414a9ec8fe0b",
    "reftest"
   ],
+  "css/css-ui/appearance-textfield-001-ref.html": [
+   "5304352e6bafd1d25436babfc2afc0ba1aa26fa3",
+   "support"
+  ],
+  "css/css-ui/appearance-textfield-001.html": [
+   "f2ca6fc6ac752085ef9bbf3593b94097a8c47c81",
+   "reftest"
+  ],
   "css/css-ui/box-sizing-001.html": [
    "545403f535d2f33993558bde9086e8798c04c11f",
    "reftest"
@@ -395968,6 +396003,10 @@
    "cf3a15f4db6c9745de687cb38f593132d5ddf2f8",
    "reftest"
   ],
+  "css/css-ui/webkit-appearance-textfield-001.html": [
+   "058e1be83bbf924d949f6b9665e456dbb932d388",
+   "reftest"
+  ],
   "css/css-values/META.yml": [
    "a22882a9996b14afa942d3403fa1a873f526073a",
    "support"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/CSSAnimation-id.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-animations/CSSAnimation-id.tentative-expected.txt
deleted file mode 100644
index ba5b2dd..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-animations/CSSAnimation-id.tentative-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Animation.id for CSS Animations assert_equals: id for CSS Animation is initially empty expected "" but got "abc"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/appearance-textfield-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-ui/appearance-textfield-001-ref.html
new file mode 100644
index 0000000..5304352e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/appearance-textfield-001-ref.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Reference for CSS Basic User Interface Test: appearance: textfield</title>
+<style>
+ #container { width: 500px; }
+</style>
+<div id="container">
+	<a>a</a>
+	<button>button</button>
+	<input type="text" value="input-text">
+	<input type="text" value="input-search"><!-- intentionally type="text" -->
+	<textarea>textarea</textarea>
+	<input type="button" value="input-button">
+	<input type="submit" value="input-submit">
+	<input type="reset" value="input-reset">
+	<input type="range">
+	<input type="checkbox">
+	<input type="radio">
+	<input type="color">
+	<select><option>select</option></select>
+	<select multiple><option>select-multiple</option></select>
+	<meter value=0.5></meter>
+	<progress value=0.5></progress>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/appearance-textfield-001.html b/third_party/blink/web_tests/external/wpt/css/css-ui/appearance-textfield-001.html
new file mode 100644
index 0000000..f2ca6fc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/appearance-textfield-001.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Basic User Interface Test: appearance: textfield</title>
+<link rel="help" href="https://drafts.csswg.org/css-ui-4/#appearance-switching">
+<meta name="assert" content="textfield is an alias to auto except on input type=search.">
+<link rel="match" href="appearance-textfield-001-ref.html">
+<style>
+ #container { width: 500px; }
+ /*
+  * If the value being tested is not supported, then 'none' is used instead,
+  * which is intended to fail the test.
+  */
+ #container > * { appearance: none; appearance: textfield; }
+</style>
+<div id="container">
+	<a>a</a>
+	<button>button</button>
+	<input type="text" value="input-text">
+	<input type="search" value="input-search">
+	<textarea>textarea</textarea>
+	<input type="button" value="input-button">
+	<input type="submit" value="input-submit">
+	<input type="reset" value="input-reset">
+	<input type="range">
+	<input type="checkbox">
+	<input type="radio">
+	<input type="color">
+	<select><option>select</option></select>
+	<select multiple><option>select-multiple</option></select>
+	<meter value=0.5></meter>
+	<progress value=0.5></progress>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/webkit-appearance-textfield-001.html b/third_party/blink/web_tests/external/wpt/css/css-ui/webkit-appearance-textfield-001.html
new file mode 100644
index 0000000..058e1be
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/webkit-appearance-textfield-001.html
@@ -0,0 +1,36 @@
+<!-- DO NOT EDIT THIS FILE.
+Edit the appearance-* file instead and then run:
+    ./tools/appearance-build-webkit-reftests.py
+-->
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Basic User Interface Test: -webkit-appearance: textfield</title>
+<link rel="help" href="https://drafts.csswg.org/css-ui-4/#appearance-switching">
+<meta name="assert" content="textfield is an alias to auto except on input type=search.">
+<link rel="match" href="appearance-textfield-001-ref.html">
+<style>
+ #container { width: 500px; }
+ /*
+  * If the value being tested is not supported, then 'none' is used instead,
+  * which is intended to fail the test.
+  */
+ #container > * { -webkit-appearance: none; -webkit-appearance: textfield; }
+</style>
+<div id="container">
+	<a>a</a>
+	<button>button</button>
+	<input type="text" value="input-text">
+	<input type="search" value="input-search">
+	<textarea>textarea</textarea>
+	<input type="button" value="input-button">
+	<input type="submit" value="input-submit">
+	<input type="reset" value="input-reset">
+	<input type="range">
+	<input type="checkbox">
+	<input type="radio">
+	<input type="color">
+	<select><option>select</option></select>
+	<select multiple><option>select-multiple</option></select>
+	<meter value=0.5></meter>
+	<progress value=0.5></progress>
+</div>
diff --git a/third_party/blink/web_tests/fast/scrolling/events/scrollend-event-fired-after-snap.html b/third_party/blink/web_tests/fast/scrolling/events/scrollend-event-fired-after-snap.html
index f083622..ad739c4 100644
--- a/third_party/blink/web_tests/fast/scrolling/events/scrollend-event-fired-after-snap.html
+++ b/third_party/blink/web_tests/fast/scrolling/events/scrollend-event-fired-after-snap.html
@@ -25,14 +25,12 @@
 }
 </style>
 
-<body style="margin:0" onload=runTests()>
-  <div id="scroller">
-    <div id="space"></div>
-    <div class="target" style="left: 0px; top: 0px;"></div>
-    <div class="target" style="left: 80px; top: 80px;"></div>
-    <div class="target" style="left: 200px; top: 200px;"></div>
-  </div>
-</body>
+<div id="scroller">
+  <div id="space"></div>
+  <div class="target" style="left: 0px; top: 0px;"></div>
+  <div class="target" style="left: 80px; top: 80px;"></div>
+  <div class="target" style="left: 200px; top: 200px;"></div>
+</div>
 
 <script>
 if (window.internals)
@@ -56,30 +54,28 @@
 scroller.addEventListener("scrollend", () => {
   scroll_end_arrived = true;
 });
-function runTests() {
-  promise_test (async () => {
-    await waitForCompositorCommit();
-    await smoothScroll(100, 200, 200, GestureSourceType.TOUCH_INPUT, 'down');
-    // Wait for the scroll snap animation to finish.
-    await waitForAnimationEnd(scrollLeft, MAX_FRAME_COUNT, MAX_UNCHANGED_FRAME);
-    await waitFor(() => { return scroll_end_arrived; });
-    // Verify that scroll snap animation has finished before firing scrollend event.
-    assert_false(scroll_arrived_after_scroll_end);
-  }, "Tests that scrollend is fired after scroll snap animation completion.");
+promise_test (async () => {
+  await waitForCompositorCommit();
+  await smoothScroll(100, 200, 200, GestureSourceType.TOUCH_INPUT, 'down');
+  // Wait for the scroll snap animation to finish.
+  await waitForAnimationEnd(scrollLeft, MAX_FRAME_COUNT, MAX_UNCHANGED_FRAME);
+  await waitFor(() => { return scroll_end_arrived; });
+  // Verify that scroll snap animation has finished before firing scrollend event.
+  assert_false(scroll_arrived_after_scroll_end);
+}, "Tests that scrollend is fired after scroll snap animation completion.");
 
-  promise_test (async () => {
-    // Reset scroll state.
-    scroller.scrollTo(0, 0);
-    await waitForCompositorCommit();
-    scroll_end_arrived = false;
-    scroll_arrived_after_scroll_end = false;
+promise_test (async () => {
+  // Reset scroll state.
+  scroller.scrollTo(0, 0);
+  await waitForCompositorCommit();
+  scroll_end_arrived = false;
+  scroll_arrived_after_scroll_end = false;
 
-    await swipe(100, 200, 200, 'up');
-    // Wait for the scroll snap animation to finish.
-    await waitForAnimationEnd(scrollLeft, MAX_FRAME_COUNT, MAX_UNCHANGED_FRAME);
-    await waitFor(() => { return scroll_end_arrived; });
-    // Verify that scroll snap animation has finished before firing scrollend event.
-    assert_false(scroll_arrived_after_scroll_end);
-  }, "Tests that scrollend is fired after fling snap animation completion.");
-}
+  await swipe(100, 200, 200, 'up');
+  // Wait for the scroll snap animation to finish.
+  await waitForAnimationEnd(scrollLeft, MAX_FRAME_COUNT, MAX_UNCHANGED_FRAME);
+  await waitFor(() => { return scroll_end_arrived; });
+  // Verify that scroll snap animation has finished before firing scrollend event.
+  assert_false(scroll_arrived_after_scroll_end);
+}, "Tests that scrollend is fired after fling snap animation completion.");
 </script>
diff --git a/third_party/blink/web_tests/platform/win/http/tests/devtools/elements/highlight/highlight-node-vertical-rl-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-node-vertical-rl-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/platform/win/http/tests/devtools/elements/highlight/highlight-node-vertical-rl-expected.txt
rename to third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-node-vertical-rl-expected.txt
diff --git a/third_party/blink/web_tests/platform/linux/http/tests/devtools/elements/highlight/highlight-node-vertical-rl-expected.txt b/third_party/blink/web_tests/platform/linux/http/tests/devtools/elements/highlight/highlight-node-vertical-rl-expected.txt
deleted file mode 100644
index 47b4f35..0000000
--- a/third_party/blink/web_tests/platform/linux/http/tests/devtools/elements/highlight/highlight-node-vertical-rl-expected.txt
+++ /dev/null
@@ -1,358 +0,0 @@
-
-
-container{
-  "paths": [
-    {
-      "path": [
-        "M",
-        80,
-        50,
-        "L",
-        380,
-        50,
-        "L",
-        380,
-        350,
-        "L",
-        80,
-        350,
-        "Z"
-      ],
-      "fillColor": "rgba(255, 0, 0, 0)",
-      "outlineColor": "rgba(128, 0, 0, 0)",
-      "name": "content"
-    },
-    {
-      "path": [
-        "M",
-        80,
-        50,
-        "L",
-        380,
-        50,
-        "L",
-        380,
-        350,
-        "L",
-        80,
-        350,
-        "Z"
-      ],
-      "fillColor": "rgba(0, 255, 0, 0)",
-      "name": "padding"
-    },
-    {
-      "path": [
-        "M",
-        80,
-        50,
-        "L",
-        380,
-        50,
-        "L",
-        380,
-        350,
-        "L",
-        80,
-        350,
-        "Z"
-      ],
-      "fillColor": "rgba(0, 0, 255, 0)",
-      "name": "border"
-    },
-    {
-      "path": [
-        "M",
-        0,
-        0,
-        "L",
-        412,
-        0,
-        "L",
-        412,
-        420,
-        "L",
-        0,
-        420,
-        "Z"
-      ],
-      "fillColor": "rgba(255, 255, 255, 0)",
-      "name": "margin"
-    }
-  ],
-  "showRulers": true,
-  "showExtensionLines": true,
-  "elementInfo": {
-    "tagName": "div",
-    "idValue": "container",
-    "nodeWidth": "300",
-    "nodeHeight": "300"
-  }
-}
-child{
-  "paths": [
-    {
-      "path": [
-        "M",
-        220,
-        100,
-        "L",
-        320,
-        100,
-        "L",
-        320,
-        200,
-        "L",
-        220,
-        200,
-        "Z"
-      ],
-      "fillColor": "rgba(255, 0, 0, 0)",
-      "outlineColor": "rgba(128, 0, 0, 0)",
-      "name": "content"
-    },
-    {
-      "path": [
-        "M",
-        140,
-        50,
-        "L",
-        380,
-        50,
-        "L",
-        380,
-        270,
-        "L",
-        140,
-        270,
-        "Z"
-      ],
-      "fillColor": "rgba(0, 255, 0, 0)",
-      "name": "padding"
-    },
-    {
-      "path": [
-        "M",
-        140,
-        50,
-        "L",
-        380,
-        50,
-        "L",
-        380,
-        270,
-        "L",
-        140,
-        270,
-        "Z"
-      ],
-      "fillColor": "rgba(0, 0, 255, 0)",
-      "name": "border"
-    },
-    {
-      "path": [
-        "M",
-        140,
-        50,
-        "L",
-        380,
-        50,
-        "L",
-        380,
-        350,
-        "L",
-        140,
-        350,
-        "Z"
-      ],
-      "fillColor": "rgba(255, 255, 255, 0)",
-      "name": "margin"
-    }
-  ],
-  "showRulers": true,
-  "showExtensionLines": true,
-  "elementInfo": {
-    "tagName": "div",
-    "idValue": "child",
-    "nodeWidth": "240",
-    "nodeHeight": "220"
-  }
-}
-span{
-  "paths": [
-    {
-      "path": [
-        "M",
-        310,
-        100,
-        "L",
-        320,
-        100,
-        "L",
-        320,
-        170,
-        "L",
-        310,
-        170,
-        "Z"
-      ],
-      "fillColor": "rgba(255, 0, 0, 0)",
-      "outlineColor": "rgba(128, 0, 0, 0)",
-      "name": "content"
-    },
-    {
-      "path": [
-        "M",
-        310,
-        100,
-        "L",
-        320,
-        100,
-        "L",
-        320,
-        170,
-        "L",
-        310,
-        170,
-        "Z"
-      ],
-      "fillColor": "rgba(0, 255, 0, 0)",
-      "name": "padding"
-    },
-    {
-      "path": [
-        "M",
-        310,
-        100,
-        "L",
-        320,
-        100,
-        "L",
-        320,
-        170,
-        "L",
-        310,
-        170,
-        "Z"
-      ],
-      "fillColor": "rgba(0, 0, 255, 0)",
-      "name": "border"
-    },
-    {
-      "path": [
-        "M",
-        310,
-        100,
-        "L",
-        320,
-        100,
-        "L",
-        320,
-        170,
-        "L",
-        310,
-        170,
-        "Z"
-      ],
-      "fillColor": "rgba(255, 255, 255, 0)",
-      "name": "margin"
-    }
-  ],
-  "showRulers": true,
-  "showExtensionLines": true,
-  "elementInfo": {
-    "tagName": "span",
-    "idValue": "span",
-    "nodeWidth": "10",
-    "nodeHeight": "70"
-  }
-}
-TEXT{
-  "paths": [
-    {
-      "path": [
-        "M",
-        310,
-        100,
-        "L",
-        320,
-        100,
-        "L",
-        320,
-        170,
-        "L",
-        310,
-        170,
-        "Z"
-      ],
-      "fillColor": "rgba(255, 0, 0, 0)",
-      "outlineColor": "rgba(128, 0, 0, 0)",
-      "name": "content"
-    },
-    {
-      "path": [
-        "M",
-        310,
-        100,
-        "L",
-        320,
-        100,
-        "L",
-        320,
-        170,
-        "L",
-        310,
-        170,
-        "Z"
-      ],
-      "fillColor": "rgba(0, 255, 0, 0)",
-      "name": "padding"
-    },
-    {
-      "path": [
-        "M",
-        310,
-        100,
-        "L",
-        320,
-        100,
-        "L",
-        320,
-        170,
-        "L",
-        310,
-        170,
-        "Z"
-      ],
-      "fillColor": "rgba(0, 0, 255, 0)",
-      "name": "border"
-    },
-    {
-      "path": [
-        "M",
-        310,
-        100,
-        "L",
-        320,
-        100,
-        "L",
-        320,
-        170,
-        "L",
-        310,
-        170,
-        "Z"
-      ],
-      "fillColor": "rgba(255, 255, 255, 0)",
-      "name": "margin"
-    }
-  ],
-  "showRulers": true,
-  "showExtensionLines": true,
-  "elementInfo": {
-    "nodeWidth": "10",
-    "nodeHeight": "70",
-    "tagName": "#text"
-  }
-}
-
diff --git a/third_party/blink/web_tests/platform/mac/http/tests/devtools/elements/highlight/highlight-node-vertical-rl-expected.txt b/third_party/blink/web_tests/platform/mac/http/tests/devtools/elements/highlight/highlight-node-vertical-rl-expected.txt
deleted file mode 100644
index 47b4f35..0000000
--- a/third_party/blink/web_tests/platform/mac/http/tests/devtools/elements/highlight/highlight-node-vertical-rl-expected.txt
+++ /dev/null
@@ -1,358 +0,0 @@
-
-
-container{
-  "paths": [
-    {
-      "path": [
-        "M",
-        80,
-        50,
-        "L",
-        380,
-        50,
-        "L",
-        380,
-        350,
-        "L",
-        80,
-        350,
-        "Z"
-      ],
-      "fillColor": "rgba(255, 0, 0, 0)",
-      "outlineColor": "rgba(128, 0, 0, 0)",
-      "name": "content"
-    },
-    {
-      "path": [
-        "M",
-        80,
-        50,
-        "L",
-        380,
-        50,
-        "L",
-        380,
-        350,
-        "L",
-        80,
-        350,
-        "Z"
-      ],
-      "fillColor": "rgba(0, 255, 0, 0)",
-      "name": "padding"
-    },
-    {
-      "path": [
-        "M",
-        80,
-        50,
-        "L",
-        380,
-        50,
-        "L",
-        380,
-        350,
-        "L",
-        80,
-        350,
-        "Z"
-      ],
-      "fillColor": "rgba(0, 0, 255, 0)",
-      "name": "border"
-    },
-    {
-      "path": [
-        "M",
-        0,
-        0,
-        "L",
-        412,
-        0,
-        "L",
-        412,
-        420,
-        "L",
-        0,
-        420,
-        "Z"
-      ],
-      "fillColor": "rgba(255, 255, 255, 0)",
-      "name": "margin"
-    }
-  ],
-  "showRulers": true,
-  "showExtensionLines": true,
-  "elementInfo": {
-    "tagName": "div",
-    "idValue": "container",
-    "nodeWidth": "300",
-    "nodeHeight": "300"
-  }
-}
-child{
-  "paths": [
-    {
-      "path": [
-        "M",
-        220,
-        100,
-        "L",
-        320,
-        100,
-        "L",
-        320,
-        200,
-        "L",
-        220,
-        200,
-        "Z"
-      ],
-      "fillColor": "rgba(255, 0, 0, 0)",
-      "outlineColor": "rgba(128, 0, 0, 0)",
-      "name": "content"
-    },
-    {
-      "path": [
-        "M",
-        140,
-        50,
-        "L",
-        380,
-        50,
-        "L",
-        380,
-        270,
-        "L",
-        140,
-        270,
-        "Z"
-      ],
-      "fillColor": "rgba(0, 255, 0, 0)",
-      "name": "padding"
-    },
-    {
-      "path": [
-        "M",
-        140,
-        50,
-        "L",
-        380,
-        50,
-        "L",
-        380,
-        270,
-        "L",
-        140,
-        270,
-        "Z"
-      ],
-      "fillColor": "rgba(0, 0, 255, 0)",
-      "name": "border"
-    },
-    {
-      "path": [
-        "M",
-        140,
-        50,
-        "L",
-        380,
-        50,
-        "L",
-        380,
-        350,
-        "L",
-        140,
-        350,
-        "Z"
-      ],
-      "fillColor": "rgba(255, 255, 255, 0)",
-      "name": "margin"
-    }
-  ],
-  "showRulers": true,
-  "showExtensionLines": true,
-  "elementInfo": {
-    "tagName": "div",
-    "idValue": "child",
-    "nodeWidth": "240",
-    "nodeHeight": "220"
-  }
-}
-span{
-  "paths": [
-    {
-      "path": [
-        "M",
-        310,
-        100,
-        "L",
-        320,
-        100,
-        "L",
-        320,
-        170,
-        "L",
-        310,
-        170,
-        "Z"
-      ],
-      "fillColor": "rgba(255, 0, 0, 0)",
-      "outlineColor": "rgba(128, 0, 0, 0)",
-      "name": "content"
-    },
-    {
-      "path": [
-        "M",
-        310,
-        100,
-        "L",
-        320,
-        100,
-        "L",
-        320,
-        170,
-        "L",
-        310,
-        170,
-        "Z"
-      ],
-      "fillColor": "rgba(0, 255, 0, 0)",
-      "name": "padding"
-    },
-    {
-      "path": [
-        "M",
-        310,
-        100,
-        "L",
-        320,
-        100,
-        "L",
-        320,
-        170,
-        "L",
-        310,
-        170,
-        "Z"
-      ],
-      "fillColor": "rgba(0, 0, 255, 0)",
-      "name": "border"
-    },
-    {
-      "path": [
-        "M",
-        310,
-        100,
-        "L",
-        320,
-        100,
-        "L",
-        320,
-        170,
-        "L",
-        310,
-        170,
-        "Z"
-      ],
-      "fillColor": "rgba(255, 255, 255, 0)",
-      "name": "margin"
-    }
-  ],
-  "showRulers": true,
-  "showExtensionLines": true,
-  "elementInfo": {
-    "tagName": "span",
-    "idValue": "span",
-    "nodeWidth": "10",
-    "nodeHeight": "70"
-  }
-}
-TEXT{
-  "paths": [
-    {
-      "path": [
-        "M",
-        310,
-        100,
-        "L",
-        320,
-        100,
-        "L",
-        320,
-        170,
-        "L",
-        310,
-        170,
-        "Z"
-      ],
-      "fillColor": "rgba(255, 0, 0, 0)",
-      "outlineColor": "rgba(128, 0, 0, 0)",
-      "name": "content"
-    },
-    {
-      "path": [
-        "M",
-        310,
-        100,
-        "L",
-        320,
-        100,
-        "L",
-        320,
-        170,
-        "L",
-        310,
-        170,
-        "Z"
-      ],
-      "fillColor": "rgba(0, 255, 0, 0)",
-      "name": "padding"
-    },
-    {
-      "path": [
-        "M",
-        310,
-        100,
-        "L",
-        320,
-        100,
-        "L",
-        320,
-        170,
-        "L",
-        310,
-        170,
-        "Z"
-      ],
-      "fillColor": "rgba(0, 0, 255, 0)",
-      "name": "border"
-    },
-    {
-      "path": [
-        "M",
-        310,
-        100,
-        "L",
-        320,
-        100,
-        "L",
-        320,
-        170,
-        "L",
-        310,
-        170,
-        "Z"
-      ],
-      "fillColor": "rgba(255, 255, 255, 0)",
-      "name": "margin"
-    }
-  ],
-  "showRulers": true,
-  "showExtensionLines": true,
-  "elementInfo": {
-    "nodeWidth": "10",
-    "nodeHeight": "70",
-    "tagName": "#text"
-  }
-}
-
diff --git a/third_party/libaddressinput/chromium/chrome_metadata_source.cc b/third_party/libaddressinput/chromium/chrome_metadata_source.cc
index 02f74d5..e4633c9e 100644
--- a/third_party/libaddressinput/chromium/chrome_metadata_source.cc
+++ b/third_party/libaddressinput/chromium/chrome_metadata_source.cc
@@ -90,8 +90,7 @@
         })");
   auto resource_request = std::make_unique<network::ResourceRequest>();
   resource_request->url = resource;
-  resource_request->load_flags =
-      net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES;
+  resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
   std::unique_ptr<network::SimpleURLLoader> loader =
       network::SimpleURLLoader::Create(std::move(resource_request),
                                        traffic_annotation);
diff --git a/third_party/lottie/README.chromium b/third_party/lottie/README.chromium
index 5ef3a69..3e46edc 100644
--- a/third_party/lottie/README.chromium
+++ b/third_party/lottie/README.chromium
@@ -16,4 +16,4 @@
 
 Generating Minified Version:
 To generate the minified version use node's uglify-js-
-$ node uglifyjs --compress --mangle reserved=['onmessage'] lottie_worker.js -o lottie_worker.min.js -b beautify=false,ascii_only=true
+$ node uglifyjs --compress --mangle reserved=['onmessage', 'postMessage'] lottie_worker.js -o lottie_worker.min.js -b beautify=false,ascii_only=true
diff --git a/third_party/lottie/README.md b/third_party/lottie/README.md
index 6d86f99..b92e3ad 100644
--- a/third_party/lottie/README.md
+++ b/third_party/lottie/README.md
@@ -54,3 +54,30 @@
   }
 },
 ```
+
+## Events fired back to the parent thread
+The web worker running the lottie player will send the following events back to
+its parent thread:
+1. **'initialized'**
+```javascript
+{
+    name: 'initialized',
+    success: true/false // True if the animation was successfully initialized.
+}
+```
+2. **'playing'**
+```javascript
+{
+    name: 'playing'
+}
+```
+3. **'resized'**
+```javascript
+{
+    name: 'resized',
+    size: {
+        height: HEIGHT, // Current height of canvas in pixels.
+        width: WIDTH    // Current width of canvas in pixels.
+    }
+}
+```
diff --git a/third_party/lottie/lottie_worker.js b/third_party/lottie/lottie_worker.js
index fdf9a1a..755de87 100644
--- a/third_party/lottie/lottie_worker.js
+++ b/third_party/lottie/lottie_worker.js
@@ -12150,47 +12150,117 @@
  * a wrapper that manages animation control for each animation.
  */
 
+/**
+ * An instance of the currently running lottie animation.
+ * @type {?AnimationItem}
+ */
 var currentAnimation = null;
 
+/**
+ * Events sent back to the parent thread.
+ */
+var events = {
+  INITIALIZED: 'initialized',  // Send when the animation was successfully
+                               // initialized.
+  RESIZED: 'resized',  // Sent when the animation has been resized.
+  PLAYING: 'playing'   // Send when the animation started playing.
+};
+
+/**
+ * Returns the size of the canvas on which the current animation is running on.
+ * @return {Object<string, number>} Returns the current size of canvas
+ */
+getCurrentCanvasSize = function() {
+  var canvas = currentAnimation.renderer.canvasContext.canvas;
+  return {
+    height: canvas.height,
+    width: canvas.width
+  };
+}
+
+/**
+ * Informs the parent thread that the canvas has been resized and also sends the
+ * new size.
+ */
+sendResizeEvent = function() {
+  var canvas = currentAnimation.renderer.canvasContext.canvas;
+  postMessage({
+    name: events.RESIZED,
+    size: getCurrentCanvasSize()
+  });
+};
+
+/**
+ * Informs the parent thread that the animation has started playing.
+ */
+sendPlayEvent = function() {
+  postMessage({
+    name: events.PLAYING
+  });
+}
+
+/**
+ * Informs the parent thread that the animation has finished initializing.
+ */
+sendInitializedEvent = function() {
+  var canvas = currentAnimation.renderer.canvasContext.canvas;
+  postMessage({
+    name: events.INITIALIZED,
+    success: currentAnimation.isLoaded
+  })
+}
+
 onmessage = function(evt) {
-    if (!evt || !evt.data) return;
+  if (!evt || !evt.data) return;
 
-    var canvas = null;
+  var canvas = null;
+  if (currentAnimation) {
+    canvas = currentAnimation.renderer.canvasContext.canvas;
+  } else if (evt.data.canvas) {
+    canvas = evt.data.canvas;
+  } else {
+    return;
+  }
+
+  // Set the draw size of the canvas. This is the pixel size at which the
+  // lottie renderer will render the frames.
+  if (evt.data.drawSize && evt.data.drawSize.height > 0 &&
+    evt.data.drawSize.width > 0) {
+    canvas.height = evt.data.drawSize.height;
+    canvas.width = evt.data.drawSize.width;
+
+    // Update lottie player to use the new canvas size.
     if (currentAnimation) {
-        canvas = currentAnimation.renderer.canvasContext.canvas;
-    } else if (evt.data.canvas) {
-        canvas = evt.data.canvas;
-    } else {
-        return;
+      currentAnimation.resize();
+      sendResizeEvent();
+    }
+  }
+
+  if (!currentAnimation) {
+    if (!evt.data.animationData || !evt.data.params)
+      return;
+    var params = evt.data.params;
+    var ctx = canvas.getContext("2d");
+    currentAnimation = lottiejs.loadAnimation({
+      renderer: 'canvas',
+      loop: params.loop,
+      autoplay: params.autoplay,
+      animationData: evt.data.animationData,
+      rendererSettings: {
+        context: ctx,
+        scaleMode: 'noScale',
+        clearCanvas: true
+      }
+    });
+
+    sendInitializedEvent();
+
+    if (params.autoplay) {
+      currentAnimation.play();
     }
 
-    // Set the draw size of the canvas. This is the pixel size at which the
-    // lottie renderer will render the frames.
-    if (evt.data.drawSize) {
-        canvas.height = evt.data.drawSize.height;
-        canvas.width = evt.data.drawSize.width;
-
-        // Update lottie player to use the new canvas size.
-        if (currentAnimation)
-            currentAnimation.resize();
+    if (currentAnimation.isLoaded && !currentAnimation.isPaused) {
+      sendPlayEvent();
     }
-
-    if (!currentAnimation) {
-        if (!evt.data.animationData || !evt.data.params)
-            return;
-        var params = evt.data.params;
-        var ctx = canvas.getContext("2d");
-        currentAnimation = lottiejs.loadAnimation({
-            renderer: 'canvas',
-            loop: params.loop,
-            autoplay: params.autoplay,
-            animationData: evt.data.animationData,
-            rendererSettings: {
-                context: ctx,
-                scaleMode: 'noScale',
-                clearCanvas: true
-            }
-        });
-        currentAnimation.play();
-    }
+  }
 };
diff --git a/third_party/lottie/lottie_worker.min.js b/third_party/lottie/lottie_worker.min.js
index 7626d80..3e2495ee 100644
--- a/third_party/lottie/lottie_worker.min.js
+++ b/third_party/lottie/lottie_worker.min.js
@@ -1 +1 @@
-var lottiejs=function(window){"use strict";var svgNS="http://www.w3.org/2000/svg",locationHref="",initialDefaultFrame=-999999,subframeEnabled=!0,expressionsPlugin,isSafari=/^((?!chrome|android).)*safari/i.test(navigator.userAgent),cachedColors={},bm_rounder=Math.round,bm_rnd,bm_pow=Math.pow,bm_sqrt=Math.sqrt,bm_abs=Math.abs,bm_floor=Math.floor,bm_max=Math.max,bm_min=Math.min,blitter=10,BMMath={};function ProjectInterface(){return{}}!function(){var t,e=["abs","acos","acosh","asin","asinh","atan","atanh","atan2","ceil","cbrt","expm1","clz32","cos","cosh","exp","floor","fround","hypot","imul","log","log1p","log2","log10","max","min","pow","random","round","sign","sin","sinh","sqrt","tan","tanh","trunc","E","LN10","LN2","LOG10E","LOG2E","PI","SQRT1_2","SQRT2"],r=e.length;for(t=0;t<r;t+=1)BMMath[e[t]]=Math[e[t]]}(),BMMath.random=Math.random,BMMath.abs=function(t){if("object"==typeof t&&t.length){var e,r=createSizedArray(t.length),i=t.length;for(e=0;e<i;e+=1)r[e]=Math.abs(t[e]);return r}return Math.abs(t)};var defaultCurveSegments=150,degToRads=Math.PI/180,roundCorner=.5519;function roundValues(t){bm_rnd=t?Math.round:function(t){return t}}function styleDiv(t){t.style.position="absolute",t.style.top=0,t.style.left=0,t.style.display="block",t.style.transformOrigin=t.style.webkitTransformOrigin="0 0",t.style.backfaceVisibility=t.style.webkitBackfaceVisibility="visible",t.style.transformStyle=t.style.webkitTransformStyle=t.style.mozTransformStyle="preserve-3d"}function BMEnterFrameEvent(t,e,r,i){this.type=t,this.currentTime=e,this.totalTime=r,this.direction=i<0?-1:1}function BMCompleteEvent(t,e){this.type=t,this.direction=e<0?-1:1}function BMCompleteLoopEvent(t,e,r,i){this.type=t,this.currentLoop=r,this.totalLoops=e,this.direction=i<0?-1:1}function BMSegmentStartEvent(t,e,r){this.type=t,this.firstFrame=e,this.totalFrames=r}function BMDestroyEvent(t,e){this.type=t,this.target=e}roundValues(!1);var createElementID=(B=0,function(){return"__lottie_element_"+ ++B}),B;function HSVtoRGB(t,e,r){var i,s,a,n,o,h,p,l;switch(h=r*(1-e),p=r*(1-(o=6*t-(n=Math.floor(6*t)))*e),l=r*(1-(1-o)*e),n%6){case 0:i=r,s=l,a=h;break;case 1:i=p,s=r,a=h;break;case 2:i=h,s=r,a=l;break;case 3:i=h,s=p,a=r;break;case 4:i=l,s=h,a=r;break;case 5:i=r,s=h,a=p}return[i,s,a]}function RGBtoHSV(t,e,r){var i,s=Math.max(t,e,r),a=Math.min(t,e,r),n=s-a,o=0===s?0:n/s,h=s/255;switch(s){case a:i=0;break;case t:i=e-r+n*(e<r?6:0),i/=6*n;break;case e:i=r-t+2*n,i/=6*n;break;case r:i=t-e+4*n,i/=6*n}return[i,o,h]}function addSaturationToRGB(t,e){var r=RGBtoHSV(255*t[0],255*t[1],255*t[2]);return r[1]+=e,1<r[1]?r[1]=1:r[1]<=0&&(r[1]=0),HSVtoRGB(r[0],r[1],r[2])}function addBrightnessToRGB(t,e){var r=RGBtoHSV(255*t[0],255*t[1],255*t[2]);return r[2]+=e,1<r[2]?r[2]=1:r[2]<0&&(r[2]=0),HSVtoRGB(r[0],r[1],r[2])}function addHueToRGB(t,e){var r=RGBtoHSV(255*t[0],255*t[1],255*t[2]);return r[0]+=e/360,1<r[0]?r[0]-=1:r[0]<0&&(r[0]+=1),HSVtoRGB(r[0],r[1],r[2])}var rgbToHex=function(){var t,e,i=[];for(t=0;t<256;t+=1)e=t.toString(16),i[t]=1==e.length?"0"+e:e;return function(t,e,r){return t<0&&(t=0),e<0&&(e=0),r<0&&(r=0),"#"+i[t]+i[e]+i[r]}}();function BaseEvent(){}BaseEvent.prototype={triggerEvent:function(t,e){if(this._cbs[t])for(var r=this._cbs[t].length,i=0;i<r;i++)this._cbs[t][i](e)},addEventListener:function(t,e){return this._cbs[t]||(this._cbs[t]=[]),this._cbs[t].push(e),function(){this.removeEventListener(t,e)}.bind(this)},removeEventListener:function(t,e){if(e){if(this._cbs[t]){for(var r=0,i=this._cbs[t].length;r<i;)this._cbs[t][r]===e&&(this._cbs[t].splice(r,1),r-=1,i-=1),r+=1;this._cbs[t].length||(this._cbs[t]=null)}}else this._cbs[t]=null}};var createTypedArray="function"==typeof Uint8ClampedArray&&"function"==typeof Float32Array?function(t,e){return"float32"===t?new Float32Array(e):"int16"===t?new Int16Array(e):"uint8c"===t?new Uint8ClampedArray(e):void 0}:function(t,e){var r,i=0,s=[];switch(t){case"int16":case"uint8c":r=1;break;default:r=1.1}for(i=0;i<e;i+=1)s.push(r);return s};function createSizedArray(t){return Array.apply(null,{length:t})}function createTag(t){return document.createElement(t)}function DynamicPropertyContainer(){}DynamicPropertyContainer.prototype={addDynamicProperty:function(t){-1===this.dynamicProperties.indexOf(t)&&(this.dynamicProperties.push(t),this.container.addDynamicProperty(this),this._isAnimated=!0)},iterateDynamicProperties:function(){this._mdf=!1;var t,e=this.dynamicProperties.length;for(t=0;t<e;t+=1)this.dynamicProperties[t].getValue(),this.dynamicProperties[t]._mdf&&(this._mdf=!0)},initDynamicPropertyContainer:function(t){this.container=t,this.dynamicProperties=[],this._mdf=!1,this._isAnimated=!1}};var getBlendMode=(Ja={0:"source-over",1:"multiply",2:"screen",3:"overlay",4:"darken",5:"lighten",6:"color-dodge",7:"color-burn",8:"hard-light",9:"soft-light",10:"difference",11:"exclusion",12:"hue",13:"saturation",14:"color",15:"luminosity"},function(t){return Ja[t]||""}),Ja,Matrix=(La=Math.cos,Ma=Math.sin,Na=Math.tan,Oa=Math.round,function(){this.reset=Pa,this.rotate=Qa,this.rotateX=Ra,this.rotateY=Sa,this.rotateZ=Ta,this.skew=Va,this.skewFromAxis=Wa,this.shear=Ua,this.scale=Xa,this.setTransform=Ya,this.translate=Za,this.transform=$a,this.applyToPoint=db,this.applyToX=eb,this.applyToY=fb,this.applyToZ=gb,this.applyToPointArray=kb,this.applyToTriplePoints=jb,this.applyToPointStringified=lb,this.toCSS=mb,this.to2dCSS=pb,this.clone=bb,this.cloneFromProps=cb,this.equals=ab,this.inversePoints=ib,this.inversePoint=hb,this._t=this.transform,this.isIdentity=_a,this._identity=!0,this._identityCalculated=!1,this.props=createTypedArray("float32",16),this.reset()}),La,Ma,Na,Oa;function Pa(){return this.props[0]=1,this.props[1]=0,this.props[2]=0,this.props[3]=0,this.props[4]=0,this.props[5]=1,this.props[6]=0,this.props[7]=0,this.props[8]=0,this.props[9]=0,this.props[10]=1,this.props[11]=0,this.props[12]=0,this.props[13]=0,this.props[14]=0,this.props[15]=1,this}function Qa(t){if(0===t)return this;var e=La(t),r=Ma(t);return this._t(e,-r,0,0,r,e,0,0,0,0,1,0,0,0,0,1)}function Ra(t){if(0===t)return this;var e=La(t),r=Ma(t);return this._t(1,0,0,0,0,e,-r,0,0,r,e,0,0,0,0,1)}function Sa(t){if(0===t)return this;var e=La(t),r=Ma(t);return this._t(e,0,r,0,0,1,0,0,-r,0,e,0,0,0,0,1)}function Ta(t){if(0===t)return this;var e=La(t),r=Ma(t);return this._t(e,-r,0,0,r,e,0,0,0,0,1,0,0,0,0,1)}function Ua(t,e){return this._t(1,e,t,1,0,0)}function Va(t,e){return this.shear(Na(t),Na(e))}function Wa(t,e){var r=La(e),i=Ma(e);return this._t(r,i,0,0,-i,r,0,0,0,0,1,0,0,0,0,1)._t(1,0,0,0,Na(t),1,0,0,0,0,1,0,0,0,0,1)._t(r,-i,0,0,i,r,0,0,0,0,1,0,0,0,0,1)}function Xa(t,e,r){return r||0===r||(r=1),1===t&&1===e&&1===r?this:this._t(t,0,0,0,0,e,0,0,0,0,r,0,0,0,0,1)}function Ya(t,e,r,i,s,a,n,o,h,p,l,m,f,c,d,u){return this.props[0]=t,this.props[1]=e,this.props[2]=r,this.props[3]=i,this.props[4]=s,this.props[5]=a,this.props[6]=n,this.props[7]=o,this.props[8]=h,this.props[9]=p,this.props[10]=l,this.props[11]=m,this.props[12]=f,this.props[13]=c,this.props[14]=d,this.props[15]=u,this}function Za(t,e,r){return r=r||0,0!==t||0!==e||0!==r?this._t(1,0,0,0,0,1,0,0,0,0,1,0,t,e,r,1):this}function $a(t,e,r,i,s,a,n,o,h,p,l,m,f,c,d,u){var y=this.props;if(1===t&&0===e&&0===r&&0===i&&0===s&&1===a&&0===n&&0===o&&0===h&&0===p&&1===l&&0===m)return y[12]=y[12]*t+y[15]*f,y[13]=y[13]*a+y[15]*c,y[14]=y[14]*l+y[15]*d,y[15]=y[15]*u,this._identityCalculated=!1,this;var g=y[0],v=y[1],P=y[2],b=y[3],x=y[4],_=y[5],S=y[6],T=y[7],A=y[8],C=y[9],E=y[10],k=y[11],D=y[12],M=y[13],I=y[14],w=y[15];return y[0]=g*t+v*s+P*h+b*f,y[1]=g*e+v*a+P*p+b*c,y[2]=g*r+v*n+P*l+b*d,y[3]=g*i+v*o+P*m+b*u,y[4]=x*t+_*s+S*h+T*f,y[5]=x*e+_*a+S*p+T*c,y[6]=x*r+_*n+S*l+T*d,y[7]=x*i+_*o+S*m+T*u,y[8]=A*t+C*s+E*h+k*f,y[9]=A*e+C*a+E*p+k*c,y[10]=A*r+C*n+E*l+k*d,y[11]=A*i+C*o+E*m+k*u,y[12]=D*t+M*s+I*h+w*f,y[13]=D*e+M*a+I*p+w*c,y[14]=D*r+M*n+I*l+w*d,y[15]=D*i+M*o+I*m+w*u,this._identityCalculated=!1,this}function _a(){return this._identityCalculated||(this._identity=!(1!==this.props[0]||0!==this.props[1]||0!==this.props[2]||0!==this.props[3]||0!==this.props[4]||1!==this.props[5]||0!==this.props[6]||0!==this.props[7]||0!==this.props[8]||0!==this.props[9]||1!==this.props[10]||0!==this.props[11]||0!==this.props[12]||0!==this.props[13]||0!==this.props[14]||1!==this.props[15]),this._identityCalculated=!0),this._identity}function ab(t){for(var e=0;e<16;){if(t.props[e]!==this.props[e])return!1;e+=1}return!0}function bb(t){var e;for(e=0;e<16;e+=1)t.props[e]=this.props[e]}function cb(t){var e;for(e=0;e<16;e+=1)this.props[e]=t[e]}function db(t,e,r){return{x:t*this.props[0]+e*this.props[4]+r*this.props[8]+this.props[12],y:t*this.props[1]+e*this.props[5]+r*this.props[9]+this.props[13],z:t*this.props[2]+e*this.props[6]+r*this.props[10]+this.props[14]}}function eb(t,e,r){return t*this.props[0]+e*this.props[4]+r*this.props[8]+this.props[12]}function fb(t,e,r){return t*this.props[1]+e*this.props[5]+r*this.props[9]+this.props[13]}function gb(t,e,r){return t*this.props[2]+e*this.props[6]+r*this.props[10]+this.props[14]}function hb(t){var e=this.props[0]*this.props[5]-this.props[1]*this.props[4],r=this.props[5]/e,i=-this.props[1]/e,s=-this.props[4]/e,a=this.props[0]/e,n=(this.props[4]*this.props[13]-this.props[5]*this.props[12])/e,o=-(this.props[0]*this.props[13]-this.props[1]*this.props[12])/e;return[t[0]*r+t[1]*s+n,t[0]*i+t[1]*a+o,0]}function ib(t){var e,r=t.length,i=[];for(e=0;e<r;e+=1)i[e]=hb(t[e]);return i}function jb(t,e,r){var i=createTypedArray("float32",6);if(this.isIdentity())i[0]=t[0],i[1]=t[1],i[2]=e[0],i[3]=e[1],i[4]=r[0],i[5]=r[1];else{var s=this.props[0],a=this.props[1],n=this.props[4],o=this.props[5],h=this.props[12],p=this.props[13];i[0]=t[0]*s+t[1]*n+h,i[1]=t[0]*a+t[1]*o+p,i[2]=e[0]*s+e[1]*n+h,i[3]=e[0]*a+e[1]*o+p,i[4]=r[0]*s+r[1]*n+h,i[5]=r[0]*a+r[1]*o+p}return i}function kb(t,e,r){return this.isIdentity()?[t,e,r]:[t*this.props[0]+e*this.props[4]+r*this.props[8]+this.props[12],t*this.props[1]+e*this.props[5]+r*this.props[9]+this.props[13],t*this.props[2]+e*this.props[6]+r*this.props[10]+this.props[14]]}function lb(t,e){if(this.isIdentity())return t+","+e;var r=this.props;return Math.round(100*(t*r[0]+e*r[4]+r[12]))/100+","+Math.round(100*(t*r[1]+e*r[5]+r[13]))/100}function mb(){for(var t=0,e=this.props,r="matrix3d(";t<16;)r+=Oa(1e4*e[t])/1e4,r+=15===t?")":",",t+=1;return r}function nb(t){return t<1e-6&&0<t||-1e-6<t&&t<0?Oa(1e4*t)/1e4:t}function pb(){var t=this.props;return"matrix("+nb(t[0])+","+nb(t[1])+","+nb(t[4])+","+nb(t[5])+","+nb(t[12])+","+nb(t[13])+")"}!function(o,h){var p,l=this,m=256,f=6,c="random",d=h.pow(m,f),u=h.pow(2,52),y=2*u,g=m-1;function v(t){var e,r=t.length,n=this,i=0,s=n.i=n.j=0,a=n.S=[];for(r||(t=[r++]);i<m;)a[i]=i++;for(i=0;i<m;i++)a[i]=a[s=g&s+t[i%r]+(e=a[i])],a[s]=e;n.g=function(t){for(var e,r=0,i=n.i,s=n.j,a=n.S;t--;)e=a[i=g&i+1],r=r*m+a[g&(a[i]=a[s=g&s+e])+(a[s]=e)];return n.i=i,n.j=s,r}}function P(t,e){return e.i=t.i,e.j=t.j,e.S=t.S.slice(),e}function b(t,e){for(var r,i=t+"",s=0;s<i.length;)e[g&s]=g&(r^=19*e[g&s])+i.charCodeAt(s++);return x(e)}function x(t){return String.fromCharCode.apply(0,t)}h["seed"+c]=function(t,e,r){function i(){for(var t=n.g(f),e=d,r=0;t<u;)t=(t+r)*m,e*=m,r=n.g(1);for(;y<=t;)t/=2,e/=2,r>>>=1;return(t+r)/e}var s=[],a=b(function t(e,r){var i,s=[],a=typeof e;if(r&&"object"==a)for(i in e)try{s.push(t(e[i],r-1))}catch(t){}return s.length?s:"string"==a?e:e+"\0"}((e=!0===e?{entropy:!0}:e||{}).entropy?[t,x(o)]:null===t?function(){try{if(p)return x(p.randomBytes(m));var t=new Uint8Array(m);return(l.crypto||l.msCrypto).getRandomValues(t),x(t)}catch(t){var e=l.navigator,r=e&&e.plugins;return[+new Date,l,r,l.screen,x(o)]}}():t,3),s),n=new v(s);return i.int32=function(){return 0|n.g(4)},i.quick=function(){return n.g(4)/4294967296},i.double=i,b(x(n.S),o),(e.pass||r||function(t,e,r,i){return i&&(i.S&&P(i,n),t.state=function(){return P(n,{})}),r?(h[c]=t,e):t})(i,a,"global"in e?e.global:this==h,e.state)},b(h.random(),o)}([],BMMath);var BezierFactory=(_e={getBezierEasing:function(t,e,r,i,s){var a=s||("bez_"+t+"_"+e+"_"+r+"_"+i).replace(/\./g,"p");if(af[a])return af[a];var n=new rf([t,e,r,i]);return af[a]=n}},af={},gf=11,hf=1/(gf-1),jf="function"==typeof Float32Array,rf.prototype={get:function(t){var e=this._p[0],r=this._p[1],i=this._p[2],s=this._p[3];return this._precomputed||this._precompute(),e===r&&i===s?t:0===t?0:1===t?1:nf(this._getTForX(t),r,s)},_precompute:function(){var t=this._p[0],e=this._p[1],r=this._p[2],i=this._p[3];this._precomputed=!0,t===e&&r===i||this._calcSampleValues()},_calcSampleValues:function(){for(var t=this._p[0],e=this._p[2],r=0;r<gf;++r)this._mSampleValues[r]=nf(r*hf,t,e)},_getTForX:function(t){for(var e=this._p[0],r=this._p[2],i=this._mSampleValues,s=0,a=1,n=gf-1;a!==n&&i[a]<=t;++a)s+=hf;var o=s+(t-i[--a])/(i[a+1]-i[a])*hf,h=of(o,e,r);return.001<=h?function(t,e,r,i){for(var s=0;s<4;++s){var a=of(e,r,i);if(0===a)return e;e-=(nf(e,r,i)-t)/a}return e}(t,o,e,r):0===h?o:function(t,e,r,i,s){for(var a,n,o=0;0<(a=nf(n=e+(r-e)/2,i,s)-t)?r=n:e=n,1e-7<Math.abs(a)&&++o<10;);return n}(t,s,s+hf,e,r)}},_e),_e,af,gf,hf,jf;function kf(t,e){return 1-3*e+3*t}function lf(t,e){return 3*e-6*t}function mf(t){return 3*t}function nf(t,e,r){return((kf(e,r)*t+lf(e,r))*t+mf(e))*t}function of(t,e,r){return 3*kf(e,r)*t*t+2*lf(e,r)*t+mf(e)}function rf(t){this._p=t,this._mSampleValues=jf?new Float32Array(gf):new Array(gf),this._precomputed=!1,this.get=this.get.bind(this)}function extendPrototype(t,e){var r,i,s=t.length;for(r=0;r<s;r+=1)for(var a in i=t[r].prototype)i.hasOwnProperty(a)&&(e.prototype[a]=i[a])}function getDescriptor(t,e){return Object.getOwnPropertyDescriptor(t,e)}function createProxyFunction(t){function e(){}return e.prototype=t,e}function bezFunction(){Math;function y(t,e,r,i,s,a){var n=t*i+e*s+r*a-s*i-a*t-r*e;return-.001<n&&n<.001}var l=function(t,e,r,i){var s,a,n,o,h,p,l=defaultCurveSegments,m=0,f=[],c=[],d=bezier_length_pool.newElement();for(n=r.length,s=0;s<l;s+=1){for(h=s/(l-1),a=p=0;a<n;a+=1)o=bm_pow(1-h,3)*t[a]+3*bm_pow(1-h,2)*h*r[a]+3*(1-h)*bm_pow(h,2)*i[a]+bm_pow(h,3)*e[a],f[a]=o,null!==c[a]&&(p+=bm_pow(f[a]-c[a],2)),c[a]=f[a];p&&(m+=p=bm_sqrt(p)),d.percents[s]=h,d.lengths[s]=m}return d.addedLength=m,d};function g(t){this.segmentLength=0,this.points=new Array(t)}function v(t,e){this.partialLength=t,this.point=e}var P,t=(P={},function(t,e,r,i){var s=(t[0]+"_"+t[1]+"_"+e[0]+"_"+e[1]+"_"+r[0]+"_"+r[1]+"_"+i[0]+"_"+i[1]).replace(/\./g,"p");if(!P[s]){var a,n,o,h,p,l,m,f=defaultCurveSegments,c=0,d=null;2===t.length&&(t[0]!=e[0]||t[1]!=e[1])&&y(t[0],t[1],e[0],e[1],t[0]+r[0],t[1]+r[1])&&y(t[0],t[1],e[0],e[1],e[0]+i[0],e[1]+i[1])&&(f=2);var u=new g(f);for(o=r.length,a=0;a<f;a+=1){for(m=createSizedArray(o),p=a/(f-1),n=l=0;n<o;n+=1)h=bm_pow(1-p,3)*t[n]+3*bm_pow(1-p,2)*p*(t[n]+r[n])+3*(1-p)*bm_pow(p,2)*(e[n]+i[n])+bm_pow(p,3)*e[n],m[n]=h,null!==d&&(l+=bm_pow(m[n]-d[n],2));c+=l=bm_sqrt(l),u.points[a]=new v(l,m),d=m}u.segmentLength=c,P[s]=u}return P[s]});function D(t,e){var r=e.percents,i=e.lengths,s=r.length,a=bm_floor((s-1)*t),n=t*e.addedLength,o=0;if(a===s-1||0===a||n===i[a])return r[a];for(var h=i[a]>n?-1:1,p=!0;p;)if(i[a]<=n&&i[a+1]>n?(o=(n-i[a])/(i[a+1]-i[a]),p=!1):a+=h,a<0||s-1<=a){if(a===s-1)return r[a];p=!1}return r[a]+(r[a+1]-r[a])*o}var M=createTypedArray("float32",8);return{getSegmentsLength:function(t){var e,r=segments_length_pool.newElement(),i=t.c,s=t.v,a=t.o,n=t.i,o=t._length,h=r.lengths,p=0;for(e=0;e<o-1;e+=1)h[e]=l(s[e],s[e+1],a[e],n[e+1]),p+=h[e].addedLength;return i&&o&&(h[e]=l(s[e],s[0],a[e],n[0]),p+=h[e].addedLength),r.totalLength=p,r},getNewSegment:function(t,e,r,i,s,a,n){var o,h=D(s=s<0?0:1<s?1:s,n),p=D(a=1<a?1:a,n),l=t.length,m=1-h,f=1-p,c=m*m*m,d=h*m*m*3,u=h*h*m*3,y=h*h*h,g=m*m*f,v=h*m*f+m*h*f+m*m*p,P=h*h*f+m*h*p+h*m*p,b=h*h*p,x=m*f*f,_=h*f*f+m*p*f+m*f*p,S=h*p*f+m*p*p+h*f*p,T=h*p*p,A=f*f*f,C=p*f*f+f*p*f+f*f*p,E=p*p*f+f*p*p+p*f*p,k=p*p*p;for(o=0;o<l;o+=1)M[4*o]=Math.round(1e3*(c*t[o]+d*r[o]+u*i[o]+y*e[o]))/1e3,M[4*o+1]=Math.round(1e3*(g*t[o]+v*r[o]+P*i[o]+b*e[o]))/1e3,M[4*o+2]=Math.round(1e3*(x*t[o]+_*r[o]+S*i[o]+T*e[o]))/1e3,M[4*o+3]=Math.round(1e3*(A*t[o]+C*r[o]+E*i[o]+k*e[o]))/1e3;return M},getPointInSegment:function(t,e,r,i,s,a){var n=D(s,a),o=1-n;return[Math.round(1e3*(o*o*o*t[0]+(n*o*o+o*n*o+o*o*n)*r[0]+(n*n*o+o*n*n+n*o*n)*i[0]+n*n*n*e[0]))/1e3,Math.round(1e3*(o*o*o*t[1]+(n*o*o+o*n*o+o*o*n)*r[1]+(n*n*o+o*n*n+n*o*n)*i[1]+n*n*n*e[1]))/1e3]},buildBezierData:t,pointOnLine2D:y,pointOnLine3D:function(t,e,r,i,s,a,n,o,h){if(0===r&&0===a&&0===h)return y(t,e,i,s,n,o);var p,l=Math.sqrt(Math.pow(i-t,2)+Math.pow(s-e,2)+Math.pow(a-r,2)),m=Math.sqrt(Math.pow(n-t,2)+Math.pow(o-e,2)+Math.pow(h-r,2)),f=Math.sqrt(Math.pow(n-i,2)+Math.pow(o-s,2)+Math.pow(h-a,2));return-1e-4<(p=m<l?f<l?l-m-f:f-m-l:m<f?f-m-l:m-l-f)&&p<1e-4}}}!function(){for(var a=0,t=["ms","moz","webkit","o"],e=0;e<t.length&&!window.requestAnimationFrame;++e)window.requestAnimationFrame=window[t[e]+"RequestAnimationFrame"],window.cancelAnimationFrame=window[t[e]+"CancelAnimationFrame"]||window[t[e]+"CancelRequestAnimationFrame"];window.requestAnimationFrame||(window.requestAnimationFrame=function(t,e){var r=(new Date).getTime(),i=Math.max(0,16-(r-a)),s=setTimeout(function(){t(r+i)},i);return a=r+i,s}),window.cancelAnimationFrame||(window.cancelAnimationFrame=function(t){clearTimeout(t)})}();var bez=bezFunction();function dataFunctionManager(){function m(t,e,r){var i,s,a,n,o,h,p=t.length;for(s=0;s<p;s+=1)if("ks"in(i=t[s])&&!i.completed){if(i.completed=!0,i.tt&&(t[s-1].td=i.tt),[],-1,i.hasMask){var l=i.masksProperties;for(n=l.length,a=0;a<n;a+=1)if(l[a].pt.k.i)d(l[a].pt.k);else for(h=l[a].pt.k.length,o=0;o<h;o+=1)l[a].pt.k[o].s&&d(l[a].pt.k[o].s[0]),l[a].pt.k[o].e&&d(l[a].pt.k[o].e[0])}0===i.ty?(i.layers=f(i.refId,e),m(i.layers,e,r)):4===i.ty?c(i.shapes):5==i.ty&&b(i,r)}}function f(t,e){for(var r=0,i=e.length;r<i;){if(e[r].id===t)return e[r].layers.__used?JSON.parse(JSON.stringify(e[r].layers)):(e[r].layers.__used=!0,e[r].layers);r+=1}}function c(t){var e,r,i;for(e=t.length-1;0<=e;e-=1)if("sh"==t[e].ty){if(t[e].ks.k.i)d(t[e].ks.k);else for(i=t[e].ks.k.length,r=0;r<i;r+=1)t[e].ks.k[r].s&&d(t[e].ks.k[r].s[0]),t[e].ks.k[r].e&&d(t[e].ks.k[r].e[0]);!0}else"gr"==t[e].ty&&c(t[e].it)}function d(t){var e,r=t.i.length;for(e=0;e<r;e+=1)t.i[e][0]+=t.v[e][0],t.i[e][1]+=t.v[e][1],t.o[e][0]+=t.v[e][0],t.o[e][1]+=t.v[e][1]}function o(t,e){var r=e?e.split("."):[100,100,100];return t[0]>r[0]||!(r[0]>t[0])&&(t[1]>r[1]||!(r[1]>t[1])&&(t[2]>r[2]||!(r[2]>t[2])&&void 0))}var i,r=(i=[4,4,14],function(t){if(o(i,t.v)&&(s(t.layers),t.assets)){var e,r=t.assets.length;for(e=0;e<r;e+=1)t.assets[e].layers&&s(t.assets[e].layers)}});function s(t){var e,r,i,s=t.length;for(e=0;e<s;e+=1)5===t[e].ty&&(r=t[e],void 0,i=r.t.d,r.t.d={k:[{s:i,t:0}]})}var h,a,n=(h=[4,7,99],function(t){if(t.chars&&!o(h,t.v)){var e,r,i,s,a,n=t.chars.length;for(e=0;e<n;e+=1)if(t.chars[e].data&&t.chars[e].data.shapes)for(i=(a=t.chars[e].data.shapes[0].it).length,r=0;r<i;r+=1)(s=a[r].ks.k).__converted||(d(a[r].ks.k),s.__converted=!0)}}),p=(a=[4,1,9],function(t){if(o(a,t.v)&&(u(t.layers),t.assets)){var e,r=t.assets.length;for(e=0;e<r;e+=1)t.assets[e].layers&&u(t.assets[e].layers)}});function l(t){var e,r,i,s=t.length;for(e=0;e<s;e+=1)if("gr"===t[e].ty)l(t[e].it);else if("fl"===t[e].ty||"st"===t[e].ty)if(t[e].c.k&&t[e].c.k[0].i)for(i=t[e].c.k.length,r=0;r<i;r+=1)t[e].c.k[r].s&&(t[e].c.k[r].s[0]/=255,t[e].c.k[r].s[1]/=255,t[e].c.k[r].s[2]/=255,t[e].c.k[r].s[3]/=255),t[e].c.k[r].e&&(t[e].c.k[r].e[0]/=255,t[e].c.k[r].e[1]/=255,t[e].c.k[r].e[2]/=255,t[e].c.k[r].e[3]/=255);else t[e].c.k[0]/=255,t[e].c.k[1]/=255,t[e].c.k[2]/=255,t[e].c.k[3]/=255}function u(t){var e,r=t.length;for(e=0;e<r;e+=1)4===t[e].ty&&l(t[e].shapes)}var y,g=(y=[4,4,18],function(t){if(o(y,t.v)&&(P(t.layers),t.assets)){var e,r=t.assets.length;for(e=0;e<r;e+=1)t.assets[e].layers&&P(t.assets[e].layers)}});function v(t){var e,r,i;for(e=t.length-1;0<=e;e-=1)if("sh"==t[e].ty){if(t[e].ks.k.i)t[e].ks.k.c=t[e].closed;else for(i=t[e].ks.k.length,r=0;r<i;r+=1)t[e].ks.k[r].s&&(t[e].ks.k[r].s[0].c=t[e].closed),t[e].ks.k[r].e&&(t[e].ks.k[r].e[0].c=t[e].closed);!0}else"gr"==t[e].ty&&v(t[e].it)}function P(t){var e,r,i,s,a,n,o=t.length;for(r=0;r<o;r+=1){if((e=t[r]).hasMask){var h=e.masksProperties;for(s=h.length,i=0;i<s;i+=1)if(h[i].pt.k.i)h[i].pt.k.c=h[i].cl;else for(n=h[i].pt.k.length,a=0;a<n;a+=1)h[i].pt.k[a].s&&(h[i].pt.k[a].s[0].c=h[i].cl),h[i].pt.k[a].e&&(h[i].pt.k[a].e[0].c=h[i].cl)}4===e.ty&&v(e.shapes)}}function b(t,e){0!==t.t.a.length||"m"in t.t.p||(t.singleShape=!0)}var t={completeData:function(t,e){t.__complete||(p(t),r(t),n(t),g(t),m(t.layers,t.assets,e),t.__complete=!0)}};return t.checkColors=p,t.checkChars=n,t.checkShapes=g,t.completeLayers=m,t}var dataManager=dataFunctionManager();dataManager.completeData=function(t,e){t.__complete||(this.checkColors(t),this.checkChars(t),this.checkShapes(t),this.completeLayers(t.layers,t.assets,e),t.__complete=!0)};var FontManager=function(){var a={w:0,size:0,shapes:[]},t=[];function u(t,e){var r=createTag("span");r.style.fontFamily=e;var i=createTag("span");i.innerHTML="giItT1WQy@!-/#",r.style.position="absolute",r.style.left="-10000px",r.style.top="-10000px",r.style.fontSize="300px",r.style.fontVariant="normal",r.style.fontStyle="normal",r.style.fontWeight="normal",r.style.letterSpacing="0",r.appendChild(i),document.body.appendChild(r);var s=i.offsetWidth;return i.style.fontFamily=t+", "+e,{node:i,w:s,parent:r}}t=t.concat([2304,2305,2306,2307,2362,2363,2364,2364,2366,2367,2368,2369,2370,2371,2372,2373,2374,2375,2376,2377,2378,2379,2380,2381,2382,2383,2387,2388,2389,2390,2391,2402,2403]);function e(){this.fonts=[],this.chars=null,this.typekitLoaded=0,this.isLoaded=!1,this.initTime=Date.now()}return e.getCombinedCharacterCodes=function(){return t},e.prototype.addChars=function(t){if(t){this.chars||(this.chars=[]);var e,r,i,s=t.length,a=this.chars.length;for(e=0;e<s;e+=1){for(r=0,i=!1;r<a;)this.chars[r].style===t[e].style&&this.chars[r].fFamily===t[e].fFamily&&this.chars[r].ch===t[e].ch&&(i=!0),r+=1;i||(this.chars.push(t[e]),a+=1)}}},e.prototype.addFonts=function(t,e){if(t){if(this.chars)return this.isLoaded=!0,void(this.fonts=t.list);var r,i,s,a,n=t.list,o=n.length,h=o;for(r=0;r<o;r+=1){var p,l,m=!0;if(n[r].loaded=!1,n[r].monoCase=u(n[r].fFamily,"monospace"),n[r].sansCase=u(n[r].fFamily,"sans-serif"),n[r].fPath){if("p"===n[r].fOrigin||3===n[r].origin){if(0<(p=document.querySelectorAll('style[f-forigin="p"][f-family="'+n[r].fFamily+'"], style[f-origin="3"][f-family="'+n[r].fFamily+'"]')).length&&(m=!1),m){var f=createTag("style");f.setAttribute("f-forigin",n[r].fOrigin),f.setAttribute("f-origin",n[r].origin),f.setAttribute("f-family",n[r].fFamily),f.type="text/css",f.innerHTML="@font-face {font-family: "+n[r].fFamily+"; font-style: normal; src: url('"+n[r].fPath+"');}",e.appendChild(f)}}else if("g"===n[r].fOrigin||1===n[r].origin){for(p=document.querySelectorAll('link[f-forigin="g"], link[f-origin="1"]'),l=0;l<p.length;l++)-1!==p[l].href.indexOf(n[r].fPath)&&(m=!1);if(m){var c=createTag("link");c.setAttribute("f-forigin",n[r].fOrigin),c.setAttribute("f-origin",n[r].origin),c.type="text/css",c.rel="stylesheet",c.href=n[r].fPath,document.body.appendChild(c)}}else if("t"===n[r].fOrigin||2===n[r].origin){for(p=document.querySelectorAll('script[f-forigin="t"], script[f-origin="2"]'),l=0;l<p.length;l++)n[r].fPath===p[l].src&&(m=!1);if(m){var d=createTag("link");d.setAttribute("f-forigin",n[r].fOrigin),d.setAttribute("f-origin",n[r].origin),d.setAttribute("rel","stylesheet"),d.setAttribute("href",n[r].fPath),e.appendChild(d)}}}else n[r].loaded=!0,h-=1;n[r].helper=(i=e,s=n[r],a=void 0,(a=createNS("text")).style.fontSize="100px",a.setAttribute("font-family",s.fFamily),a.setAttribute("font-style",s.fStyle),a.setAttribute("font-weight",s.fWeight),a.textContent="1",s.fClass?(a.style.fontFamily="inherit",a.setAttribute("class",s.fClass)):a.style.fontFamily=s.fFamily,i.appendChild(a),createTag("canvas").getContext("2d").font=s.fWeight+" "+s.fStyle+" 100px "+s.fFamily,a),n[r].cache={},this.fonts.push(n[r])}0===h?this.isLoaded=!0:setTimeout(this.checkLoadedFonts.bind(this),100)}else this.isLoaded=!0},e.prototype.getCharData=function(t,e,r){for(var i=0,s=this.chars.length;i<s;){if(this.chars[i].ch===t&&this.chars[i].style===e&&this.chars[i].fFamily===r)return this.chars[i];i+=1}return console&&console.warn&&console.warn("Missing character from exported characters list: ",t,e,r),a},e.prototype.getFontByName=function(t){for(var e=0,r=this.fonts.length;e<r;){if(this.fonts[e].fName===t)return this.fonts[e];e+=1}return this.fonts[0]},e.prototype.measureText=function(t,e,r){var i=this.getFontByName(e),s=t.charCodeAt(0);if(!i.cache[s+1]){var a=i.helper;if(" "===t){a.textContent="|"+t+"|";var n=a.getComputedTextLength();a.textContent="||";var o=a.getComputedTextLength();i.cache[s+1]=(n-o)/100}else a.textContent=t,i.cache[s+1]=a.getComputedTextLength()/100}return i.cache[s+1]*r},e.prototype.checkLoadedFonts=function(){var t,e,r,i=this.fonts.length,s=i;for(t=0;t<i;t+=1)this.fonts[t].loaded?s-=1:"n"===this.fonts[t].fOrigin||0===this.fonts[t].origin?this.fonts[t].loaded=!0:(e=this.fonts[t].monoCase.node,r=this.fonts[t].monoCase.w,e.offsetWidth!==r?(s-=1,this.fonts[t].loaded=!0):(e=this.fonts[t].sansCase.node,r=this.fonts[t].sansCase.w,e.offsetWidth!==r&&(s-=1,this.fonts[t].loaded=!0)),this.fonts[t].loaded&&(this.fonts[t].sansCase.parent.parentNode.removeChild(this.fonts[t].sansCase.parent),this.fonts[t].monoCase.parent.parentNode.removeChild(this.fonts[t].monoCase.parent)));0!==s&&Date.now()-this.initTime<5e3?setTimeout(this.checkLoadedFonts.bind(this),20):setTimeout(function(){this.isLoaded=!0}.bind(this),0)},e.prototype.loaded=function(){return this.isLoaded},e}();FontManager=function(){this.fonts=[],this.chars=null,this.typekitLoaded=0,this.isLoaded=!1,this.initTime=Date.now()};var PropertyFactory=(km=initialDefaultFrame,lm=Math.abs,{getProp:function(t,e,r,i,s){var a;if(e.k.length)if("number"==typeof e.k[0])a=new vm(t,e,i,s);else switch(r){case 0:a=new wm(t,e,i,s);break;case 1:a=new xm(t,e,i,s)}else a=new um(t,e,i,s);return a.effectsSequence.length&&s.addDynamicProperty(a),a}}),km,lm;function mm(t,e){var r,i=this.offsetTime;"multidimensional"===this.propType&&(r=createTypedArray("float32",this.pv.length));for(var s,a,n,o,h,p,l,m,f=e.lastIndex,c=f,d=this.keyframes.length-1,u=!0;u;){if(s=this.keyframes[c],a=this.keyframes[c+1],c===d-1&&t>=a.t-i){s.h&&(s=a),f=0;break}if(a.t-i>t){f=c;break}c<d-1?c+=1:(f=0,u=!1)}var y,g=a.t-i,v=s.t-i;if(s.to){s.bezierData||(s.bezierData=bez.buildBezierData(s.s,a.s||s.e,s.to,s.ti));var P=s.bezierData;if(g<=t||t<v){var b=g<=t?P.points.length-1:0;for(o=P.points[b].point.length,n=0;n<o;n+=1)r[n]=P.points[b].point[n]}else{s.__fnct?m=s.__fnct:(m=BezierFactory.getBezierEasing(s.o.x,s.o.y,s.i.x,s.i.y,s.n).get,s.__fnct=m),h=m((t-v)/(g-v));var x,_=P.segmentLength*h,S=e.lastFrame<t&&e._lastKeyframeIndex===c?e._lastAddedLength:0;for(l=e.lastFrame<t&&e._lastKeyframeIndex===c?e._lastPoint:0,u=!0,p=P.points.length;u;){if(S+=P.points[l].partialLength,0==_||0===h||l===P.points.length-1){for(o=P.points[l].point.length,n=0;n<o;n+=1)r[n]=P.points[l].point[n];break}if(S<=_&&_<S+P.points[l+1].partialLength){for(x=(_-S)/P.points[l+1].partialLength,o=P.points[l].point.length,n=0;n<o;n+=1)r[n]=P.points[l].point[n]+(P.points[l+1].point[n]-P.points[l].point[n])*x;break}l<p-1?l+=1:u=!1}e._lastPoint=l,e._lastAddedLength=S-P.points[l].partialLength,e._lastKeyframeIndex=c}}else{var T,A,C,E,k;if(d=s.s.length,y=a.s||s.e,this.sh&&1!==s.h)if(g<=t)r[0]=y[0],r[1]=y[1],r[2]=y[2];else if(t<=v)r[0]=s.s[0],r[1]=s.s[1],r[2]=s.s[2];else{!function(t,e){var r=e[0],i=e[1],s=e[2],a=e[3],n=Math.atan2(2*i*a-2*r*s,1-2*i*i-2*s*s),o=Math.asin(2*r*i+2*s*a),h=Math.atan2(2*r*a-2*i*s,1-2*r*r-2*s*s);t[0]=n/degToRads,t[1]=o/degToRads,t[2]=h/degToRads}(r,function(t,e,r){var i,s,a,n,o,h=[],p=t[0],l=t[1],m=t[2],f=t[3],c=e[0],d=e[1],u=e[2],y=e[3];(s=p*c+l*d+m*u+f*y)<0&&(s=-s,c=-c,d=-d,u=-u,y=-y);o=1e-6<1-s?(i=Math.acos(s),a=Math.sin(i),n=Math.sin((1-r)*i)/a,Math.sin(r*i)/a):(n=1-r,r);return h[0]=n*p+o*c,h[1]=n*l+o*d,h[2]=n*m+o*u,h[3]=n*f+o*y,h}(pm(s.s),pm(y),(t-v)/(g-v)))}else for(c=0;c<d;c+=1)1!==s.h&&(h=g<=t?1:t<v?0:(s.o.x.constructor===Array?(s.__fnct||(s.__fnct=[]),s.__fnct[c]?m=s.__fnct[c]:(T=void 0===s.o.x[c]?s.o.x[0]:s.o.x[c],A=void 0===s.o.y[c]?s.o.y[0]:s.o.y[c],C=void 0===s.i.x[c]?s.i.x[0]:s.i.x[c],E=void 0===s.i.y[c]?s.i.y[0]:s.i.y[c],m=BezierFactory.getBezierEasing(T,A,C,E).get,s.__fnct[c]=m)):s.__fnct?m=s.__fnct:(T=s.o.x,A=s.o.y,C=s.i.x,E=s.i.y,m=BezierFactory.getBezierEasing(T,A,C,E).get,s.__fnct=m),m((t-v)/(g-v)))),y=a.s||s.e,k=1===s.h?s.s[c]:s.s[c]+(y[c]-s.s[c])*h,1===d?r=k:r[c]=k}return e.lastIndex=f,r}function pm(t){var e=t[0]*degToRads,r=t[1]*degToRads,i=t[2]*degToRads,s=Math.cos(e/2),a=Math.cos(r/2),n=Math.cos(i/2),o=Math.sin(e/2),h=Math.sin(r/2),p=Math.sin(i/2);return[o*h*n+s*a*p,o*a*n+s*h*p,s*h*n-o*a*p,s*a*n-o*h*p]}function qm(){var t=this.comp.renderedFrame-this.offsetTime,e=this.keyframes[0].t-this.offsetTime,r=this.keyframes[this.keyframes.length-1].t-this.offsetTime;if(!(t===this._caching.lastFrame||this._caching.lastFrame!==km&&(this._caching.lastFrame>=r&&r<=t||this._caching.lastFrame<e&&t<e))){this._caching.lastFrame>=t&&(this._caching._lastKeyframeIndex=-1,this._caching.lastIndex=0);var i=this.interpolateValue(t,this._caching);this.pv=i}return this._caching.lastFrame=t,this.pv}function rm(t){var e;if("unidimensional"===this.propType)e=t*this.mult,1e-5<lm(this.v-e)&&(this.v=e,this._mdf=!0);else for(var r=0,i=this.v.length;r<i;)e=t[r]*this.mult,1e-5<lm(this.v[r]-e)&&(this.v[r]=e,this._mdf=!0),r+=1}function sm(){if(this.elem.globalData.frameId!==this.frameId&&this.effectsSequence.length)if(this.lock)this.setVValue(this.pv);else{this.lock=!0,this._mdf=this._isFirstFrame;var t,e=this.effectsSequence.length,r=this.kf?this.pv:this.data.k;for(t=0;t<e;t+=1)r=this.effectsSequence[t](r);this.setVValue(r),this._isFirstFrame=!1,this.lock=!1,this.frameId=this.elem.globalData.frameId}}function tm(t){this.effectsSequence.push(t),this.container.addDynamicProperty(this)}function um(t,e,r,i){this.propType="unidimensional",this.mult=r||1,this.data=e,this.v=r?e.k*r:e.k,this.pv=e.k,this._mdf=!1,this.elem=t,this.container=i,this.comp=t.comp,this.k=!1,this.kf=!1,this.vel=0,this.effectsSequence=[],this._isFirstFrame=!0,this.getValue=sm,this.setVValue=rm,this.addEffect=tm}function vm(t,e,r,i){this.propType="multidimensional",this.mult=r||1,this.data=e,this._mdf=!1,this.elem=t,this.container=i,this.comp=t.comp,this.k=!1,this.kf=!1,this.frameId=-1;var s,a=e.k.length;this.v=createTypedArray("float32",a),this.pv=createTypedArray("float32",a);createTypedArray("float32",a);for(this.vel=createTypedArray("float32",a),s=0;s<a;s+=1)this.v[s]=e.k[s]*this.mult,this.pv[s]=e.k[s];this._isFirstFrame=!0,this.effectsSequence=[],this.getValue=sm,this.setVValue=rm,this.addEffect=tm}function wm(t,e,r,i){this.propType="unidimensional",this.keyframes=e.k,this.offsetTime=t.data.st,this.frameId=-1,this._caching={lastFrame:km,lastIndex:0,value:0,_lastKeyframeIndex:-1},this.k=!0,this.kf=!0,this.data=e,this.mult=r||1,this.elem=t,this.container=i,this.comp=t.comp,this.v=km,this.pv=km,this._isFirstFrame=!0,this.getValue=sm,this.setVValue=rm,this.interpolateValue=mm,this.effectsSequence=[qm.bind(this)],this.addEffect=tm}function xm(t,e,r,i){this.propType="multidimensional";var s,a,n,o,h,p=e.k.length;for(s=0;s<p-1;s+=1)e.k[s].to&&e.k[s].s&&e.k[s].e&&(a=e.k[s].s,n=e.k[s].e,o=e.k[s].to,h=e.k[s].ti,(2===a.length&&(a[0]!==n[0]||a[1]!==n[1])&&bez.pointOnLine2D(a[0],a[1],n[0],n[1],a[0]+o[0],a[1]+o[1])&&bez.pointOnLine2D(a[0],a[1],n[0],n[1],n[0]+h[0],n[1]+h[1])||3===a.length&&(a[0]!==n[0]||a[1]!==n[1]||a[2]!==n[2])&&bez.pointOnLine3D(a[0],a[1],a[2],n[0],n[1],n[2],a[0]+o[0],a[1]+o[1],a[2]+o[2])&&bez.pointOnLine3D(a[0],a[1],a[2],n[0],n[1],n[2],n[0]+h[0],n[1]+h[1],n[2]+h[2]))&&(e.k[s].to=null,e.k[s].ti=null),a[0]===n[0]&&a[1]===n[1]&&0===o[0]&&0===o[1]&&0===h[0]&&0===h[1]&&(2===a.length||a[2]===n[2]&&0===o[2]&&0===h[2])&&(e.k[s].to=null,e.k[s].ti=null));this.effectsSequence=[qm.bind(this)],this.keyframes=e.k,this.offsetTime=t.data.st,this.k=!0,this.kf=!0,this._isFirstFrame=!0,this.mult=r||1,this.elem=t,this.container=i,this.comp=t.comp,this.getValue=sm,this.setVValue=rm,this.interpolateValue=mm,this.frameId=-1;var l=e.k[0].s.length;for(this.v=createTypedArray("float32",l),this.pv=createTypedArray("float32",l),s=0;s<l;s+=1)this.v[s]=km,this.pv[s]=km;this._caching={lastFrame:km,lastIndex:0,value:createTypedArray("float32",l)},this.addEffect=tm}var TransformPropertyFactory=(Qo.prototype={applyToMatrix:function(t){var e=this._mdf;this.iterateDynamicProperties(),this._mdf=this._mdf||e,this.a&&t.translate(-this.a.v[0],-this.a.v[1],this.a.v[2]),this.s&&t.scale(this.s.v[0],this.s.v[1],this.s.v[2]),this.sk&&t.skewFromAxis(-this.sk.v,this.sa.v),this.r?t.rotate(-this.r.v):t.rotateZ(-this.rz.v).rotateY(this.ry.v).rotateX(this.rx.v).rotateZ(-this.or.v[2]).rotateY(this.or.v[1]).rotateX(this.or.v[0]),this.data.p.s?this.data.p.z?t.translate(this.px.v,this.py.v,-this.pz.v):t.translate(this.px.v,this.py.v,0):t.translate(this.p.v[0],this.p.v[1],-this.p.v[2])},getValue:function(t){if(this.elem.globalData.frameId!==this.frameId){if(this._isDirty&&(this.precalculateMatrix(),this._isDirty=!1),this.iterateDynamicProperties(),this._mdf||t){if(this.v.cloneFromProps(this.pre.props),this.appliedTransformations<1&&this.v.translate(-this.a.v[0],-this.a.v[1],this.a.v[2]),this.appliedTransformations<2&&this.v.scale(this.s.v[0],this.s.v[1],this.s.v[2]),this.sk&&this.appliedTransformations<3&&this.v.skewFromAxis(-this.sk.v,this.sa.v),this.r&&this.appliedTransformations<4?this.v.rotate(-this.r.v):!this.r&&this.appliedTransformations<4&&this.v.rotateZ(-this.rz.v).rotateY(this.ry.v).rotateX(this.rx.v).rotateZ(-this.or.v[2]).rotateY(this.or.v[1]).rotateX(this.or.v[0]),this.autoOriented){var e,r,i=this.elem.globalData.frameRate;if(this.p&&this.p.keyframes&&this.p.getValueAtTime)r=this.p._caching.lastFrame+this.p.offsetTime<=this.p.keyframes[0].t?(e=this.p.getValueAtTime((this.p.keyframes[0].t+.01)/i,0),this.p.getValueAtTime(this.p.keyframes[0].t/i,0)):this.p._caching.lastFrame+this.p.offsetTime>=this.p.keyframes[this.p.keyframes.length-1].t?(e=this.p.getValueAtTime(this.p.keyframes[this.p.keyframes.length-1].t/i,0),this.p.getValueAtTime((this.p.keyframes[this.p.keyframes.length-1].t-.01)/i,0)):(e=this.p.pv,this.p.getValueAtTime((this.p._caching.lastFrame+this.p.offsetTime-.01)/i,this.p.offsetTime));else if(this.px&&this.px.keyframes&&this.py.keyframes&&this.px.getValueAtTime&&this.py.getValueAtTime){e=[],r=[];var s=this.px,a=this.py;s._caching.lastFrame+s.offsetTime<=s.keyframes[0].t?(e[0]=s.getValueAtTime((s.keyframes[0].t+.01)/i,0),e[1]=a.getValueAtTime((a.keyframes[0].t+.01)/i,0),r[0]=s.getValueAtTime(s.keyframes[0].t/i,0),r[1]=a.getValueAtTime(a.keyframes[0].t/i,0)):s._caching.lastFrame+s.offsetTime>=s.keyframes[s.keyframes.length-1].t?(e[0]=s.getValueAtTime(s.keyframes[s.keyframes.length-1].t/i,0),e[1]=a.getValueAtTime(a.keyframes[a.keyframes.length-1].t/i,0),r[0]=s.getValueAtTime((s.keyframes[s.keyframes.length-1].t-.01)/i,0),r[1]=a.getValueAtTime((a.keyframes[a.keyframes.length-1].t-.01)/i,0)):(e=[s.pv,a.pv],r[0]=s.getValueAtTime((s._caching.lastFrame+s.offsetTime-.01)/i,s.offsetTime),r[1]=a.getValueAtTime((a._caching.lastFrame+a.offsetTime-.01)/i,a.offsetTime))}this.v.rotate(-Math.atan2(e[1]-r[1],e[0]-r[0]))}this.data.p&&this.data.p.s?this.data.p.z?this.v.translate(this.px.v,this.py.v,-this.pz.v):this.v.translate(this.px.v,this.py.v,0):this.v.translate(this.p.v[0],this.p.v[1],-this.p.v[2])}this.frameId=this.elem.globalData.frameId}},precalculateMatrix:function(){if(!this.a.k&&(this.pre.translate(-this.a.v[0],-this.a.v[1],this.a.v[2]),this.appliedTransformations=1,!this.s.effectsSequence.length)){if(this.pre.scale(this.s.v[0],this.s.v[1],this.s.v[2]),this.appliedTransformations=2,this.sk){if(this.sk.effectsSequence.length||this.sa.effectsSequence.length)return;this.pre.skewFromAxis(-this.sk.v,this.sa.v),this.appliedTransformations=3}if(this.r){if(this.r.effectsSequence.length)return;this.pre.rotate(-this.r.v),this.appliedTransformations=4}else this.rz.effectsSequence.length||this.ry.effectsSequence.length||this.rx.effectsSequence.length||this.or.effectsSequence.length||(this.pre.rotateZ(-this.rz.v).rotateY(this.ry.v).rotateX(this.rx.v).rotateZ(-this.or.v[2]).rotateY(this.or.v[1]).rotateX(this.or.v[0]),this.appliedTransformations=4)}},autoOrient:function(){}},extendPrototype([DynamicPropertyContainer],Qo),Qo.prototype.addDynamicProperty=function(t){this._addDynamicProperty(t),this.elem.addDynamicProperty(t),this._isDirty=!0},Qo.prototype._addDynamicProperty=DynamicPropertyContainer.prototype.addDynamicProperty,{getTransformProperty:function(t,e,r){return new Qo(t,e,r)}});function Qo(t,e,r){if(this.elem=t,this.frameId=-1,this.propType="transform",this.data=e,this.v=new Matrix,this.pre=new Matrix,this.appliedTransformations=0,this.initDynamicPropertyContainer(r||t),e.p&&e.p.s?(this.px=PropertyFactory.getProp(t,e.p.x,0,0,this),this.py=PropertyFactory.getProp(t,e.p.y,0,0,this),e.p.z&&(this.pz=PropertyFactory.getProp(t,e.p.z,0,0,this))):this.p=PropertyFactory.getProp(t,e.p||{k:[0,0,0]},1,0,this),e.rx){if(this.rx=PropertyFactory.getProp(t,e.rx,0,degToRads,this),this.ry=PropertyFactory.getProp(t,e.ry,0,degToRads,this),this.rz=PropertyFactory.getProp(t,e.rz,0,degToRads,this),e.or.k[0].ti){var i,s=e.or.k.length;for(i=0;i<s;i+=1)e.or.k[i].to=e.or.k[i].ti=null}this.or=PropertyFactory.getProp(t,e.or,1,degToRads,this),this.or.sh=!0}else this.r=PropertyFactory.getProp(t,e.r||{k:0},0,degToRads,this);e.sk&&(this.sk=PropertyFactory.getProp(t,e.sk,0,degToRads,this),this.sa=PropertyFactory.getProp(t,e.sa,0,degToRads,this)),this.a=PropertyFactory.getProp(t,e.a||{k:[0,0,0]},1,0,this),this.s=PropertyFactory.getProp(t,e.s||{k:[100,100,100]},1,.01,this),e.o?this.o=PropertyFactory.getProp(t,e.o,0,.01,t):this.o={_mdf:!1,v:1},this._isDirty=!0,this.dynamicProperties.length||this.getValue(!0)}function ShapePath(){this.c=!1,this._length=0,this._maxLength=8,this.v=createSizedArray(this._maxLength),this.o=createSizedArray(this._maxLength),this.i=createSizedArray(this._maxLength)}ShapePath.prototype.setPathData=function(t,e){this.c=t,this.setLength(e);for(var r=0;r<e;)this.v[r]=point_pool.newElement(),this.o[r]=point_pool.newElement(),this.i[r]=point_pool.newElement(),r+=1},ShapePath.prototype.setLength=function(t){for(;this._maxLength<t;)this.doubleArrayLength();this._length=t},ShapePath.prototype.doubleArrayLength=function(){this.v=this.v.concat(createSizedArray(this._maxLength)),this.i=this.i.concat(createSizedArray(this._maxLength)),this.o=this.o.concat(createSizedArray(this._maxLength)),this._maxLength*=2},ShapePath.prototype.setXYAt=function(t,e,r,i,s){var a;switch(this._length=Math.max(this._length,i+1),this._length>=this._maxLength&&this.doubleArrayLength(),r){case"v":a=this.v;break;case"i":a=this.i;break;case"o":a=this.o}a[i]&&(!a[i]||s)||(a[i]=point_pool.newElement()),a[i][0]=t,a[i][1]=e},ShapePath.prototype.setTripleAt=function(t,e,r,i,s,a,n,o){this.setXYAt(t,e,"v",n,o),this.setXYAt(r,i,"o",n,o),this.setXYAt(s,a,"i",n,o)},ShapePath.prototype.reverse=function(){var t=new ShapePath;t.setPathData(this.c,this._length);var e=this.v,r=this.o,i=this.i,s=0;this.c&&(t.setTripleAt(e[0][0],e[0][1],i[0][0],i[0][1],r[0][0],r[0][1],0,!1),s=1);var a,n=this._length-1,o=this._length;for(a=s;a<o;a+=1)t.setTripleAt(e[n][0],e[n][1],i[n][0],i[n][1],r[n][0],r[n][1],a,!1),n-=1;return t};var ShapePropertyFactory=function(){var s=-999999;function t(t,e,r){var i,s,a,n,o,h,p,l,m,f=r.lastIndex,c=this.keyframes;if(t<c[0].t-this.offsetTime)i=c[0].s[0],a=!0,f=0;else if(t>=c[c.length-1].t-this.offsetTime)i=c[c.length-1].s?c[c.length-1].s[0]:c[c.length-2].e[0],a=!0;else{for(var d,u,y=f,g=c.length-1,v=!0;v&&(d=c[y],!((u=c[y+1]).t-this.offsetTime>t));)y<g-1?y+=1:v=!1;if(f=y,!(a=1===d.h)){if(t>=u.t-this.offsetTime)l=1;else if(t<d.t-this.offsetTime)l=0;else{var P;d.__fnct?P=d.__fnct:(P=BezierFactory.getBezierEasing(d.o.x,d.o.y,d.i.x,d.i.y).get,d.__fnct=P),l=P((t-(d.t-this.offsetTime))/(u.t-this.offsetTime-(d.t-this.offsetTime)))}s=u.s?u.s[0]:d.e[0]}i=d.s[0]}for(h=e._length,p=i.i[0].length,r.lastIndex=f,n=0;n<h;n+=1)for(o=0;o<p;o+=1)m=a?i.i[n][o]:i.i[n][o]+(s.i[n][o]-i.i[n][o])*l,e.i[n][o]=m,m=a?i.o[n][o]:i.o[n][o]+(s.o[n][o]-i.o[n][o])*l,e.o[n][o]=m,m=a?i.v[n][o]:i.v[n][o]+(s.v[n][o]-i.v[n][o])*l,e.v[n][o]=m}function a(){this.paths=this.localShapeCollection}function e(t){!function(t,e){if(t._length!==e._length||t.c!==e.c)return!1;var r,i=t._length;for(r=0;r<i;r+=1)if(t.v[r][0]!==e.v[r][0]||t.v[r][1]!==e.v[r][1]||t.o[r][0]!==e.o[r][0]||t.o[r][1]!==e.o[r][1]||t.i[r][0]!==e.i[r][0]||t.i[r][1]!==e.i[r][1])return!1;return!0}(this.v,t)&&(this.v=shape_pool.clone(t),this.localShapeCollection.releaseShapes(),this.localShapeCollection.addShape(this.v),this._mdf=!0,this.paths=this.localShapeCollection)}function r(){if(this.elem.globalData.frameId!==this.frameId&&this.effectsSequence.length)if(this.lock)this.setVValue(this.pv);else{this.lock=!0,this._mdf=!1;var t,e=this.kf?this.pv:this.data.ks?this.data.ks.k:this.data.pt.k,r=this.effectsSequence.length;for(t=0;t<r;t+=1)e=this.effectsSequence[t](e);this.setVValue(e),this.lock=!1,this.frameId=this.elem.globalData.frameId}}function n(t,e,r){this.propType="shape",this.comp=t.comp,this.container=t,this.elem=t,this.data=e,this.k=!1,this.kf=!1,this._mdf=!1;var i=3===r?e.pt.k:e.ks.k;this.v=shape_pool.clone(i),this.pv=shape_pool.clone(this.v),this.localShapeCollection=shapeCollection_pool.newShapeCollection(),this.paths=this.localShapeCollection,this.paths.addShape(this.v),this.reset=a,this.effectsSequence=[]}function i(t){this.effectsSequence.push(t),this.container.addDynamicProperty(this)}function o(t,e,r){this.propType="shape",this.comp=t.comp,this.elem=t,this.container=t,this.offsetTime=t.data.st,this.keyframes=3===r?e.pt.k:e.ks.k,this.k=!0,this.kf=!0;var i=this.keyframes[0].s[0].i.length;this.keyframes[0].s[0].i[0].length;this.v=shape_pool.newElement(),this.v.setPathData(this.keyframes[0].s[0].c,i),this.pv=shape_pool.clone(this.v),this.localShapeCollection=shapeCollection_pool.newShapeCollection(),this.paths=this.localShapeCollection,this.paths.addShape(this.v),this.lastFrame=s,this.reset=a,this._caching={lastFrame:s,lastIndex:0},this.effectsSequence=[function(){var t=this.comp.renderedFrame-this.offsetTime,e=this.keyframes[0].t-this.offsetTime,r=this.keyframes[this.keyframes.length-1].t-this.offsetTime,i=this._caching.lastFrame;return i!==s&&(i<e&&t<e||r<i&&r<t)||(this._caching.lastIndex=i<t?this._caching.lastIndex:0,this.interpolateShape(t,this.pv,this._caching)),this._caching.lastFrame=t,this.pv}.bind(this)]}n.prototype.interpolateShape=t,n.prototype.getValue=r,n.prototype.setVValue=e,n.prototype.addEffect=i,o.prototype.getValue=r,o.prototype.interpolateShape=t,o.prototype.setVValue=e,o.prototype.addEffect=i;var h,p=(h=roundCorner,l.prototype={reset:a,getValue:function(){this.elem.globalData.frameId!==this.frameId&&(this.frameId=this.elem.globalData.frameId,this.iterateDynamicProperties(),this._mdf&&this.convertEllToPath())},convertEllToPath:function(){var t=this.p.v[0],e=this.p.v[1],r=this.s.v[0]/2,i=this.s.v[1]/2,s=3!==this.d,a=this.v;a.v[0][0]=t,a.v[0][1]=e-i,a.v[1][0]=s?t+r:t-r,a.v[1][1]=e,a.v[2][0]=t,a.v[2][1]=e+i,a.v[3][0]=s?t-r:t+r,a.v[3][1]=e,a.i[0][0]=s?t-r*h:t+r*h,a.i[0][1]=e-i,a.i[1][0]=s?t+r:t-r,a.i[1][1]=e-i*h,a.i[2][0]=s?t+r*h:t-r*h,a.i[2][1]=e+i,a.i[3][0]=s?t-r:t+r,a.i[3][1]=e+i*h,a.o[0][0]=s?t+r*h:t-r*h,a.o[0][1]=e-i,a.o[1][0]=s?t+r:t-r,a.o[1][1]=e+i*h,a.o[2][0]=s?t-r*h:t+r*h,a.o[2][1]=e+i,a.o[3][0]=s?t-r:t+r,a.o[3][1]=e-i*h}},extendPrototype([DynamicPropertyContainer],l),l);function l(t,e){this.v=shape_pool.newElement(),this.v.setPathData(!0,4),this.localShapeCollection=shapeCollection_pool.newShapeCollection(),this.paths=this.localShapeCollection,this.localShapeCollection.addShape(this.v),this.d=e.d,this.elem=t,this.comp=t.comp,this.frameId=-1,this.initDynamicPropertyContainer(t),this.p=PropertyFactory.getProp(t,e.p,1,0,this),this.s=PropertyFactory.getProp(t,e.s,1,0,this),this.dynamicProperties.length?this.k=!0:(this.k=!1,this.convertEllToPath())}var m=(f.prototype={reset:a,getValue:function(){this.elem.globalData.frameId!==this.frameId&&(this.frameId=this.elem.globalData.frameId,this.iterateDynamicProperties(),this._mdf&&this.convertToPath())},convertStarToPath:function(){var t,e,r,i,s=2*Math.floor(this.pt.v),a=2*Math.PI/s,n=!0,o=this.or.v,h=this.ir.v,p=this.os.v,l=this.is.v,m=2*Math.PI*o/(2*s),f=2*Math.PI*h/(2*s),c=-Math.PI/2;c+=this.r.v;var d=3===this.data.d?-1:1;for(t=this.v._length=0;t<s;t+=1){r=n?p:l,i=n?m:f;var u=(e=n?o:h)*Math.cos(c),y=e*Math.sin(c),g=0===u&&0===y?0:y/Math.sqrt(u*u+y*y),v=0===u&&0===y?0:-u/Math.sqrt(u*u+y*y);u+=+this.p.v[0],y+=+this.p.v[1],this.v.setTripleAt(u,y,u-g*i*r*d,y-v*i*r*d,u+g*i*r*d,y+v*i*r*d,t,!0),n=!n,c+=a*d}},convertPolygonToPath:function(){var t,e=Math.floor(this.pt.v),r=2*Math.PI/e,i=this.or.v,s=this.os.v,a=2*Math.PI*i/(4*e),n=-Math.PI/2,o=3===this.data.d?-1:1;for(n+=this.r.v,t=this.v._length=0;t<e;t+=1){var h=i*Math.cos(n),p=i*Math.sin(n),l=0===h&&0===p?0:p/Math.sqrt(h*h+p*p),m=0===h&&0===p?0:-h/Math.sqrt(h*h+p*p);h+=+this.p.v[0],p+=+this.p.v[1],this.v.setTripleAt(h,p,h-l*a*s*o,p-m*a*s*o,h+l*a*s*o,p+m*a*s*o,t,!0),n+=r*o}this.paths.length=0,this.paths[0]=this.v}},extendPrototype([DynamicPropertyContainer],f),f);function f(t,e){this.v=shape_pool.newElement(),this.v.setPathData(!0,0),this.elem=t,this.comp=t.comp,this.data=e,this.frameId=-1,this.d=e.d,this.initDynamicPropertyContainer(t),1===e.sy?(this.ir=PropertyFactory.getProp(t,e.ir,0,0,this),this.is=PropertyFactory.getProp(t,e.is,0,.01,this),this.convertToPath=this.convertStarToPath):this.convertToPath=this.convertPolygonToPath,this.pt=PropertyFactory.getProp(t,e.pt,0,0,this),this.p=PropertyFactory.getProp(t,e.p,1,0,this),this.r=PropertyFactory.getProp(t,e.r,0,degToRads,this),this.or=PropertyFactory.getProp(t,e.or,0,0,this),this.os=PropertyFactory.getProp(t,e.os,0,.01,this),this.localShapeCollection=shapeCollection_pool.newShapeCollection(),this.localShapeCollection.addShape(this.v),this.paths=this.localShapeCollection,this.dynamicProperties.length?this.k=!0:(this.k=!1,this.convertToPath())}var c=(d.prototype={convertRectToPath:function(){var t=this.p.v[0],e=this.p.v[1],r=this.s.v[0]/2,i=this.s.v[1]/2,s=bm_min(r,i,this.r.v),a=s*(1-roundCorner);this.v._length=0,2===this.d||1===this.d?(this.v.setTripleAt(t+r,e-i+s,t+r,e-i+s,t+r,e-i+a,0,!0),this.v.setTripleAt(t+r,e+i-s,t+r,e+i-a,t+r,e+i-s,1,!0),0!==s?(this.v.setTripleAt(t+r-s,e+i,t+r-s,e+i,t+r-a,e+i,2,!0),this.v.setTripleAt(t-r+s,e+i,t-r+a,e+i,t-r+s,e+i,3,!0),this.v.setTripleAt(t-r,e+i-s,t-r,e+i-s,t-r,e+i-a,4,!0),this.v.setTripleAt(t-r,e-i+s,t-r,e-i+a,t-r,e-i+s,5,!0),this.v.setTripleAt(t-r+s,e-i,t-r+s,e-i,t-r+a,e-i,6,!0),this.v.setTripleAt(t+r-s,e-i,t+r-a,e-i,t+r-s,e-i,7,!0)):(this.v.setTripleAt(t-r,e+i,t-r+a,e+i,t-r,e+i,2),this.v.setTripleAt(t-r,e-i,t-r,e-i+a,t-r,e-i,3))):(this.v.setTripleAt(t+r,e-i+s,t+r,e-i+a,t+r,e-i+s,0,!0),0!==s?(this.v.setTripleAt(t+r-s,e-i,t+r-s,e-i,t+r-a,e-i,1,!0),this.v.setTripleAt(t-r+s,e-i,t-r+a,e-i,t-r+s,e-i,2,!0),this.v.setTripleAt(t-r,e-i+s,t-r,e-i+s,t-r,e-i+a,3,!0),this.v.setTripleAt(t-r,e+i-s,t-r,e+i-a,t-r,e+i-s,4,!0),this.v.setTripleAt(t-r+s,e+i,t-r+s,e+i,t-r+a,e+i,5,!0),this.v.setTripleAt(t+r-s,e+i,t+r-a,e+i,t+r-s,e+i,6,!0),this.v.setTripleAt(t+r,e+i-s,t+r,e+i-s,t+r,e+i-a,7,!0)):(this.v.setTripleAt(t-r,e-i,t-r+a,e-i,t-r,e-i,1,!0),this.v.setTripleAt(t-r,e+i,t-r,e+i-a,t-r,e+i,2,!0),this.v.setTripleAt(t+r,e+i,t+r-a,e+i,t+r,e+i,3,!0)))},getValue:function(t){this.elem.globalData.frameId!==this.frameId&&(this.frameId=this.elem.globalData.frameId,this.iterateDynamicProperties(),this._mdf&&this.convertRectToPath())},reset:a},extendPrototype([DynamicPropertyContainer],d),d);function d(t,e){this.v=shape_pool.newElement(),this.v.c=!0,this.localShapeCollection=shapeCollection_pool.newShapeCollection(),this.localShapeCollection.addShape(this.v),this.paths=this.localShapeCollection,this.elem=t,this.comp=t.comp,this.frameId=-1,this.d=e.d,this.initDynamicPropertyContainer(t),this.p=PropertyFactory.getProp(t,e.p,1,0,this),this.s=PropertyFactory.getProp(t,e.s,1,0,this),this.r=PropertyFactory.getProp(t,e.r,0,0,this),this.dynamicProperties.length?this.k=!0:(this.k=!1,this.convertRectToPath())}var u={getShapeProp:function(t,e,r){var i;return 3===r||4===r?i=(3===r?e.pt:e.ks).k.length?new o(t,e,r):new n(t,e,r):5===r?i=new c(t,e):6===r?i=new p(t,e):7===r&&(i=new m(t,e)),i.k&&t.addDynamicProperty(i),i},getConstructorFunction:function(){return n},getKeyframedConstructorFunction:function(){return o}};return u}(),ShapeModifiers=(Tr={},Ur={},Tr.registerModifier=function(t,e){Ur[t]||(Ur[t]=e)},Tr.getModifier=function(t,e,r){return new Ur[t](e,r)},Tr),Tr,Ur;function ShapeModifier(){}function TrimModifier(){}function RoundCornersModifier(){}function RepeaterModifier(){}function ShapeCollection(){this._length=0,this._maxLength=4,this.shapes=createSizedArray(this._maxLength)}function DashProperty(t,e,r,i){this.elem=t,this.frameId=-1,this.dataProps=createSizedArray(e.length),this.renderer=r,this.k=!1,this.dashStr="",this.dashArray=createTypedArray("float32",e.length?e.length-1:0),this.dashoffset=createTypedArray("float32",1),this.initDynamicPropertyContainer(i);var s,a,n=e.length||0;for(s=0;s<n;s+=1)a=PropertyFactory.getProp(t,e[s].v,0,0,this),this.k=a.k||this.k,this.dataProps[s]={n:e[s].n,p:a};this.k||this.getValue(!0),this._isAnimated=this.k}function GradientProperty(t,e,r){this.data=e,this.c=createTypedArray("uint8c",4*e.p);var i=e.k.k[0].s?e.k.k[0].s.length-4*e.p:e.k.k.length-4*e.p;this.o=createTypedArray("float32",i),this._cmdf=!1,this._omdf=!1,this._collapsable=this.checkCollapsable(),this._hasOpacity=i,this.initDynamicPropertyContainer(r),this.prop=PropertyFactory.getProp(t,e.k,1,null,this),this.k=this.prop.k,this.getValue(!0)}ShapeModifier.prototype.initModifierProperties=function(){},ShapeModifier.prototype.addShapeToModifier=function(){},ShapeModifier.prototype.addShape=function(t){if(!this.closed){var e={shape:t.sh,data:t,localShapeCollection:shapeCollection_pool.newShapeCollection()};this.shapes.push(e),this.addShapeToModifier(e),this._isAnimated&&t.setAsAnimated()}},ShapeModifier.prototype.init=function(t,e){this.shapes=[],this.elem=t,this.initDynamicPropertyContainer(t),this.initModifierProperties(t,e),this.frameId=initialDefaultFrame,this.closed=!1,this.k=!1,this.dynamicProperties.length?this.k=!0:this.getValue(!0)},ShapeModifier.prototype.processKeys=function(){this.elem.globalData.frameId!==this.frameId&&(this.frameId=this.elem.globalData.frameId,this.iterateDynamicProperties())},extendPrototype([DynamicPropertyContainer],ShapeModifier),extendPrototype([ShapeModifier],TrimModifier),TrimModifier.prototype.initModifierProperties=function(t,e){this.s=PropertyFactory.getProp(t,e.s,0,.01,this),this.e=PropertyFactory.getProp(t,e.e,0,.01,this),this.o=PropertyFactory.getProp(t,e.o,0,0,this),this.sValue=0,this.eValue=0,this.getValue=this.processKeys,this.m=e.m,this._isAnimated=!!this.s.effectsSequence.length||!!this.e.effectsSequence.length||!!this.o.effectsSequence.length},TrimModifier.prototype.addShapeToModifier=function(t){t.pathsData=[]},TrimModifier.prototype.calculateShapeEdges=function(t,e,r,i,s){var a=[];e<=1?a.push({s:t,e:e}):1<=t?a.push({s:t-1,e:e-1}):(a.push({s:t,e:1}),a.push({s:0,e:e-1}));var n,o,h=[],p=a.length;for(n=0;n<p;n+=1){var l,m;if((o=a[n]).e*s<i||o.s*s>i+r);else l=o.s*s<=i?0:(o.s*s-i)/r,m=o.e*s>=i+r?1:(o.e*s-i)/r,h.push([l,m])}return h.length||h.push([0,0]),h},TrimModifier.prototype.releasePathsData=function(t){var e,r=t.length;for(e=0;e<r;e+=1)segments_length_pool.release(t[e]);return t.length=0,t},TrimModifier.prototype.processShapes=function(t){var e,r,i;if(this._mdf||t){var s=this.o.v%360/360;if(s<0&&(s+=1),e=(1<this.s.v?1:this.s.v<0?0:this.s.v)+s,(r=(1<this.e.v?1:this.e.v<0?0:this.e.v)+s)<e){var a=e;e=r,r=a}e=1e-4*Math.round(1e4*e),r=1e-4*Math.round(1e4*r),this.sValue=e,this.eValue=r}else e=this.sValue,r=this.eValue;var n,o,h,p,l,m,f=this.shapes.length,c=0;if(r===e)for(n=0;n<f;n+=1)this.shapes[n].localShapeCollection.releaseShapes(),this.shapes[n].shape._mdf=!0,this.shapes[n].shape.paths=this.shapes[n].localShapeCollection;else if(1===r&&0===e||0===r&&1===e){if(this._mdf)for(n=0;n<f;n+=1)this.shapes[n].pathsData.length=0,this.shapes[n].shape._mdf=!0}else{var d,u,y=[];for(n=0;n<f;n+=1)if((d=this.shapes[n]).shape._mdf||this._mdf||t||2===this.m){if(h=(i=d.shape.paths)._length,m=0,!d.shape._mdf&&d.pathsData.length)m=d.totalShapeLength;else{for(p=this.releasePathsData(d.pathsData),o=0;o<h;o+=1)l=bez.getSegmentsLength(i.shapes[o]),p.push(l),m+=l.totalLength;d.totalShapeLength=m,d.pathsData=p}c+=m,d.shape._mdf=!0}else d.shape.paths=d.localShapeCollection;var g,v=e,P=r,b=0;for(n=f-1;0<=n;n-=1)if((d=this.shapes[n]).shape._mdf){for((u=d.localShapeCollection).releaseShapes(),2===this.m&&1<f?(g=this.calculateShapeEdges(e,r,d.totalShapeLength,b,c),b+=d.totalShapeLength):g=[[v,P]],h=g.length,o=0;o<h;o+=1){v=g[o][0],P=g[o][1],y.length=0,P<=1?y.push({s:d.totalShapeLength*v,e:d.totalShapeLength*P}):1<=v?y.push({s:d.totalShapeLength*(v-1),e:d.totalShapeLength*(P-1)}):(y.push({s:d.totalShapeLength*v,e:d.totalShapeLength}),y.push({s:0,e:d.totalShapeLength*(P-1)}));var x=this.addShapes(d,y[0]);if(y[0].s!==y[0].e){if(1<y.length)if(d.shape.paths.shapes[d.shape.paths._length-1].c){var _=x.pop();this.addPaths(x,u),x=this.addShapes(d,y[1],_)}else this.addPaths(x,u),x=this.addShapes(d,y[1]);this.addPaths(x,u)}}d.shape.paths=u}}},TrimModifier.prototype.addPaths=function(t,e){var r,i=t.length;for(r=0;r<i;r+=1)e.addShape(t[r])},TrimModifier.prototype.addSegment=function(t,e,r,i,s,a,n){s.setXYAt(e[0],e[1],"o",a),s.setXYAt(r[0],r[1],"i",a+1),n&&s.setXYAt(t[0],t[1],"v",a),s.setXYAt(i[0],i[1],"v",a+1)},TrimModifier.prototype.addSegmentFromArray=function(t,e,r,i){e.setXYAt(t[1],t[5],"o",r),e.setXYAt(t[2],t[6],"i",r+1),i&&e.setXYAt(t[0],t[4],"v",r),e.setXYAt(t[3],t[7],"v",r+1)},TrimModifier.prototype.addShapes=function(t,e,r){var i,s,a,n,o,h,p,l,m=t.pathsData,f=t.shape.paths.shapes,c=t.shape.paths._length,d=0,u=[],y=!0;for(l=r?(o=r._length,r._length):(r=shape_pool.newElement(),o=0),u.push(r),i=0;i<c;i+=1){for(h=m[i].lengths,r.c=f[i].c,a=f[i].c?h.length:h.length+1,s=1;s<a;s+=1)if(d+(n=h[s-1]).addedLength<e.s)d+=n.addedLength,r.c=!1;else{if(d>e.e){r.c=!1;break}e.s<=d&&e.e>=d+n.addedLength?(this.addSegment(f[i].v[s-1],f[i].o[s-1],f[i].i[s],f[i].v[s],r,o,y),y=!1):(p=bez.getNewSegment(f[i].v[s-1],f[i].v[s],f[i].o[s-1],f[i].i[s],(e.s-d)/n.addedLength,(e.e-d)/n.addedLength,h[s-1]),this.addSegmentFromArray(p,r,o,y),y=!1,r.c=!1),d+=n.addedLength,o+=1}if(f[i].c&&h.length){if(n=h[s-1],d<=e.e){var g=h[s-1].addedLength;e.s<=d&&e.e>=d+g?(this.addSegment(f[i].v[s-1],f[i].o[s-1],f[i].i[0],f[i].v[0],r,o,y),y=!1):(p=bez.getNewSegment(f[i].v[s-1],f[i].v[0],f[i].o[s-1],f[i].i[0],(e.s-d)/g,(e.e-d)/g,h[s-1]),this.addSegmentFromArray(p,r,o,y),y=!1,r.c=!1)}else r.c=!1;d+=n.addedLength,o+=1}if(r._length&&(r.setXYAt(r.v[l][0],r.v[l][1],"i",l),r.setXYAt(r.v[r._length-1][0],r.v[r._length-1][1],"o",r._length-1)),d>e.e)break;i<c-1&&(r=shape_pool.newElement(),y=!0,u.push(r),o=0)}return u},ShapeModifiers.registerModifier("tm",TrimModifier),extendPrototype([ShapeModifier],RoundCornersModifier),RoundCornersModifier.prototype.initModifierProperties=function(t,e){this.getValue=this.processKeys,this.rd=PropertyFactory.getProp(t,e.r,0,null,this),this._isAnimated=!!this.rd.effectsSequence.length},RoundCornersModifier.prototype.processPath=function(t,e){var r=shape_pool.newElement();r.c=t.c;var i,s,a,n,o,h,p,l,m,f,c,d,u,y=t._length,g=0;for(i=0;i<y;i+=1)s=t.v[i],n=t.o[i],a=t.i[i],s[0]===n[0]&&s[1]===n[1]&&s[0]===a[0]&&s[1]===a[1]?0!==i&&i!==y-1||t.c?(o=0===i?t.v[y-1]:t.v[i-1],p=(h=Math.sqrt(Math.pow(s[0]-o[0],2)+Math.pow(s[1]-o[1],2)))?Math.min(h/2,e)/h:0,l=d=s[0]+(o[0]-s[0])*p,m=u=s[1]-(s[1]-o[1])*p,f=l-(l-s[0])*roundCorner,c=m-(m-s[1])*roundCorner,r.setTripleAt(l,m,f,c,d,u,g),g+=1,o=i===y-1?t.v[0]:t.v[i+1],p=(h=Math.sqrt(Math.pow(s[0]-o[0],2)+Math.pow(s[1]-o[1],2)))?Math.min(h/2,e)/h:0,l=f=s[0]+(o[0]-s[0])*p,m=c=s[1]+(o[1]-s[1])*p,d=l-(l-s[0])*roundCorner,u=m-(m-s[1])*roundCorner,r.setTripleAt(l,m,f,c,d,u,g)):r.setTripleAt(s[0],s[1],n[0],n[1],a[0],a[1],g):r.setTripleAt(t.v[i][0],t.v[i][1],t.o[i][0],t.o[i][1],t.i[i][0],t.i[i][1],g),g+=1;return r},RoundCornersModifier.prototype.processShapes=function(t){var e,r,i,s,a,n,o=this.shapes.length,h=this.rd.v;if(0!==h)for(r=0;r<o;r+=1){if((a=this.shapes[r]).shape.paths,n=a.localShapeCollection,a.shape._mdf||this._mdf||t)for(n.releaseShapes(),a.shape._mdf=!0,e=a.shape.paths.shapes,s=a.shape.paths._length,i=0;i<s;i+=1)n.addShape(this.processPath(e[i],h));a.shape.paths=a.localShapeCollection}this.dynamicProperties.length||(this._mdf=!1)},ShapeModifiers.registerModifier("rd",RoundCornersModifier),extendPrototype([ShapeModifier],RepeaterModifier),RepeaterModifier.prototype.initModifierProperties=function(t,e){this.getValue=this.processKeys,this.c=PropertyFactory.getProp(t,e.c,0,null,this),this.o=PropertyFactory.getProp(t,e.o,0,null,this),this.tr=TransformPropertyFactory.getTransformProperty(t,e.tr,this),this.so=PropertyFactory.getProp(t,e.tr.so,0,.01,this),this.eo=PropertyFactory.getProp(t,e.tr.eo,0,.01,this),this.data=e,this.dynamicProperties.length||this.getValue(!0),this._isAnimated=!!this.dynamicProperties.length,this.pMatrix=new Matrix,this.rMatrix=new Matrix,this.sMatrix=new Matrix,this.tMatrix=new Matrix,this.matrix=new Matrix},RepeaterModifier.prototype.applyTransforms=function(t,e,r,i,s,a){var n=a?-1:1,o=i.s.v[0]+(1-i.s.v[0])*(1-s),h=i.s.v[1]+(1-i.s.v[1])*(1-s);t.translate(i.p.v[0]*n*s,i.p.v[1]*n*s,i.p.v[2]),e.translate(-i.a.v[0],-i.a.v[1],i.a.v[2]),e.rotate(-i.r.v*n*s),e.translate(i.a.v[0],i.a.v[1],i.a.v[2]),r.translate(-i.a.v[0],-i.a.v[1],i.a.v[2]),r.scale(a?1/o:o,a?1/h:h),r.translate(i.a.v[0],i.a.v[1],i.a.v[2])},RepeaterModifier.prototype.init=function(t,e,r,i){this.elem=t,this.arr=e,this.pos=r,this.elemsData=i,this._currentCopies=0,this._elements=[],this._groups=[],this.frameId=-1,this.initDynamicPropertyContainer(t),this.initModifierProperties(t,e[r]);for(;0<r;)r-=1,this._elements.unshift(e[r]),1;this.dynamicProperties.length?this.k=!0:this.getValue(!0)},RepeaterModifier.prototype.resetElements=function(t){var e,r=t.length;for(e=0;e<r;e+=1)t[e]._processed=!1,"gr"===t[e].ty&&this.resetElements(t[e].it)},RepeaterModifier.prototype.cloneElements=function(t){t.length;var e=JSON.parse(JSON.stringify(t));return this.resetElements(e),e},RepeaterModifier.prototype.changeGroupRender=function(t,e){var r,i=t.length;for(r=0;r<i;r+=1)t[r]._render=e,"gr"===t[r].ty&&this.changeGroupRender(t[r].it,e)},RepeaterModifier.prototype.processShapes=function(t){var e,r,i,s,a;if(this._mdf||t){var n,o=Math.ceil(this.c.v);if(this._groups.length<o){for(;this._groups.length<o;){var h={it:this.cloneElements(this._elements),ty:"gr"};h.it.push({a:{a:0,ix:1,k:[0,0]},nm:"Transform",o:{a:0,ix:7,k:100},p:{a:0,ix:2,k:[0,0]},r:{a:1,ix:6,k:[{s:0,e:0,t:0},{s:0,e:0,t:1}]},s:{a:0,ix:3,k:[100,100]},sa:{a:0,ix:5,k:0},sk:{a:0,ix:4,k:0},ty:"tr"}),this.arr.splice(0,0,h),this._groups.splice(0,0,h),this._currentCopies+=1}this.elem.reloadShapes()}for(i=a=0;i<=this._groups.length-1;i+=1)n=a<o,this._groups[i]._render=n,this.changeGroupRender(this._groups[i].it,n),a+=1;this._currentCopies=o;var p=this.o.v,l=p%1,m=0<p?Math.floor(p):Math.ceil(p),f=(this.tr.v.props,this.pMatrix.props),c=this.rMatrix.props,d=this.sMatrix.props;this.pMatrix.reset(),this.rMatrix.reset(),this.sMatrix.reset(),this.tMatrix.reset(),this.matrix.reset();var u,y,g=0;if(0<p){for(;g<m;)this.applyTransforms(this.pMatrix,this.rMatrix,this.sMatrix,this.tr,1,!1),g+=1;l&&(this.applyTransforms(this.pMatrix,this.rMatrix,this.sMatrix,this.tr,l,!1),g+=l)}else if(p<0){for(;m<g;)this.applyTransforms(this.pMatrix,this.rMatrix,this.sMatrix,this.tr,1,!0),g-=1;l&&(this.applyTransforms(this.pMatrix,this.rMatrix,this.sMatrix,this.tr,-l,!0),g-=l)}for(i=1===this.data.m?0:this._currentCopies-1,s=1===this.data.m?1:-1,a=this._currentCopies;a;){if(y=(r=(e=this.elemsData[i].it)[e.length-1].transform.mProps.v.props).length,e[e.length-1].transform.mProps._mdf=!0,e[e.length-1].transform.op._mdf=!0,e[e.length-1].transform.op.v=this.so.v+(this.eo.v-this.so.v)*(i/(this._currentCopies-1)),0!==g){for((0!==i&&1===s||i!==this._currentCopies-1&&-1===s)&&this.applyTransforms(this.pMatrix,this.rMatrix,this.sMatrix,this.tr,1,!1),this.matrix.transform(c[0],c[1],c[2],c[3],c[4],c[5],c[6],c[7],c[8],c[9],c[10],c[11],c[12],c[13],c[14],c[15]),this.matrix.transform(d[0],d[1],d[2],d[3],d[4],d[5],d[6],d[7],d[8],d[9],d[10],d[11],d[12],d[13],d[14],d[15]),this.matrix.transform(f[0],f[1],f[2],f[3],f[4],f[5],f[6],f[7],f[8],f[9],f[10],f[11],f[12],f[13],f[14],f[15]),u=0;u<y;u+=1)r[u]=this.matrix.props[u];this.matrix.reset()}else for(this.matrix.reset(),u=0;u<y;u+=1)r[u]=this.matrix.props[u];g+=1,a-=1,i+=s}}else for(a=this._currentCopies,i=0,s=1;a;)r=(e=this.elemsData[i].it)[e.length-1].transform.mProps.v.props,e[e.length-1].transform.mProps._mdf=!1,e[e.length-1].transform.op._mdf=!1,a-=1,i+=s},RepeaterModifier.prototype.addShape=function(){},ShapeModifiers.registerModifier("rp",RepeaterModifier),ShapeCollection.prototype.addShape=function(t){this._length===this._maxLength&&(this.shapes=this.shapes.concat(createSizedArray(this._maxLength)),this._maxLength*=2),this.shapes[this._length]=t,this._length+=1},ShapeCollection.prototype.releaseShapes=function(){var t;for(t=0;t<this._length;t+=1)shape_pool.release(this.shapes[t]);this._length=0},DashProperty.prototype.getValue=function(t){if((this.elem.globalData.frameId!==this.frameId||t)&&(this.frameId=this.elem.globalData.frameId,this.iterateDynamicProperties(),this._mdf=this._mdf||t,this._mdf)){var e=0,r=this.dataProps.length;for("svg"===this.renderer&&(this.dashStr=""),e=0;e<r;e+=1)"o"!=this.dataProps[e].n?"svg"===this.renderer?this.dashStr+=" "+this.dataProps[e].p.v:this.dashArray[e]=this.dataProps[e].p.v:this.dashoffset[0]=this.dataProps[e].p.v}},extendPrototype([DynamicPropertyContainer],DashProperty),GradientProperty.prototype.comparePoints=function(t,e){for(var r=0,i=this.o.length/2;r<i;){if(.01<Math.abs(t[4*r]-t[4*e+2*r]))return!1;r+=1}return!0},GradientProperty.prototype.checkCollapsable=function(){if(this.o.length/2!=this.c.length/4)return!1;if(this.data.k.k[0].s)for(var t=0,e=this.data.k.k.length;t<e;){if(!this.comparePoints(this.data.k.k[t].s,this.data.p))return!1;t+=1}else if(!this.comparePoints(this.data.k.k,this.data.p))return!1;return!0},GradientProperty.prototype.getValue=function(t){if(this.prop.getValue(),this._mdf=!1,this._cmdf=!1,this._omdf=!1,this.prop._mdf||t){var e,r,i,s=4*this.data.p;for(e=0;e<s;e+=1)r=e%4==0?100:255,i=Math.round(this.prop.v[e]*r),this.c[e]!==i&&(this.c[e]=i,this._cmdf=!t);if(this.o.length)for(s=this.prop.v.length,e=4*this.data.p;e<s;e+=1)r=e%2==0?100:1,i=e%2==0?Math.round(100*this.prop.v[e]):this.prop.v[e],this.o[e-4*this.data.p]!==i&&(this.o[e-4*this.data.p]=i,this._omdf=!t);this._mdf=!t}},extendPrototype([DynamicPropertyContainer],GradientProperty);var buildShapeString=function(t,e,r,i){if(0===e)return"";var s,a=t.o,n=t.i,o=t.v,h=" M"+i.applyToPointStringified(o[0][0],o[0][1]);for(s=1;s<e;s+=1)h+=" C"+i.applyToPointStringified(a[s-1][0],a[s-1][1])+" "+i.applyToPointStringified(n[s][0],n[s][1])+" "+i.applyToPointStringified(o[s][0],o[s][1]);return r&&e&&(h+=" C"+i.applyToPointStringified(a[s-1][0],a[s-1][1])+" "+i.applyToPointStringified(n[0][0],n[0][1])+" "+i.applyToPointStringified(o[0][0],o[0][1]),h+="z"),h},ImagePreloader=function(){},featureSupport=(Iv={maskType:!0},(/MSIE 10/i.test(navigator.userAgent)||/MSIE 9/i.test(navigator.userAgent)||/rv:11.0/i.test(navigator.userAgent)||/Edge\/\d./i.test(navigator.userAgent))&&(Iv.maskType=!1),Iv),Iv,filtersFactory=(Jv={},Jv.createFilter=function(t){var e=createNS("filter");return e.setAttribute("id",t),e.setAttribute("filterUnits","objectBoundingBox"),e.setAttribute("x","0%"),e.setAttribute("y","0%"),e.setAttribute("width","100%"),e.setAttribute("height","100%"),e},Jv.createAlphaToLuminanceFilter=function(){var t=createNS("feColorMatrix");return t.setAttribute("type","matrix"),t.setAttribute("color-interpolation-filters","sRGB"),t.setAttribute("values","0 0 0 1 0  0 0 0 1 0  0 0 0 1 0  0 0 0 1 1"),t},Jv),Jv,assetLoader={load:function(t,e,r){var i,s=new XMLHttpRequest;s.open("GET",t,!0);try{s.responseType="json"}catch(t){}s.send(),s.onreadystatechange=function(){if(4==s.readyState)if(200==s.status)i=Pv(s),e(i);else try{i=Pv(s),e(i)}catch(t){r&&r(t)}}}};function Pv(t){return t.response&&"object"==typeof t.response?t.response:t.response&&"string"==typeof t.response?JSON.parse(t.response):t.responseText?JSON.parse(t.responseText):void 0}var assetLoader=null;function TextAnimatorProperty(t,e,r){this._isFirstFrame=!0,this._hasMaskedPath=!1,this._frameId=-1,this._textData=t,this._renderType=e,this._elem=r,this._animatorsData=createSizedArray(this._textData.a.length),this._pathData={},this._moreOptions={alignment:{}},this.renderedLetters=[],this.lettersChangedFlag=!1,this.initDynamicPropertyContainer(r)}function TextAnimatorDataProperty(t,e,r){var i={propType:!1},s=PropertyFactory.getProp,a=e.a;this.a={r:a.r?s(t,a.r,0,degToRads,r):i,rx:a.rx?s(t,a.rx,0,degToRads,r):i,ry:a.ry?s(t,a.ry,0,degToRads,r):i,sk:a.sk?s(t,a.sk,0,degToRads,r):i,sa:a.sa?s(t,a.sa,0,degToRads,r):i,s:a.s?s(t,a.s,1,.01,r):i,a:a.a?s(t,a.a,1,0,r):i,o:a.o?s(t,a.o,0,.01,r):i,p:a.p?s(t,a.p,1,0,r):i,sw:a.sw?s(t,a.sw,0,0,r):i,sc:a.sc?s(t,a.sc,1,0,r):i,fc:a.fc?s(t,a.fc,1,0,r):i,fh:a.fh?s(t,a.fh,0,0,r):i,fs:a.fs?s(t,a.fs,0,.01,r):i,fb:a.fb?s(t,a.fb,0,.01,r):i,t:a.t?s(t,a.t,0,0,r):i},this.s=TextSelectorProp.getTextSelectorProp(t,e.s,r),this.s.t=e.s.t}function LetterProps(t,e,r,i,s,a){this.o=t,this.sw=e,this.sc=r,this.fc=i,this.m=s,this.p=a,this._mdf={o:!0,sw:!!e,sc:!!r,fc:!!i,m:!0,p:!0}}function TextProperty(t,e){this._frameId=initialDefaultFrame,this.pv="",this.v="",this.kf=!1,this._isFirstFrame=!0,this._mdf=!1,this.data=e,this.elem=t,this.comp=this.elem.comp,this.keysIndex=0,this.canResize=!1,this.minimumFontSize=1,this.effectsSequence=[],this.currentData={ascent:0,boxWidth:this.defaultBoxWidth,f:"",fStyle:"",fWeight:"",fc:"",j:"",justifyOffset:"",l:[],lh:0,lineWidths:[],ls:"",of:"",s:"",sc:"",sw:0,t:0,tr:0,sz:0,ps:null,fillColorAnim:!1,strokeColorAnim:!1,strokeWidthAnim:!1,yOffset:0,finalSize:0,finalText:[],finalLineHeight:0,__complete:!1},this.copyData(this.currentData,this.data.d.k[0].s),this.searchProperty()||this.completeTextData(this.currentData)}TextAnimatorProperty.prototype.searchProperties=function(){var t,e,r=this._textData.a.length,i=PropertyFactory.getProp;for(t=0;t<r;t+=1)e=this._textData.a[t],this._animatorsData[t]=new TextAnimatorDataProperty(this._elem,e,this);this._textData.p&&"m"in this._textData.p?(this._pathData={f:i(this._elem,this._textData.p.f,0,0,this),l:i(this._elem,this._textData.p.l,0,0,this),r:this._textData.p.r,m:this._elem.maskManager.getMaskProperty(this._textData.p.m)},this._hasMaskedPath=!0):this._hasMaskedPath=!1,this._moreOptions.alignment=i(this._elem,this._textData.m.a,1,0,this)},TextAnimatorProperty.prototype.getMeasures=function(t,e){if(this.lettersChangedFlag=e,this._mdf||this._isFirstFrame||e||this._hasMaskedPath&&this._pathData.m._mdf){this._isFirstFrame=!1;var r,i,s,a,n,o,h,p,l,m,f,c,d,u,y,g,v,P,b,x=this._moreOptions.alignment.v,_=this._animatorsData,S=this._textData,T=this.mHelper,A=this._renderType,C=this.renderedLetters.length,E=(this.data,t.l);if(this._hasMaskedPath){if(b=this._pathData.m,!this._pathData.n||this._pathData._mdf){var k,D=b.v;for(this._pathData.r&&(D=D.reverse()),n={tLength:0,segments:[]},a=D._length-1,s=g=0;s<a;s+=1)k=bez.buildBezierData(D.v[s],D.v[s+1],[D.o[s][0]-D.v[s][0],D.o[s][1]-D.v[s][1]],[D.i[s+1][0]-D.v[s+1][0],D.i[s+1][1]-D.v[s+1][1]]),n.tLength+=k.segmentLength,n.segments.push(k),g+=k.segmentLength;s=a,b.v.c&&(k=bez.buildBezierData(D.v[s],D.v[0],[D.o[s][0]-D.v[s][0],D.o[s][1]-D.v[s][1]],[D.i[0][0]-D.v[0][0],D.i[0][1]-D.v[0][1]]),n.tLength+=k.segmentLength,n.segments.push(k),g+=k.segmentLength),this._pathData.pi=n}if(n=this._pathData.pi,o=this._pathData.f.v,m=1,l=!(p=f=0),u=n.segments,o<0&&b.v.c)for(n.tLength<Math.abs(o)&&(o=-Math.abs(o)%n.tLength),m=(d=u[f=u.length-1].points).length-1;o<0;)o+=d[m].partialLength,(m-=1)<0&&(m=(d=u[f-=1].points).length-1);c=(d=u[f].points)[m-1],y=(h=d[m]).partialLength}a=E.length,i=r=0;var M,I,w,F,V=1.2*t.finalSize*.714,R=!0;w=_.length;var L,z,O,B,N,G,j,J,K,q,H,W,X,Y=-1,Q=o,$=f,U=m,Z=-1,tt="",et=this.defaultPropsArray;if(2===t.j||1===t.j){var rt=0,it=0,st=2===t.j?-.5:-1,at=0,nt=!0;for(s=0;s<a;s+=1)if(E[s].n){for(rt&&(rt+=it);at<s;)E[at].animatorJustifyOffset=rt,at+=1;nt=!(rt=0)}else{for(I=0;I<w;I+=1)(M=_[I].a).t.propType&&(nt&&2===t.j&&(it+=M.t.v*st),(L=_[I].s.getMult(E[s].anIndexes[I],S.a[I].s.totalChars)).length?rt+=M.t.v*L[0]*st:rt+=M.t.v*L*st);nt=!1}for(rt&&(rt+=it);at<s;)E[at].animatorJustifyOffset=rt,at+=1}for(s=0;s<a;s+=1){if(T.reset(),N=1,E[s].n)r=0,i+=t.yOffset,i+=R?1:0,o=Q,R=!1,0,this._hasMaskedPath&&(m=U,c=(d=u[f=$].points)[m-1],y=(h=d[m]).partialLength,p=0),X=q=W=tt="",et=this.defaultPropsArray;else{if(this._hasMaskedPath){if(Z!==E[s].line){switch(t.j){case 1:o+=g-t.lineWidths[E[s].line];break;case 2:o+=(g-t.lineWidths[E[s].line])/2}Z=E[s].line}Y!==E[s].ind&&(E[Y]&&(o+=E[Y].extra),o+=E[s].an/2,Y=E[s].ind),o+=x[0]*E[s].an/200;var ot=0;for(I=0;I<w;I+=1)(M=_[I].a).p.propType&&((L=_[I].s.getMult(E[s].anIndexes[I],S.a[I].s.totalChars)).length?ot+=M.p.v[0]*L[0]:ot+=M.p.v[0]*L),M.a.propType&&((L=_[I].s.getMult(E[s].anIndexes[I],S.a[I].s.totalChars)).length?ot+=M.a.v[0]*L[0]:ot+=M.a.v[0]*L);for(l=!0;l;)o+ot<=p+y||!d?(v=(o+ot-p)/h.partialLength,O=c.point[0]+(h.point[0]-c.point[0])*v,B=c.point[1]+(h.point[1]-c.point[1])*v,T.translate(-x[0]*E[s].an/200,-x[1]*V/100),l=!1):d&&(p+=h.partialLength,(m+=1)>=d.length&&(m=0,d=u[f+=1]?u[f].points:b.v.c?u[f=m=0].points:(p-=h.partialLength,null)),d&&(c=h,y=(h=d[m]).partialLength));z=E[s].an/2-E[s].add,T.translate(-z,0,0)}else z=E[s].an/2-E[s].add,T.translate(-z,0,0),T.translate(-x[0]*E[s].an/200,-x[1]*V/100,0);for(E[s].l/2,I=0;I<w;I+=1)(M=_[I].a).t.propType&&(L=_[I].s.getMult(E[s].anIndexes[I],S.a[I].s.totalChars),0===r&&0===t.j||(this._hasMaskedPath?L.length?o+=M.t.v*L[0]:o+=M.t.v*L:L.length?r+=M.t.v*L[0]:r+=M.t.v*L));for(E[s].l/2,t.strokeWidthAnim&&(j=t.sw||0),t.strokeColorAnim&&(G=t.sc?[t.sc[0],t.sc[1],t.sc[2]]:[0,0,0]),t.fillColorAnim&&t.fc&&(J=[t.fc[0],t.fc[1],t.fc[2]]),I=0;I<w;I+=1)(M=_[I].a).a.propType&&((L=_[I].s.getMult(E[s].anIndexes[I],S.a[I].s.totalChars)).length?T.translate(-M.a.v[0]*L[0],-M.a.v[1]*L[1],M.a.v[2]*L[2]):T.translate(-M.a.v[0]*L,-M.a.v[1]*L,M.a.v[2]*L));for(I=0;I<w;I+=1)(M=_[I].a).s.propType&&((L=_[I].s.getMult(E[s].anIndexes[I],S.a[I].s.totalChars)).length?T.scale(1+(M.s.v[0]-1)*L[0],1+(M.s.v[1]-1)*L[1],1):T.scale(1+(M.s.v[0]-1)*L,1+(M.s.v[1]-1)*L,1));for(I=0;I<w;I+=1){if(M=_[I].a,L=_[I].s.getMult(E[s].anIndexes[I],S.a[I].s.totalChars),M.sk.propType&&(L.length?T.skewFromAxis(-M.sk.v*L[0],M.sa.v*L[1]):T.skewFromAxis(-M.sk.v*L,M.sa.v*L)),M.r.propType&&(L.length?T.rotateZ(-M.r.v*L[2]):T.rotateZ(-M.r.v*L)),M.ry.propType&&(L.length?T.rotateY(M.ry.v*L[1]):T.rotateY(M.ry.v*L)),M.rx.propType&&(L.length?T.rotateX(M.rx.v*L[0]):T.rotateX(M.rx.v*L)),M.o.propType&&(L.length?N+=(M.o.v*L[0]-N)*L[0]:N+=(M.o.v*L-N)*L),t.strokeWidthAnim&&M.sw.propType&&(L.length?j+=M.sw.v*L[0]:j+=M.sw.v*L),t.strokeColorAnim&&M.sc.propType)for(K=0;K<3;K+=1)L.length?G[K]=G[K]+(M.sc.v[K]-G[K])*L[0]:G[K]=G[K]+(M.sc.v[K]-G[K])*L;if(t.fillColorAnim&&t.fc){if(M.fc.propType)for(K=0;K<3;K+=1)L.length?J[K]=J[K]+(M.fc.v[K]-J[K])*L[0]:J[K]=J[K]+(M.fc.v[K]-J[K])*L;M.fh.propType&&(J=L.length?addHueToRGB(J,M.fh.v*L[0]):addHueToRGB(J,M.fh.v*L)),M.fs.propType&&(J=L.length?addSaturationToRGB(J,M.fs.v*L[0]):addSaturationToRGB(J,M.fs.v*L)),M.fb.propType&&(J=L.length?addBrightnessToRGB(J,M.fb.v*L[0]):addBrightnessToRGB(J,M.fb.v*L))}}for(I=0;I<w;I+=1)(M=_[I].a).p.propType&&(L=_[I].s.getMult(E[s].anIndexes[I],S.a[I].s.totalChars),this._hasMaskedPath?L.length?T.translate(0,M.p.v[1]*L[0],-M.p.v[2]*L[1]):T.translate(0,M.p.v[1]*L,-M.p.v[2]*L):L.length?T.translate(M.p.v[0]*L[0],M.p.v[1]*L[1],-M.p.v[2]*L[2]):T.translate(M.p.v[0]*L,M.p.v[1]*L,-M.p.v[2]*L));if(t.strokeWidthAnim&&(q=j<0?0:j),t.strokeColorAnim&&(H="rgb("+Math.round(255*G[0])+","+Math.round(255*G[1])+","+Math.round(255*G[2])+")"),t.fillColorAnim&&t.fc&&(W="rgb("+Math.round(255*J[0])+","+Math.round(255*J[1])+","+Math.round(255*J[2])+")"),this._hasMaskedPath){if(T.translate(0,-t.ls),T.translate(0,x[1]*V/100+i,0),S.p.p){P=(h.point[1]-c.point[1])/(h.point[0]-c.point[0]);var ht=180*Math.atan(P)/Math.PI;h.point[0]<c.point[0]&&(ht+=180),T.rotate(-ht*Math.PI/180)}T.translate(O,B,0),o-=x[0]*E[s].an/200,E[s+1]&&Y!==E[s+1].ind&&(o+=E[s].an/2,o+=t.tr/1e3*t.finalSize)}else{switch(T.translate(r,i,0),t.ps&&T.translate(t.ps[0],t.ps[1]+t.ascent,0),t.j){case 1:T.translate(E[s].animatorJustifyOffset+t.justifyOffset+(t.boxWidth-t.lineWidths[E[s].line]),0,0);break;case 2:T.translate(E[s].animatorJustifyOffset+t.justifyOffset+(t.boxWidth-t.lineWidths[E[s].line])/2,0,0)}T.translate(0,-t.ls),T.translate(z,0,0),T.translate(x[0]*E[s].an/200,x[1]*V/100,0),r+=E[s].l+t.tr/1e3*t.finalSize}"html"===A?tt=T.toCSS():"svg"===A?tt=T.to2dCSS():et=[T.props[0],T.props[1],T.props[2],T.props[3],T.props[4],T.props[5],T.props[6],T.props[7],T.props[8],T.props[9],T.props[10],T.props[11],T.props[12],T.props[13],T.props[14],T.props[15]],X=N}C<=s?(F=new LetterProps(X,q,H,W,tt,et),this.renderedLetters.push(F),C+=1,this.lettersChangedFlag=!0):(F=this.renderedLetters[s],this.lettersChangedFlag=F.update(X,q,H,W,tt,et)||this.lettersChangedFlag)}}},TextAnimatorProperty.prototype.getValue=function(){this._elem.globalData.frameId!==this._frameId&&(this._frameId=this._elem.globalData.frameId,this.iterateDynamicProperties())},TextAnimatorProperty.prototype.mHelper=new Matrix,TextAnimatorProperty.prototype.defaultPropsArray=[],extendPrototype([DynamicPropertyContainer],TextAnimatorProperty),LetterProps.prototype.update=function(t,e,r,i,s,a){this._mdf.o=!1,this._mdf.sw=!1,this._mdf.sc=!1,this._mdf.fc=!1,this._mdf.m=!1;var n=this._mdf.p=!1;return this.o!==t&&(this.o=t,n=this._mdf.o=!0),this.sw!==e&&(this.sw=e,n=this._mdf.sw=!0),this.sc!==r&&(this.sc=r,n=this._mdf.sc=!0),this.fc!==i&&(this.fc=i,n=this._mdf.fc=!0),this.m!==s&&(this.m=s,n=this._mdf.m=!0),!a.length||this.p[0]===a[0]&&this.p[1]===a[1]&&this.p[4]===a[4]&&this.p[5]===a[5]&&this.p[12]===a[12]&&this.p[13]===a[13]||(this.p=a,n=this._mdf.p=!0),n},TextProperty.prototype.defaultBoxWidth=[0,0],TextProperty.prototype.copyData=function(t,e){for(var r in e)e.hasOwnProperty(r)&&(t[r]=e[r]);return t},TextProperty.prototype.setCurrentData=function(t){t.__complete||this.completeTextData(t),this.currentData=t,this.currentData.boxWidth=this.currentData.boxWidth||this.defaultBoxWidth,this._mdf=!0},TextProperty.prototype.searchProperty=function(){return this.searchKeyframes()},TextProperty.prototype.searchKeyframes=function(){return this.kf=1<this.data.d.k.length,this.kf&&this.addEffect(this.getKeyframeValue.bind(this)),this.kf},TextProperty.prototype.addEffect=function(t){this.effectsSequence.push(t),this.elem.addDynamicProperty(this)},TextProperty.prototype.getValue=function(t){if(this.elem.globalData.frameId!==this.frameId&&this.effectsSequence.length||t){this.currentData.t=this.data.d.k[this.keysIndex].s.t;var e=this.currentData,r=this.keysIndex;if(this.lock)this.setCurrentData(this.currentData);else{this.lock=!0,this._mdf=!1;var i,s=this.effectsSequence.length,a=t||this.data.d.k[this.keysIndex].s;for(i=0;i<s;i+=1)a=r!==this.keysIndex?this.effectsSequence[i](a,a.t):this.effectsSequence[i](this.currentData,a.t);e!==a&&this.setCurrentData(a),this.pv=this.v=this.currentData,this.lock=!1,this.frameId=this.elem.globalData.frameId}}},TextProperty.prototype.getKeyframeValue=function(){for(var t=this.data.d.k,e=this.elem.comp.renderedFrame,r=0,i=t.length;r<=i-1&&(t[r].s,!(r===i-1||t[r+1].t>e));)r+=1;return this.keysIndex!==r&&(this.keysIndex=r),this.data.d.k[this.keysIndex].s},TextProperty.prototype.buildFinalText=function(t){for(var e=FontManager.getCombinedCharacterCodes(),r=[],i=0,s=t.length;i<s;)-1!==e.indexOf(t.charCodeAt(i))?r[r.length-1]+=t.charAt(i):r.push(t.charAt(i)),i+=1;return r},TextProperty.prototype.completeTextData=function(t){t.__complete=!0;var e,r,i,s,a,n,o,h=this.elem.globalData.fontManager,p=this.data,l=[],m=0,f=p.m.g,c=0,d=0,u=0,y=[],g=0,v=0,P=h.getFontByName(t.f),b=0,x=P.fStyle?P.fStyle.split(" "):[],_="normal",S="normal";for(r=x.length,e=0;e<r;e+=1)switch(x[e].toLowerCase()){case"italic":S="italic";break;case"bold":_="700";break;case"black":_="900";break;case"medium":_="500";break;case"regular":case"normal":_="400";break;case"light":case"thin":_="200"}t.fWeight=P.fWeight||_,t.fStyle=S,r=t.t.length,t.finalSize=t.s,t.finalText=this.buildFinalText(t.t),t.finalLineHeight=t.lh;var T,A=t.tr/1e3*t.finalSize;if(t.sz)for(var C,E,k=!0,D=t.sz[0],M=t.sz[1];k;){g=C=0,r=(E=this.buildFinalText(t.t)).length,A=t.tr/1e3*t.finalSize;var I=-1;for(e=0;e<r;e+=1)T=E[e].charCodeAt(0),i=!1," "===E[e]?I=e:13!==T&&3!==T||(i=!(g=0),C+=t.finalLineHeight||1.2*t.finalSize),D<g+(b=h.chars?(o=h.getCharData(E[e],P.fStyle,P.fFamily),i?0:o.w*t.finalSize/100):h.measureText(E[e],t.f,t.finalSize))&&" "!==E[e]?(-1===I?r+=1:e=I,C+=t.finalLineHeight||1.2*t.finalSize,E.splice(e,I===e?1:0,"\r"),I=-1,g=0):(g+=b,g+=A);C+=P.ascent*t.finalSize/100,this.canResize&&t.finalSize>this.minimumFontSize&&M<C?(t.finalSize-=1,t.finalLineHeight=t.finalSize*t.lh/t.s):(t.finalText=E,r=t.finalText.length,k=!1)}g=-A;var w,F=b=0;for(e=0;e<r;e+=1)if(i=!1,T=(w=t.finalText[e]).charCodeAt(0)," "===w?s="\xa0":13===T||3===T?(F=0,y.push(g),v=v<g?g:v,g=-2*A,i=!(s=""),u+=1):s=t.finalText[e],b=h.chars?(o=h.getCharData(w,P.fStyle,h.getFontByName(t.f).fFamily),i?0:o.w*t.finalSize/100):h.measureText(s,t.f,t.finalSize)," "===w?F+=b+A:(g+=b+A+F,F=0),l.push({l:b,an:b,add:c,n:i,anIndexes:[],val:s,line:u,animatorJustifyOffset:0}),2==f){if(c+=b,""===s||"\xa0"===s||e===r-1){for(""!==s&&"\xa0"!==s||(c-=b);d<=e;)l[d].an=c,l[d].ind=m,l[d].extra=b,d+=1;m+=1,c=0}}else if(3==f){if(c+=b,""===s||e===r-1){for(""===s&&(c-=b);d<=e;)l[d].an=c,l[d].ind=m,l[d].extra=b,d+=1;c=0,m+=1}}else l[m].ind=m,l[m].extra=0,m+=1;if(t.l=l,v=v<g?g:v,y.push(g),t.sz)t.boxWidth=t.sz[0],t.justifyOffset=0;else switch(t.boxWidth=v,t.j){case 1:t.justifyOffset=-t.boxWidth;break;case 2:t.justifyOffset=-t.boxWidth/2;break;default:t.justifyOffset=0}t.lineWidths=y;var V,R,L=p.a;n=L.length;var z,O,B=[];for(a=0;a<n;a+=1){for((V=L[a]).a.sc&&(t.strokeColorAnim=!0),V.a.sw&&(t.strokeWidthAnim=!0),(V.a.fc||V.a.fh||V.a.fs||V.a.fb)&&(t.fillColorAnim=!0),O=0,z=V.s.b,e=0;e<r;e+=1)(R=l[e]).anIndexes[a]=O,(1==z&&""!==R.val||2==z&&""!==R.val&&"\xa0"!==R.val||3==z&&(R.n||"\xa0"==R.val||e==r-1)||4==z&&(R.n||e==r-1))&&(1===V.s.rn&&B.push(O),O+=1);p.a[a].s.totalChars=O;var N,G=-1;if(1===V.s.rn)for(e=0;e<r;e+=1)G!=(R=l[e]).anIndexes[a]&&(G=R.anIndexes[a],N=B.splice(Math.floor(Math.random()*B.length),1)[0]),R.anIndexes[a]=N}t.yOffset=t.finalLineHeight||1.2*t.finalSize,t.ls=t.ls||0,t.ascent=P.ascent*t.finalSize/100},TextProperty.prototype.updateDocumentData=function(t,e){e=void 0===e?this.keysIndex:e;var r=this.copyData({},this.data.d.k[e].s);r=this.copyData(r,t),this.data.d.k[e].s=r,this.recalculate(e),this.elem.addDynamicProperty(this)},TextProperty.prototype.recalculate=function(t){var e=this.data.d.k[t].s;e.__complete=!1,this.keysIndex=0,this._isFirstFrame=!0,this.getValue(e)},TextProperty.prototype.canResizeFont=function(t){this.canResize=t,this.recalculate(this.keysIndex),this.elem.addDynamicProperty(this)},TextProperty.prototype.setMinimumFontSize=function(t){this.minimumFontSize=Math.floor(t)||1,this.recalculate(this.keysIndex),this.elem.addDynamicProperty(this)};var TextSelectorProp=(cz=Math.max,dz=Math.min,ez=Math.floor,fz.prototype={getMult:function(t){this._currentTextLength!==this.elem.textProperty.currentData.l.length&&this.getValue();var e=BezierFactory.getBezierEasing(this.ne.v/100,0,1-this.xe.v/100,1).get,r=0,i=this.finalS,s=this.finalE,a=this.data.sh;if(2==a)r=e(r=s===i?s<=t?1:0:cz(0,dz(.5/(s-i)+(t-i)/(s-i),1)));else if(3==a)r=e(r=s===i?s<=t?0:1:1-cz(0,dz(.5/(s-i)+(t-i)/(s-i),1)));else if(4==a)s===i?r=0:(r=cz(0,dz(.5/(s-i)+(t-i)/(s-i),1)))<.5?r*=2:r=1-2*(r-.5),r=e(r);else if(5==a){if(s===i)r=0;else{var n=s-i,o=-n/2+(t=dz(cz(0,t+.5-i),s-i)),h=n/2;r=Math.sqrt(1-o*o/(h*h))}r=e(r)}else r=6==a?e(r=s===i?0:(t=dz(cz(0,t+.5-i),s-i),(1+Math.cos(Math.PI+2*Math.PI*t/(s-i)))/2)):(t>=ez(i)&&(r=t-i<0?1-(i-t):cz(0,dz(s-t,1))),e(r));return r*this.a.v},getValue:function(t){this.iterateDynamicProperties(),this._mdf=t||this._mdf,this._currentTextLength=this.elem.textProperty.currentData.l.length||0,t&&2===this.data.r&&(this.e.v=this._currentTextLength);var e=2===this.data.r?1:100/this.data.totalChars,r=this.o.v/e,i=this.s.v/e+r,s=this.e.v/e+r;if(s<i){var a=i;i=s,s=a}this.finalS=i,this.finalE=s}},extendPrototype([DynamicPropertyContainer],fz),{getTextSelectorProp:function(t,e,r){return new fz(t,e,r)}}),cz,dz,ez;function fz(t,e){this._currentTextLength=-1,this.k=!1,this.data=e,this.elem=t,this.comp=t.comp,this.finalS=0,this.finalE=0,this.initDynamicPropertyContainer(t),this.s=PropertyFactory.getProp(t,e.s||{k:0},0,0,this),this.e="e"in e?PropertyFactory.getProp(t,e.e,0,0,this):{v:100},this.o=PropertyFactory.getProp(t,e.o||{k:0},0,0,this),this.xe=PropertyFactory.getProp(t,e.xe||{k:0},0,0,this),this.ne=PropertyFactory.getProp(t,e.ne||{k:0},0,0,this),this.a=PropertyFactory.getProp(t,e.a,0,.01,this),this.dynamicProperties.length||this.getValue()}var pool_factory=function(t,e,r,i){var s=0,a=t,n=createSizedArray(a);function o(){return s?n[s-=1]:e()}return{newElement:o,release:function(t){s===a&&(n=pooling.double(n),a*=2),r&&r(t),n[s]=t,s+=1}}},pooling={double:function(t){return t.concat(createSizedArray(t.length))}},point_pool=pool_factory(8,function(){return createTypedArray("float32",2)}),shape_pool=(Vz=pool_factory(4,function(){return new ShapePath},function(t){var e,r=t._length;for(e=0;e<r;e+=1)point_pool.release(t.v[e]),point_pool.release(t.i[e]),point_pool.release(t.o[e]),t.v[e]=null,t.i[e]=null,t.o[e]=null;t._length=0,t.c=!1}),Vz.clone=function(t){var e,r=Vz.newElement(),i=void 0===t._length?t.v.length:t._length;for(r.setLength(i),r.c=t.c,e=0;e<i;e+=1)r.setTripleAt(t.v[e][0],t.v[e][1],t.o[e][0],t.o[e][1],t.i[e][0],t.i[e][1],e);return r},Vz),Vz,shapeCollection_pool=(cA={newShapeCollection:function(){var t;t=dA?fA[dA-=1]:new ShapeCollection;return t},release:function(t){var e,r=t._length;for(e=0;e<r;e+=1)shape_pool.release(t.shapes[e]);t._length=0,dA===eA&&(fA=pooling.double(fA),eA*=2);fA[dA]=t,dA+=1}},dA=0,eA=4,fA=createSizedArray(eA),cA),cA,dA,eA,fA,segments_length_pool=pool_factory(8,function(){return{lengths:[],totalLength:0}},function(t){var e,r=t.lengths.length;for(e=0;e<r;e+=1)bezier_length_pool.release(t.lengths[e]);t.lengths.length=0}),bezier_length_pool=pool_factory(8,function(){return{addedLength:0,percents:createTypedArray("float32",defaultCurveSegments),lengths:createTypedArray("float32",defaultCurveSegments)}});function BaseRenderer(){}function SVGRenderer(t,e){this.animationItem=t,this.layers=null,this.renderedFrame=-1,this.svgElement=createNS("svg");var r="";if(e&&e.title){var i=createNS("title"),s=createElementID();i.setAttribute("id",s),i.textContent=e.title,this.svgElement.appendChild(i),r+=s}if(e&&e.description){var a=createNS("desc"),n=createElementID();a.setAttribute("id",n),a.textContent=e.description,this.svgElement.appendChild(a),r+=" "+n}r&&this.svgElement.setAttribute("aria-labelledby",r);var o=createNS("defs");this.svgElement.appendChild(o);var h=createNS("g");this.svgElement.appendChild(h),this.layerElement=h,this.renderConfig={preserveAspectRatio:e&&e.preserveAspectRatio||"xMidYMid meet",imagePreserveAspectRatio:e&&e.imagePreserveAspectRatio||"xMidYMid slice",progressiveLoad:e&&e.progressiveLoad||!1,hideOnTransparent:!e||!1!==e.hideOnTransparent,viewBoxOnly:e&&e.viewBoxOnly||!1,viewBoxSize:e&&e.viewBoxSize||!1,className:e&&e.className||""},this.globalData={_mdf:!1,frameNum:-1,defs:o,renderConfig:this.renderConfig},this.elements=[],this.pendingElements=[],this.destroyed=!1,this.rendererType="svg"}function CanvasRenderer(t,e){this.animationItem=t,this.renderConfig={clearCanvas:!e||void 0===e.clearCanvas||e.clearCanvas,context:e&&e.context||null,progressiveLoad:e&&e.progressiveLoad||!1,preserveAspectRatio:e&&e.preserveAspectRatio||"xMidYMid meet",imagePreserveAspectRatio:e&&e.imagePreserveAspectRatio||"xMidYMid slice",className:e&&e.className||""},this.renderConfig.dpr=e&&e.dpr||1,this.animationItem.wrapper&&(this.renderConfig.dpr=e&&e.dpr||window.devicePixelRatio||1),this.renderedFrame=-1,this.globalData={frameNum:-1,_mdf:!1,renderConfig:this.renderConfig,currentGlobalAlpha:-1},this.contextData=new CVContextData,this.elements=[],this.pendingElements=[],this.transformMat=new Matrix,this.completeLayers=!1,this.rendererType="canvas"}function MaskElement(t,e,r){this.data=t,this.element=e,this.globalData=r,this.storedData=[],this.masksProperties=this.data.masksProperties||[],this.maskElement=null;var i,s=this.globalData.defs,a=this.masksProperties?this.masksProperties.length:0;this.viewData=createSizedArray(a),this.solidPath="";var n,o,h,p,l,m,f,c=this.masksProperties,d=0,u=[],y=createElementID(),g="clipPath",v="clip-path";for(i=0;i<a;i++)if(("a"!==c[i].mode&&"n"!==c[i].mode||c[i].inv||100!==c[i].o.k)&&(v=g="mask"),"s"!=c[i].mode&&"i"!=c[i].mode||0!==d?p=null:((p=createNS("rect")).setAttribute("fill","#ffffff"),p.setAttribute("width",this.element.comp.data.w||0),p.setAttribute("height",this.element.comp.data.h||0),u.push(p)),n=createNS("path"),"n"!=c[i].mode){var P;if(d+=1,n.setAttribute("fill","s"===c[i].mode?"#000000":"#ffffff"),n.setAttribute("clip-rule","nonzero"),0!==c[i].x.k?(v=g="mask",f=PropertyFactory.getProp(this.element,c[i].x,0,null,this.element),P=createElementID(),(l=createNS("filter")).setAttribute("id",P),(m=createNS("feMorphology")).setAttribute("operator","erode"),m.setAttribute("in","SourceGraphic"),m.setAttribute("radius","0"),l.appendChild(m),s.appendChild(l),n.setAttribute("stroke","s"===c[i].mode?"#000000":"#ffffff")):f=m=null,this.storedData[i]={elem:n,x:f,expan:m,lastPath:"",lastOperator:"",filterId:P,lastRadius:0},"i"==c[i].mode){h=u.length;var b=createNS("g");for(o=0;o<h;o+=1)b.appendChild(u[o]);var x=createNS("mask");x.setAttribute("mask-type","alpha"),x.setAttribute("id",y+"_"+d),x.appendChild(n),s.appendChild(x),b.setAttribute("mask","url("+locationHref+"#"+y+"_"+d+")"),u.length=0,u.push(b)}else u.push(n);c[i].inv&&!this.solidPath&&(this.solidPath=this.createLayerSolidPath()),this.viewData[i]={elem:n,lastPath:"",op:PropertyFactory.getProp(this.element,c[i].o,0,.01,this.element),prop:ShapePropertyFactory.getShapeProp(this.element,c[i],3),invRect:p},this.viewData[i].prop.k||this.drawPath(c[i],this.viewData[i].prop.v,this.viewData[i])}else this.viewData[i]={op:PropertyFactory.getProp(this.element,c[i].o,0,.01,this.element),prop:ShapePropertyFactory.getShapeProp(this.element,c[i],3),elem:n,lastPath:""},s.appendChild(n);for(this.maskElement=createNS(g),a=u.length,i=0;i<a;i+=1)this.maskElement.appendChild(u[i]);0<d&&(this.maskElement.setAttribute("id",y),this.element.maskedElement.setAttribute(v,"url("+locationHref+"#"+y+")"),s.appendChild(this.maskElement)),this.viewData.length&&this.element.addRenderableComponent(this)}function HierarchyElement(){}function FrameElement(){}function TransformElement(){}function RenderableElement(){}function RenderableDOMElement(){}function ProcessedElement(t,e){this.elem=t,this.pos=e}function SVGShapeData(t,e,r){this.caches=[],this.styles=[],this.transformers=t,this.lStr="",this.sh=r,this.lvl=e,this._isAnimated=!!r.k;for(var i=0,s=t.length;i<s;){if(t[i].mProps.dynamicProperties.length){this._isAnimated=!0;break}i+=1}}function ShapeGroupData(){this.it=[],this.prevViewData=[],this.gr=createNS("g")}function ShapeTransformManager(){this.sequences={},this.sequenceList=[],this.transform_key_count=0}function CVShapeData(t,e,r,i){this.styledShapes=[],this.tr=[0,0,0,0,0,0];var s=4;"rc"==e.ty?s=5:"el"==e.ty?s=6:"sr"==e.ty&&(s=7),this.sh=ShapePropertyFactory.getShapeProp(t,e,s,t);var a,n,o=r.length;for(a=0;a<o;a+=1)r[a].closed||(n={transforms:i.addTransformSequence(r[a].transforms),trNodes:[]},this.styledShapes.push(n),r[a].elements.push(n))}function BaseElement(){}function NullElement(t,e,r){this.initFrame(),this.initBaseData(t,e,r),this.initFrame(),this.initTransform(t,e,r),this.initHierarchy()}function SVGBaseElement(){}function IShapeElement(){}function ITextElement(){}function ICompElement(){}function IImageElement(t,e,r){this.assetData=e.getAssetData(t.refId),this.initElement(t,e,r),this.sourceRect={top:0,left:0,width:this.assetData.w,height:this.assetData.h}}function ISolidElement(t,e,r){this.initElement(t,e,r)}function SVGShapeElement(t,e,r){this.shapes=[],this.shapesData=t.shapes,this.stylesList=[],this.shapeModifiers=[],this.itemsData=[],this.processedElements=[],this.animatedContents=[],this.initElement(t,e,r),this.prevViewData=[]}function CVContextData(){this.saved=[],this.cArrPos=0,this.cTr=new Matrix,this.cO=1;var t;for(this.savedOp=createTypedArray("float32",15),t=0;t<15;t+=1)this.saved[t]=createTypedArray("float32",16);this._length=15}function CVBaseElement(){}function CVCompElement(t,e,r){this.completeLayers=!1,this.layers=t.layers,this.pendingElements=[],this.elements=createSizedArray(this.layers.length),this.initElement(t,e,r),this.tm=t.tm?PropertyFactory.getProp(this,t.tm,0,e.frameRate,this):{_placeholder:!0}}function CVMaskElement(t,e){this.data=t,this.element=e,this.masksProperties=this.data.masksProperties||[],this.viewData=createSizedArray(this.masksProperties.length);var r,i=this.masksProperties.length,s=!1;for(r=0;r<i;r++)"n"!==this.masksProperties[r].mode&&(s=!0),this.viewData[r]=ShapePropertyFactory.getShapeProp(this.element,this.masksProperties[r],3);(this.hasMasks=s)&&this.element.addRenderableComponent(this)}function CVShapeElement(t,e,r){this.shapes=[],this.shapesData=t.shapes,this.stylesList=[],this.itemsData=[],this.prevViewData=[],this.shapeModifiers=[],this.processedElements=[],this.transformsManager=new ShapeTransformManager,this.initElement(t,e,r)}function CVSolidElement(t,e,r){this.initElement(t,e,r)}function CVEffects(){}BaseRenderer.prototype.checkLayers=function(t){var e,r,i=this.layers.length;for(this.completeLayers=!0,e=i-1;0<=e;e--)this.elements[e]||(r=this.layers[e]).ip-r.st<=t-this.layers[e].st&&r.op-r.st>t-this.layers[e].st&&this.buildItem(e),this.completeLayers=!!this.elements[e]&&this.completeLayers;this.checkPendingElements()},BaseRenderer.prototype.createItem=function(t){switch(t.ty){case 2:return this.createImage(t);case 0:return this.createComp(t);case 1:return this.createSolid(t);case 3:return this.createNull(t);case 4:return this.createShape(t);case 5:return this.createText(t);case 13:return this.createCamera(t)}return this.createNull(t)},BaseRenderer.prototype.createCamera=function(){throw new Error("You're using a 3d camera. Try the html renderer.")},BaseRenderer.prototype.buildAllItems=function(){var t,e=this.layers.length;for(t=0;t<e;t+=1)this.buildItem(t);this.checkPendingElements()},BaseRenderer.prototype.includeLayers=function(t){this.completeLayers=!1;var e,r,i=t.length,s=this.layers.length;for(e=0;e<i;e+=1)for(r=0;r<s;){if(this.layers[r].id==t[e].id){this.layers[r]=t[e];break}r+=1}},BaseRenderer.prototype.setProjectInterface=function(t){this.globalData.projectInterface=t},BaseRenderer.prototype.initItems=function(){this.globalData.progressiveLoad||this.buildAllItems()},BaseRenderer.prototype.buildElementParenting=function(t,e,r){for(var i=this.elements,s=this.layers,a=0,n=s.length;a<n;)s[a].ind==e&&(i[a]&&!0!==i[a]?(r.push(i[a]),i[a].setAsParent(),void 0!==s[a].parent?this.buildElementParenting(t,s[a].parent,r):t.setHierarchy(r)):(this.buildItem(a),this.addPendingElement(t))),a+=1},BaseRenderer.prototype.addPendingElement=function(t){this.pendingElements.push(t)},BaseRenderer.prototype.searchExtraCompositions=function(t){var e,r=t.length;for(e=0;e<r;e+=1)if(t[e].xt){var i=this.createComp(t[e]);i.initExpressions(),this.globalData.projectInterface.registerComposition(i)}},BaseRenderer.prototype.setupGlobalData=function(t,e){this.globalData.fontManager=new FontManager,this.globalData.fontManager.addChars(t.chars),this.globalData.fontManager.addFonts(t.fonts,e),this.globalData.getAssetData=this.animationItem.getAssetData.bind(this.animationItem),this.globalData.getAssetsPath=this.animationItem.getAssetsPath.bind(this.animationItem),this.globalData.imageLoader=this.animationItem.imagePreloader,this.globalData.frameId=0,this.globalData.frameRate=t.fr,this.globalData.nm=t.nm,this.globalData.compSize={w:t.w,h:t.h}},extendPrototype([BaseRenderer],SVGRenderer),SVGRenderer.prototype.createNull=function(t){return new NullElement(t,this.globalData,this)},SVGRenderer.prototype.createShape=function(t){return new SVGShapeElement(t,this.globalData,this)},SVGRenderer.prototype.createText=function(t){return new SVGTextElement(t,this.globalData,this)},SVGRenderer.prototype.createImage=function(t){return new IImageElement(t,this.globalData,this)},SVGRenderer.prototype.createComp=function(t){return new SVGCompElement(t,this.globalData,this)},SVGRenderer.prototype.createSolid=function(t){return new ISolidElement(t,this.globalData,this)},SVGRenderer.prototype.configAnimation=function(t){this.svgElement.setAttribute("xmlns","http://www.w3.org/2000/svg"),this.renderConfig.viewBoxSize?this.svgElement.setAttribute("viewBox",this.renderConfig.viewBoxSize):this.svgElement.setAttribute("viewBox","0 0 "+t.w+" "+t.h),this.renderConfig.viewBoxOnly||(this.svgElement.setAttribute("width",t.w),this.svgElement.setAttribute("height",t.h),this.svgElement.style.width="100%",this.svgElement.style.height="100%",this.svgElement.style.transform="translate3d(0,0,0)"),this.renderConfig.className&&this.svgElement.setAttribute("class",this.renderConfig.className),this.svgElement.setAttribute("preserveAspectRatio",this.renderConfig.preserveAspectRatio),this.animationItem.wrapper.appendChild(this.svgElement);var e=this.globalData.defs;this.setupGlobalData(t,e),this.globalData.progressiveLoad=this.renderConfig.progressiveLoad,this.data=t;var r=createNS("clipPath"),i=createNS("rect");i.setAttribute("width",t.w),i.setAttribute("height",t.h),i.setAttribute("x",0),i.setAttribute("y",0);var s=createElementID();r.setAttribute("id",s),r.appendChild(i),this.layerElement.setAttribute("clip-path","url("+locationHref+"#"+s+")"),e.appendChild(r),this.layers=t.layers,this.elements=createSizedArray(t.layers.length)},SVGRenderer.prototype.destroy=function(){this.animationItem.wrapper.innerHTML="",this.layerElement=null,this.globalData.defs=null;var t,e=this.layers?this.layers.length:0;for(t=0;t<e;t++)this.elements[t]&&this.elements[t].destroy();this.elements.length=0,this.destroyed=!0,this.animationItem=null},SVGRenderer.prototype.updateContainerSize=function(){},SVGRenderer.prototype.buildItem=function(t){var e=this.elements;if(!e[t]&&99!=this.layers[t].ty){e[t]=!0;var r=this.createItem(this.layers[t]);e[t]=r,expressionsPlugin&&(0===this.layers[t].ty&&this.globalData.projectInterface.registerComposition(r),r.initExpressions()),this.appendElementInPos(r,t),this.layers[t].tt&&(this.elements[t-1]&&!0!==this.elements[t-1]?r.setMatte(e[t-1].layerId):(this.buildItem(t-1),this.addPendingElement(r)))}},SVGRenderer.prototype.checkPendingElements=function(){for(;this.pendingElements.length;){var t=this.pendingElements.pop();if(t.checkParenting(),t.data.tt)for(var e=0,r=this.elements.length;e<r;){if(this.elements[e]===t){t.setMatte(this.elements[e-1].layerId);break}e+=1}}},SVGRenderer.prototype.renderFrame=function(t){if(this.renderedFrame!==t&&!this.destroyed){null===t?t=this.renderedFrame:this.renderedFrame=t,this.globalData.frameNum=t,this.globalData.frameId+=1,this.globalData.projectInterface.currentFrame=t,this.globalData._mdf=!1;var e,r=this.layers.length;for(this.completeLayers||this.checkLayers(t),e=r-1;0<=e;e--)(this.completeLayers||this.elements[e])&&this.elements[e].prepareFrame(t-this.layers[e].st);if(this.globalData._mdf)for(e=0;e<r;e+=1)(this.completeLayers||this.elements[e])&&this.elements[e].renderFrame()}},SVGRenderer.prototype.appendElementInPos=function(t,e){var r=t.getBaseElement();if(r){for(var i,s=0;s<e;)this.elements[s]&&!0!==this.elements[s]&&this.elements[s].getBaseElement()&&(i=this.elements[s].getBaseElement()),s+=1;i?this.layerElement.insertBefore(r,i):this.layerElement.appendChild(r)}},SVGRenderer.prototype.hide=function(){this.layerElement.style.display="none"},SVGRenderer.prototype.show=function(){this.layerElement.style.display="block"},extendPrototype([BaseRenderer],CanvasRenderer),CanvasRenderer.prototype.createShape=function(t){return new CVShapeElement(t,this.globalData,this)},CanvasRenderer.prototype.createText=function(t){return new CVTextElement(t,this.globalData,this)},CanvasRenderer.prototype.createImage=function(t){return new CVImageElement(t,this.globalData,this)},CanvasRenderer.prototype.createComp=function(t){return new CVCompElement(t,this.globalData,this)},CanvasRenderer.prototype.createSolid=function(t){return new CVSolidElement(t,this.globalData,this)},CanvasRenderer.prototype.createNull=SVGRenderer.prototype.createNull,CanvasRenderer.prototype.ctxTransform=function(t){if(1!==t[0]||0!==t[1]||0!==t[4]||1!==t[5]||0!==t[12]||0!==t[13])if(this.renderConfig.clearCanvas){this.transformMat.cloneFromProps(t);var e=this.contextData.cTr.props;this.transformMat.transform(e[0],e[1],e[2],e[3],e[4],e[5],e[6],e[7],e[8],e[9],e[10],e[11],e[12],e[13],e[14],e[15]),this.contextData.cTr.cloneFromProps(this.transformMat.props);var r=this.contextData.cTr.props;this.canvasContext.setTransform(r[0],r[1],r[4],r[5],r[12],r[13])}else this.canvasContext.transform(t[0],t[1],t[4],t[5],t[12],t[13])},CanvasRenderer.prototype.ctxOpacity=function(t){if(!this.renderConfig.clearCanvas)return this.canvasContext.globalAlpha*=t<0?0:t,void(this.globalData.currentGlobalAlpha=this.contextData.cO);this.contextData.cO*=t<0?0:t,this.globalData.currentGlobalAlpha!==this.contextData.cO&&(this.canvasContext.globalAlpha=this.contextData.cO,this.globalData.currentGlobalAlpha=this.contextData.cO)},CanvasRenderer.prototype.reset=function(){this.renderConfig.clearCanvas?this.contextData.reset():this.canvasContext.restore()},CanvasRenderer.prototype.save=function(t){if(this.renderConfig.clearCanvas){t&&this.canvasContext.save();var e=this.contextData.cTr.props;this.contextData._length<=this.contextData.cArrPos&&this.contextData.duplicate();var r,i=this.contextData.saved[this.contextData.cArrPos];for(r=0;r<16;r+=1)i[r]=e[r];this.contextData.savedOp[this.contextData.cArrPos]=this.contextData.cO,this.contextData.cArrPos+=1}else this.canvasContext.save()},CanvasRenderer.prototype.restore=function(t){if(this.renderConfig.clearCanvas){t&&(this.canvasContext.restore(),this.globalData.blendMode="source-over"),this.contextData.cArrPos-=1;var e,r=this.contextData.saved[this.contextData.cArrPos],i=this.contextData.cTr.props;for(e=0;e<16;e+=1)i[e]=r[e];this.canvasContext.setTransform(r[0],r[1],r[4],r[5],r[12],r[13]),r=this.contextData.savedOp[this.contextData.cArrPos],this.contextData.cO=r,this.globalData.currentGlobalAlpha!==r&&(this.canvasContext.globalAlpha=r,this.globalData.currentGlobalAlpha=r)}else this.canvasContext.restore()},CanvasRenderer.prototype.configAnimation=function(t){this.animationItem.wrapper?(this.animationItem.container=createTag("canvas"),this.animationItem.container.style.width="100%",this.animationItem.container.style.height="100%",this.animationItem.container.style.transformOrigin=this.animationItem.container.style.mozTransformOrigin=this.animationItem.container.style.webkitTransformOrigin=this.animationItem.container.style["-webkit-transform"]="0px 0px 0px",this.animationItem.wrapper.appendChild(this.animationItem.container),this.canvasContext=this.animationItem.container.getContext("2d"),this.renderConfig.className&&this.animationItem.container.setAttribute("class",this.renderConfig.className)):this.canvasContext=this.renderConfig.context,this.data=t,this.layers=t.layers,this.transformCanvas={w:t.w,h:t.h,sx:0,sy:0,tx:0,ty:0},this.setupGlobalData(t,document.body),this.globalData.canvasContext=this.canvasContext,(this.globalData.renderer=this).globalData.isDashed=!1,this.globalData.progressiveLoad=this.renderConfig.progressiveLoad,this.globalData.transformCanvas=this.transformCanvas,this.elements=createSizedArray(t.layers.length),this.updateContainerSize()},CanvasRenderer.prototype.updateContainerSize=function(){var t,e,r,i;if(this.reset(),this.animationItem.wrapper&&this.animationItem.container?(t=this.animationItem.wrapper.offsetWidth,e=this.animationItem.wrapper.offsetHeight,this.animationItem.container.setAttribute("width",t*this.renderConfig.dpr),this.animationItem.container.setAttribute("height",e*this.renderConfig.dpr)):(t=this.canvasContext.canvas.width*this.renderConfig.dpr,e=this.canvasContext.canvas.height*this.renderConfig.dpr),-1!==this.renderConfig.preserveAspectRatio.indexOf("meet")||-1!==this.renderConfig.preserveAspectRatio.indexOf("slice")){var s=this.renderConfig.preserveAspectRatio.split(" "),a=s[1]||"meet",n=s[0]||"xMidYMid",o=n.substr(0,4),h=n.substr(4);(r=t/e)<(i=this.transformCanvas.w/this.transformCanvas.h)&&"meet"===a||i<r&&"slice"===a?(this.transformCanvas.sx=t/(this.transformCanvas.w/this.renderConfig.dpr),this.transformCanvas.sy=t/(this.transformCanvas.w/this.renderConfig.dpr)):(this.transformCanvas.sx=e/(this.transformCanvas.h/this.renderConfig.dpr),this.transformCanvas.sy=e/(this.transformCanvas.h/this.renderConfig.dpr)),this.transformCanvas.tx="xMid"===o&&(i<r&&"meet"===a||r<i&&"slice"===a)?(t-this.transformCanvas.w*(e/this.transformCanvas.h))/2*this.renderConfig.dpr:"xMax"===o&&(i<r&&"meet"===a||r<i&&"slice"===a)?(t-this.transformCanvas.w*(e/this.transformCanvas.h))*this.renderConfig.dpr:0,this.transformCanvas.ty="YMid"===h&&(r<i&&"meet"===a||i<r&&"slice"===a)?(e-this.transformCanvas.h*(t/this.transformCanvas.w))/2*this.renderConfig.dpr:"YMax"===h&&(r<i&&"meet"===a||i<r&&"slice"===a)?(e-this.transformCanvas.h*(t/this.transformCanvas.w))*this.renderConfig.dpr:0}else"none"==this.renderConfig.preserveAspectRatio?(this.transformCanvas.sx=t/(this.transformCanvas.w/this.renderConfig.dpr),this.transformCanvas.sy=e/(this.transformCanvas.h/this.renderConfig.dpr)):(this.transformCanvas.sx=this.renderConfig.dpr,this.transformCanvas.sy=this.renderConfig.dpr),this.transformCanvas.tx=0,this.transformCanvas.ty=0;this.transformCanvas.props=[this.transformCanvas.sx,0,0,0,0,this.transformCanvas.sy,0,0,0,0,1,0,this.transformCanvas.tx,this.transformCanvas.ty,0,1],this.ctxTransform(this.transformCanvas.props),this.canvasContext.beginPath(),this.canvasContext.rect(0,0,this.transformCanvas.w,this.transformCanvas.h),this.canvasContext.closePath(),this.canvasContext.clip(),this.renderFrame(this.renderedFrame,!0)},CanvasRenderer.prototype.destroy=function(){var t;for(this.renderConfig.clearCanvas&&(this.animationItem.wrapper.innerHTML=""),t=(this.layers?this.layers.length:0)-1;0<=t;t-=1)this.elements[t]&&this.elements[t].destroy();this.elements.length=0,this.globalData.canvasContext=null,this.animationItem.container=null,this.destroyed=!0},CanvasRenderer.prototype.renderFrame=function(t,e){if((this.renderedFrame!==t||!0!==this.renderConfig.clearCanvas||e)&&!this.destroyed&&-1!==t){this.renderedFrame=t,this.globalData.frameNum=t-this.animationItem._isFirstFrame,this.globalData.frameId+=1,this.globalData._mdf=!this.renderConfig.clearCanvas||e,this.globalData.projectInterface.currentFrame=t;var r,i=this.layers.length;for(this.completeLayers||this.checkLayers(t),r=0;r<i;r++)(this.completeLayers||this.elements[r])&&this.elements[r].prepareFrame(t-this.layers[r].st);if(this.globalData._mdf){for(!0===this.renderConfig.clearCanvas?this.canvasContext.clearRect(0,0,this.transformCanvas.w,this.transformCanvas.h):this.save(),r=i-1;0<=r;r-=1)(this.completeLayers||this.elements[r])&&this.elements[r].renderFrame();!0!==this.renderConfig.clearCanvas&&this.restore()}}},CanvasRenderer.prototype.buildItem=function(t){var e=this.elements;if(!e[t]&&99!=this.layers[t].ty){var r=this.createItem(this.layers[t],this,this.globalData);(e[t]=r).initExpressions()}},CanvasRenderer.prototype.checkPendingElements=function(){for(;this.pendingElements.length;){this.pendingElements.pop().checkParenting()}},CanvasRenderer.prototype.hide=function(){this.animationItem.container.style.display="none"},CanvasRenderer.prototype.show=function(){this.animationItem.container.style.display="block"},CanvasRenderer.prototype.configAnimation=function(t){this.animationItem.wrapper?(this.animationItem.container=createTag("canvas"),this.animationItem.container.style.width="100%",this.animationItem.container.style.height="100%",this.animationItem.container.style.transformOrigin=this.animationItem.container.style.mozTransformOrigin=this.animationItem.container.style.webkitTransformOrigin=this.animationItem.container.style["-webkit-transform"]="0px 0px 0px",this.animationItem.wrapper.appendChild(this.animationItem.container),this.canvasContext=this.animationItem.container.getContext("2d"),this.renderConfig.className&&this.animationItem.container.setAttribute("class",this.renderConfig.className)):this.canvasContext=this.renderConfig.context,this.data=t,this.layers=t.layers,this.transformCanvas={w:t.w,h:t.h,sx:0,sy:0,tx:0,ty:0},this.globalData.frameId=0,this.globalData.frameRate=t.fr,this.globalData.nm=t.nm,this.globalData.compSize={w:t.w,h:t.h},this.globalData.canvasContext=this.canvasContext,(this.globalData.renderer=this).globalData.isDashed=!1,this.globalData.progressiveLoad=this.renderConfig.progressiveLoad,this.globalData.transformCanvas=this.transformCanvas,this.elements=createSizedArray(t.layers.length),this.updateContainerSize()},MaskElement.prototype.getMaskProperty=function(t){return this.viewData[t].prop},MaskElement.prototype.renderFrame=function(t){var e,r=this.element.finalTransform.mat,i=this.masksProperties.length;for(e=0;e<i;e++)if((this.viewData[e].prop._mdf||t)&&this.drawPath(this.masksProperties[e],this.viewData[e].prop.v,this.viewData[e]),(this.viewData[e].op._mdf||t)&&this.viewData[e].elem.setAttribute("fill-opacity",this.viewData[e].op.v),"n"!==this.masksProperties[e].mode&&(this.viewData[e].invRect&&(this.element.finalTransform.mProp._mdf||t)&&(this.viewData[e].invRect.setAttribute("x",-r.props[12]),this.viewData[e].invRect.setAttribute("y",-r.props[13])),this.storedData[e].x&&(this.storedData[e].x._mdf||t))){var s=this.storedData[e].expan;this.storedData[e].x.v<0?("erode"!==this.storedData[e].lastOperator&&(this.storedData[e].lastOperator="erode",this.storedData[e].elem.setAttribute("filter","url("+locationHref+"#"+this.storedData[e].filterId+")")),s.setAttribute("radius",-this.storedData[e].x.v)):("dilate"!==this.storedData[e].lastOperator&&(this.storedData[e].lastOperator="dilate",this.storedData[e].elem.setAttribute("filter",null)),this.storedData[e].elem.setAttribute("stroke-width",2*this.storedData[e].x.v))}},MaskElement.prototype.getMaskelement=function(){return this.maskElement},MaskElement.prototype.createLayerSolidPath=function(){var t="M0,0 ";return t+=" h"+this.globalData.compSize.w,t+=" v"+this.globalData.compSize.h,t+=" h-"+this.globalData.compSize.w,t+=" v-"+this.globalData.compSize.h+" "},MaskElement.prototype.drawPath=function(t,e,r){var i,s,a=" M"+e.v[0][0]+","+e.v[0][1];for(s=e._length,i=1;i<s;i+=1)a+=" C"+e.o[i-1][0]+","+e.o[i-1][1]+" "+e.i[i][0]+","+e.i[i][1]+" "+e.v[i][0]+","+e.v[i][1];if(e.c&&1<s&&(a+=" C"+e.o[i-1][0]+","+e.o[i-1][1]+" "+e.i[0][0]+","+e.i[0][1]+" "+e.v[0][0]+","+e.v[0][1]),r.lastPath!==a){var n="";r.elem&&(e.c&&(n=t.inv?this.solidPath+a:a),r.elem.setAttribute("d",n)),r.lastPath=a}},MaskElement.prototype.destroy=function(){this.element=null,this.globalData=null,this.maskElement=null,this.data=null,this.masksProperties=null},HierarchyElement.prototype={initHierarchy:function(){this.hierarchy=[],this._isParent=!1,this.checkParenting()},setHierarchy:function(t){this.hierarchy=t},setAsParent:function(){this._isParent=!0},checkParenting:function(){void 0!==this.data.parent&&this.comp.buildElementParenting(this,this.data.parent,[])}},FrameElement.prototype={initFrame:function(){this._isFirstFrame=!1,this.dynamicProperties=[],this._mdf=!1},prepareProperties:function(t,e){var r,i=this.dynamicProperties.length;for(r=0;r<i;r+=1)(e||this._isParent&&"transform"===this.dynamicProperties[r].propType)&&(this.dynamicProperties[r].getValue(),this.dynamicProperties[r]._mdf&&(this.globalData._mdf=!0,this._mdf=!0))},addDynamicProperty:function(t){-1===this.dynamicProperties.indexOf(t)&&this.dynamicProperties.push(t)}},TransformElement.prototype={initTransform:function(){this.finalTransform={mProp:this.data.ks?TransformPropertyFactory.getTransformProperty(this,this.data.ks,this):{o:0},_matMdf:!1,_opMdf:!1,mat:new Matrix},this.data.ao&&(this.finalTransform.mProp.autoOriented=!0),this.data.ty},renderTransform:function(){if(this.finalTransform._opMdf=this.finalTransform.mProp.o._mdf||this._isFirstFrame,this.finalTransform._matMdf=this.finalTransform.mProp._mdf||this._isFirstFrame,this.hierarchy){var t,e=this.finalTransform.mat,r=0,i=this.hierarchy.length;if(!this.finalTransform._matMdf)for(;r<i;){if(this.hierarchy[r].finalTransform.mProp._mdf){this.finalTransform._matMdf=!0;break}r+=1}if(this.finalTransform._matMdf)for(t=this.finalTransform.mProp.v.props,e.cloneFromProps(t),r=0;r<i;r+=1)t=this.hierarchy[r].finalTransform.mProp.v.props,e.transform(t[0],t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15])}},globalToLocal:function(t){var e=[];e.push(this.finalTransform);for(var r=!0,i=this.comp;r;)i.finalTransform?(i.data.hasMask&&e.splice(0,0,i.finalTransform),i=i.comp):r=!1;var s,a,n=e.length;for(s=0;s<n;s+=1)a=e[s].mat.applyToPointArray(0,0,0),t=[t[0]-a[0],t[1]-a[1],0];return t},mHelper:new Matrix},RenderableElement.prototype={initRenderable:function(){this.isInRange=!1,this.hidden=!1,this.isTransparent=!1,this.renderableComponents=[]},addRenderableComponent:function(t){-1===this.renderableComponents.indexOf(t)&&this.renderableComponents.push(t)},removeRenderableComponent:function(t){-1!==this.renderableComponents.indexOf(t)&&this.renderableComponents.splice(this.renderableComponents.indexOf(t),1)},prepareRenderableFrame:function(t){this.checkLayerLimits(t)},checkTransparency:function(){this.finalTransform.mProp.o.v<=0?!this.isTransparent&&this.globalData.renderConfig.hideOnTransparent&&(this.isTransparent=!0,this.hide()):this.isTransparent&&(this.isTransparent=!1,this.show())},checkLayerLimits:function(t){this.data.ip-this.data.st<=t&&this.data.op-this.data.st>t?!0!==this.isInRange&&(this.globalData._mdf=!0,this._mdf=!0,this.isInRange=!0,this.show()):!1!==this.isInRange&&(this.globalData._mdf=!0,this.isInRange=!1,this.hide())},renderRenderable:function(){var t,e=this.renderableComponents.length;for(t=0;t<e;t+=1)this.renderableComponents[t].renderFrame(this._isFirstFrame)},sourceRectAtTime:function(){return{top:0,left:0,width:100,height:100}},getLayerSize:function(){return 5===this.data.ty?{w:this.data.textData.width,h:this.data.textData.height}:{w:this.data.width,h:this.data.height}}},extendPrototype([RenderableElement,createProxyFunction({initElement:function(t,e,r){this.initFrame(),this.initBaseData(t,e,r),this.initTransform(t,e,r),this.initHierarchy(),this.initRenderable(),this.initRendererElement(),this.createContainerElements(),this.createRenderableComponents(),this.createContent(),this.hide()},hide:function(){this.hidden||this.isInRange&&!this.isTransparent||((this.baseElement||this.layerElement).style.display="none",this.hidden=!0)},show:function(){this.isInRange&&!this.isTransparent&&(this.data.hd||((this.baseElement||this.layerElement).style.display="block"),this.hidden=!1,this._isFirstFrame=!0)},renderFrame:function(){this.data.hd||this.hidden||(this.renderTransform(),this.renderRenderable(),this.renderElement(),this.renderInnerContent(),this._isFirstFrame&&(this._isFirstFrame=!1))},renderInnerContent:function(){},prepareFrame:function(t){this._mdf=!1,this.prepareRenderableFrame(t),this.prepareProperties(t,this.isInRange),this.checkTransparency()},destroy:function(){this.innerElem=null,this.destroyBaseElement()}})],RenderableDOMElement),SVGShapeData.prototype.setAsAnimated=function(){this._isAnimated=!0},ShapeTransformManager.prototype={addTransformSequence:function(t){var e,r=t.length,i="_";for(e=0;e<r;e+=1)i+=t[e].transform.key+"_";var s=this.sequences[i];return s||(s={transforms:[].concat(t),finalTransform:new Matrix,_mdf:!1},this.sequences[i]=s,this.sequenceList.push(s)),s},processSequence:function(t,e){for(var r,i=0,s=t.transforms.length,a=e;i<s&&!e;){if(t.transforms[i].transform.mProps._mdf){a=!0;break}i+=1}if(a)for(t.finalTransform.reset(),i=s-1;0<=i;i-=1)r=t.transforms[i].transform.mProps.v.props,t.finalTransform.transform(r[0],r[1],r[2],r[3],r[4],r[5],r[6],r[7],r[8],r[9],r[10],r[11],r[12],r[13],r[14],r[15]);t._mdf=a},processSequences:function(t){var e,r=this.sequenceList.length;for(e=0;e<r;e+=1)this.processSequence(this.sequenceList[e],t)},getNewKey:function(){return"_"+this.transform_key_count++}},CVShapeData.prototype.setAsAnimated=SVGShapeData.prototype.setAsAnimated,BaseElement.prototype={checkMasks:function(){if(!this.data.hasMask)return!1;for(var t=0,e=this.data.masksProperties.length;t<e;){if("n"!==this.data.masksProperties[t].mode&&!1!==this.data.masksProperties[t].cl)return!0;t+=1}return!1},initExpressions:function(){this.layerInterface=LayerExpressionInterface(this),this.data.hasMask&&this.maskManager&&this.layerInterface.registerMaskInterface(this.maskManager);var t=EffectsExpressionInterface.createEffectsInterface(this,this.layerInterface);this.layerInterface.registerEffectsInterface(t),0===this.data.ty||this.data.xt?this.compInterface=CompExpressionInterface(this):4===this.data.ty?(this.layerInterface.shapeInterface=ShapeExpressionInterface(this.shapesData,this.itemsData,this.layerInterface),this.layerInterface.content=this.layerInterface.shapeInterface):5===this.data.ty&&(this.layerInterface.textInterface=TextExpressionInterface(this),this.layerInterface.text=this.layerInterface.textInterface)},setBlendMode:function(){var t=getBlendMode(this.data.bm);(this.baseElement||this.layerElement).style["mix-blend-mode"]=t},initBaseData:function(t,e,r){this.globalData=e,this.comp=r,this.data=t,this.layerId=createElementID(),this.data.sr||(this.data.sr=1),this.effectsManager=new EffectsManager(this.data,this,this.dynamicProperties)},getType:function(){return this.type},sourceRectAtTime:function(){}},NullElement.prototype.prepareFrame=function(t){this.prepareProperties(t,!0)},NullElement.prototype.renderFrame=function(){},NullElement.prototype.getBaseElement=function(){return null},NullElement.prototype.destroy=function(){},NullElement.prototype.sourceRectAtTime=function(){},NullElement.prototype.hide=function(){},extendPrototype([BaseElement,TransformElement,HierarchyElement,FrameElement],NullElement),SVGBaseElement.prototype={initRendererElement:function(){this.layerElement=createNS("g")},createContainerElements:function(){this.matteElement=createNS("g"),this.transformedElement=this.layerElement,this.maskedElement=this.layerElement,this._sizeChanged=!1;var t,e,r,i=null;if(this.data.td){if(3==this.data.td||1==this.data.td){var s=createNS("mask");s.setAttribute("id",this.layerId),s.setAttribute("mask-type",3==this.data.td?"luminance":"alpha"),s.appendChild(this.layerElement),i=s,this.globalData.defs.appendChild(s),featureSupport.maskType||1!=this.data.td||(s.setAttribute("mask-type","luminance"),t=createElementID(),e=filtersFactory.createFilter(t),this.globalData.defs.appendChild(e),e.appendChild(filtersFactory.createAlphaToLuminanceFilter()),(r=createNS("g")).appendChild(this.layerElement),i=r,s.appendChild(r),r.setAttribute("filter","url("+locationHref+"#"+t+")"))}else if(2==this.data.td){var a=createNS("mask");a.setAttribute("id",this.layerId),a.setAttribute("mask-type","alpha");var n=createNS("g");a.appendChild(n),t=createElementID(),e=filtersFactory.createFilter(t);var o=createNS("feComponentTransfer");o.setAttribute("in","SourceGraphic"),e.appendChild(o);var h=createNS("feFuncA");h.setAttribute("type","table"),h.setAttribute("tableValues","1.0 0.0"),o.appendChild(h),this.globalData.defs.appendChild(e);var p=createNS("rect");p.setAttribute("width",this.comp.data.w),p.setAttribute("height",this.comp.data.h),p.setAttribute("x","0"),p.setAttribute("y","0"),p.setAttribute("fill","#ffffff"),p.setAttribute("opacity","0"),n.setAttribute("filter","url("+locationHref+"#"+t+")"),n.appendChild(p),n.appendChild(this.layerElement),i=n,featureSupport.maskType||(a.setAttribute("mask-type","luminance"),e.appendChild(filtersFactory.createAlphaToLuminanceFilter()),r=createNS("g"),n.appendChild(p),r.appendChild(this.layerElement),i=r,n.appendChild(r)),this.globalData.defs.appendChild(a)}}else this.data.tt?(this.matteElement.appendChild(this.layerElement),i=this.matteElement,this.baseElement=this.matteElement):this.baseElement=this.layerElement;if(this.data.ln&&this.layerElement.setAttribute("id",this.data.ln),this.data.cl&&this.layerElement.setAttribute("class",this.data.cl),0===this.data.ty&&!this.data.hd){var l=createNS("clipPath"),m=createNS("path");m.setAttribute("d","M0,0 L"+this.data.w+",0 L"+this.data.w+","+this.data.h+" L0,"+this.data.h+"z");var f=createElementID();if(l.setAttribute("id",f),l.appendChild(m),this.globalData.defs.appendChild(l),this.checkMasks()){var c=createNS("g");c.setAttribute("clip-path","url("+locationHref+"#"+f+")"),c.appendChild(this.layerElement),this.transformedElement=c,i?i.appendChild(this.transformedElement):this.baseElement=this.transformedElement}else this.layerElement.setAttribute("clip-path","url("+locationHref+"#"+f+")")}0!==this.data.bm&&this.setBlendMode()},renderElement:function(){this.finalTransform._matMdf&&this.transformedElement.setAttribute("transform",this.finalTransform.mat.to2dCSS()),this.finalTransform._opMdf&&this.transformedElement.setAttribute("opacity",this.finalTransform.mProp.o.v)},destroyBaseElement:function(){this.layerElement=null,this.matteElement=null,this.maskManager.destroy()},getBaseElement:function(){return this.data.hd?null:this.baseElement},createRenderableComponents:function(){this.maskManager=new MaskElement(this.data,this,this.globalData),this.renderableEffectsManager=new SVGEffects(this)},setMatte:function(t){this.matteElement&&this.matteElement.setAttribute("mask","url("+locationHref+"#"+t+")")}},IShapeElement.prototype={addShapeToModifiers:function(t){var e,r=this.shapeModifiers.length;for(e=0;e<r;e+=1)this.shapeModifiers[e].addShape(t)},isShapeInAnimatedModifiers:function(t){for(var e=this.shapeModifiers.length;0<e;)if(this.shapeModifiers[0].isAnimatedWithShape(t))return!0;return!1},renderModifiers:function(){if(this.shapeModifiers.length){var t,e=this.shapes.length;for(t=0;t<e;t+=1)this.shapes[t].sh.reset();for(t=(e=this.shapeModifiers.length)-1;0<=t;t-=1)this.shapeModifiers[t].processShapes(this._isFirstFrame)}},lcEnum:{1:"butt",2:"round",3:"square"},ljEnum:{1:"miter",2:"round",3:"bevel"},searchProcessedElement:function(t){for(var e=this.processedElements,r=0,i=e.length;r<i;){if(e[r].elem===t)return e[r].pos;r+=1}return 0},addProcessedElement:function(t,e){for(var r=this.processedElements,i=r.length;i;)if(r[i-=1].elem===t)return void(r[i].pos=e);r.push(new ProcessedElement(t,e))},prepareFrame:function(t){this.prepareRenderableFrame(t),this.prepareProperties(t,this.isInRange)}},ITextElement.prototype.initElement=function(t,e,r){this.lettersChangedFlag=!0,this.initFrame(),this.initBaseData(t,e,r),this.textProperty=new TextProperty(this,t.t,this.dynamicProperties),this.textAnimator=new TextAnimatorProperty(t.t,this.renderType,this),this.initTransform(t,e,r),this.initHierarchy(),this.initRenderable(),this.initRendererElement(),this.createContainerElements(),this.createRenderableComponents(),this.createContent(),this.hide(),this.textAnimator.searchProperties(this.dynamicProperties)},ITextElement.prototype.prepareFrame=function(t){this._mdf=!1,this.prepareRenderableFrame(t),this.prepareProperties(t,this.isInRange),(this.textProperty._mdf||this.textProperty._isFirstFrame)&&(this.buildNewText(),this.textProperty._isFirstFrame=!1,this.textProperty._mdf=!1)},ITextElement.prototype.createPathShape=function(t,e){var r,i,s=e.length,a="";for(r=0;r<s;r+=1)i=e[r].ks.k,a+=buildShapeString(i,i.i.length,!0,t);return a},ITextElement.prototype.updateDocumentData=function(t,e){this.textProperty.updateDocumentData(t,e)},ITextElement.prototype.canResizeFont=function(t){this.textProperty.canResizeFont(t)},ITextElement.prototype.setMinimumFontSize=function(t){this.textProperty.setMinimumFontSize(t)},ITextElement.prototype.applyTextPropertiesToMatrix=function(t,e,r,i,s){switch(t.ps&&e.translate(t.ps[0],t.ps[1]+t.ascent,0),e.translate(0,-t.ls,0),t.j){case 1:e.translate(t.justifyOffset+(t.boxWidth-t.lineWidths[r]),0,0);break;case 2:e.translate(t.justifyOffset+(t.boxWidth-t.lineWidths[r])/2,0,0)}e.translate(i,s,0)},ITextElement.prototype.buildColor=function(t){return"rgb("+Math.round(255*t[0])+","+Math.round(255*t[1])+","+Math.round(255*t[2])+")"},ITextElement.prototype.emptyProp=new LetterProps,ITextElement.prototype.destroy=function(){},extendPrototype([BaseElement,TransformElement,HierarchyElement,FrameElement,RenderableDOMElement],ICompElement),ICompElement.prototype.initElement=function(t,e,r){this.initFrame(),this.initBaseData(t,e,r),this.initTransform(t,e,r),this.initRenderable(),this.initHierarchy(),this.initRendererElement(),this.createContainerElements(),this.createRenderableComponents(),!this.data.xt&&e.progressiveLoad||this.buildAllItems(),this.hide()},ICompElement.prototype.prepareFrame=function(t){if(this._mdf=!1,this.prepareRenderableFrame(t),this.prepareProperties(t,this.isInRange),this.isInRange||this.data.xt){if(this.tm._placeholder)this.renderedFrame=t/this.data.sr;else{var e=this.tm.v;e===this.data.op&&(e=this.data.op-1),this.renderedFrame=e}var r,i=this.elements.length;for(this.completeLayers||this.checkLayers(this.renderedFrame),r=i-1;0<=r;r-=1)(this.completeLayers||this.elements[r])&&(this.elements[r].prepareFrame(this.renderedFrame-this.layers[r].st),this.elements[r]._mdf&&(this._mdf=!0))}},ICompElement.prototype.renderInnerContent=function(){var t,e=this.layers.length;for(t=0;t<e;t+=1)(this.completeLayers||this.elements[t])&&this.elements[t].renderFrame()},ICompElement.prototype.setElements=function(t){this.elements=t},ICompElement.prototype.getElements=function(){return this.elements},ICompElement.prototype.destroyElements=function(){var t,e=this.layers.length;for(t=0;t<e;t+=1)this.elements[t]&&this.elements[t].destroy()},ICompElement.prototype.destroy=function(){this.destroyElements(),this.destroyBaseElement()},extendPrototype([BaseElement,TransformElement,SVGBaseElement,HierarchyElement,FrameElement,RenderableDOMElement],IImageElement),IImageElement.prototype.createContent=function(){var t=this.globalData.getAssetsPath(this.assetData);this.innerElem=createNS("image"),this.innerElem.setAttribute("width",this.assetData.w+"px"),this.innerElem.setAttribute("height",this.assetData.h+"px"),this.innerElem.setAttribute("preserveAspectRatio",this.assetData.pr||this.globalData.renderConfig.imagePreserveAspectRatio),this.innerElem.setAttributeNS("http://www.w3.org/1999/xlink","href",t),this.layerElement.appendChild(this.innerElem)},IImageElement.prototype.sourceRectAtTime=function(){return this.sourceRect},extendPrototype([IImageElement],ISolidElement),ISolidElement.prototype.createContent=function(){var t=createNS("rect");t.setAttribute("width",this.data.sw),t.setAttribute("height",this.data.sh),t.setAttribute("fill",this.data.sc),this.layerElement.appendChild(t)},extendPrototype([BaseElement,TransformElement,SVGBaseElement,IShapeElement,HierarchyElement,FrameElement,RenderableDOMElement],SVGShapeElement),SVGShapeElement.prototype.initSecondaryElement=function(){},SVGShapeElement.prototype.identityMatrix=new Matrix,SVGShapeElement.prototype.buildExpressionInterface=function(){},SVGShapeElement.prototype.createContent=function(){this.searchShapes(this.shapesData,this.itemsData,this.prevViewData,this.layerElement,0,[],!0),this.filterUniqueShapes()},SVGShapeElement.prototype.filterUniqueShapes=function(){var t,e,r,i,s=this.shapes.length,a=this.stylesList.length,n=[],o=!1;for(r=0;r<a;r+=1){for(i=this.stylesList[r],o=!1,t=n.length=0;t<s;t+=1)-1!==(e=this.shapes[t]).styles.indexOf(i)&&(n.push(e),o=e._isAnimated||o);1<n.length&&o&&this.setShapesAsAnimated(n)}},SVGShapeElement.prototype.setShapesAsAnimated=function(t){var e,r=t.length;for(e=0;e<r;e+=1)t[e].setAsAnimated()},SVGShapeElement.prototype.createStyleElement=function(t,e){var r,i=new SVGStyleData(t,e),s=i.pElem;if("st"===t.ty)r=new SVGStrokeStyleData(this,t,i);else if("fl"===t.ty)r=new SVGFillStyleData(this,t,i);else if("gf"===t.ty||"gs"===t.ty){r=new("gf"===t.ty?SVGGradientFillStyleData:SVGGradientStrokeStyleData)(this,t,i),this.globalData.defs.appendChild(r.gf),r.maskId&&(this.globalData.defs.appendChild(r.ms),this.globalData.defs.appendChild(r.of),s.setAttribute("mask","url("+locationHref+"#"+r.maskId+")"))}return"st"!==t.ty&&"gs"!==t.ty||(s.setAttribute("stroke-linecap",this.lcEnum[t.lc]||"round"),s.setAttribute("stroke-linejoin",this.ljEnum[t.lj]||"round"),s.setAttribute("fill-opacity","0"),1===t.lj&&s.setAttribute("stroke-miterlimit",t.ml)),2===t.r&&s.setAttribute("fill-rule","evenodd"),t.ln&&s.setAttribute("id",t.ln),t.cl&&s.setAttribute("class",t.cl),t.bm&&(s.style["mix-blend-mode"]=getBlendMode(t.bm)),this.stylesList.push(i),this.addToAnimatedContents(t,r),r},SVGShapeElement.prototype.createGroupElement=function(t){var e=new ShapeGroupData;return t.ln&&e.gr.setAttribute("id",t.ln),t.cl&&e.gr.setAttribute("class",t.cl),t.bm&&(e.gr.style["mix-blend-mode"]=getBlendMode(t.bm)),e},SVGShapeElement.prototype.createTransformElement=function(t,e){var r=TransformPropertyFactory.getTransformProperty(this,t,this),i=new SVGTransformData(r,r.o,e);return this.addToAnimatedContents(t,i),i},SVGShapeElement.prototype.createShapeElement=function(t,e,r){var i=4;"rc"===t.ty?i=5:"el"===t.ty?i=6:"sr"===t.ty&&(i=7);var s=new SVGShapeData(e,r,ShapePropertyFactory.getShapeProp(this,t,i,this));return this.shapes.push(s),this.addShapeToModifiers(s),this.addToAnimatedContents(t,s),s},SVGShapeElement.prototype.addToAnimatedContents=function(t,e){for(var r=0,i=this.animatedContents.length;r<i;){if(this.animatedContents[r].element===e)return;r+=1}this.animatedContents.push({fn:SVGElementsRenderer.createRenderFunction(t),element:e,data:t})},SVGShapeElement.prototype.setElementStyles=function(t){var e,r=t.styles,i=this.stylesList.length;for(e=0;e<i;e+=1)this.stylesList[e].closed||r.push(this.stylesList[e])},SVGShapeElement.prototype.reloadShapes=function(){this._isFirstFrame=!0;var t,e=this.itemsData.length;for(t=0;t<e;t+=1)this.prevViewData[t]=this.itemsData[t];for(this.searchShapes(this.shapesData,this.itemsData,this.prevViewData,this.layerElement,0,[],!0),this.filterUniqueShapes(),e=this.dynamicProperties.length,t=0;t<e;t+=1)this.dynamicProperties[t].getValue();this.renderModifiers()},SVGShapeElement.prototype.searchShapes=function(t,e,r,i,s,a,n){var o,h,p,l,m,f,c=[].concat(a),d=t.length-1,u=[],y=[];for(o=d;0<=o;o-=1){if((f=this.searchProcessedElement(t[o]))?e[o]=r[f-1]:t[o]._render=n,"fl"==t[o].ty||"st"==t[o].ty||"gf"==t[o].ty||"gs"==t[o].ty)f?e[o].style.closed=!1:e[o]=this.createStyleElement(t[o],s),t[o]._render&&i.appendChild(e[o].style.pElem),u.push(e[o].style);else if("gr"==t[o].ty){if(f)for(p=e[o].it.length,h=0;h<p;h+=1)e[o].prevViewData[h]=e[o].it[h];else e[o]=this.createGroupElement(t[o]);this.searchShapes(t[o].it,e[o].it,e[o].prevViewData,e[o].gr,s+1,c,n),t[o]._render&&i.appendChild(e[o].gr)}else"tr"==t[o].ty?(f||(e[o]=this.createTransformElement(t[o],i)),l=e[o].transform,c.push(l)):"sh"==t[o].ty||"rc"==t[o].ty||"el"==t[o].ty||"sr"==t[o].ty?(f||(e[o]=this.createShapeElement(t[o],c,s)),this.setElementStyles(e[o])):"tm"==t[o].ty||"rd"==t[o].ty||"ms"==t[o].ty?(f?(m=e[o]).closed=!1:((m=ShapeModifiers.getModifier(t[o].ty)).init(this,t[o]),e[o]=m,this.shapeModifiers.push(m)),y.push(m)):"rp"==t[o].ty&&(f?(m=e[o]).closed=!0:(m=ShapeModifiers.getModifier(t[o].ty),(e[o]=m).init(this,t,o,e),this.shapeModifiers.push(m),n=!1),y.push(m));this.addProcessedElement(t[o],o+1)}for(d=u.length,o=0;o<d;o+=1)u[o].closed=!0;for(d=y.length,o=0;o<d;o+=1)y[o].closed=!0},SVGShapeElement.prototype.renderInnerContent=function(){this.renderModifiers();var t,e=this.stylesList.length;for(t=0;t<e;t+=1)this.stylesList[t].reset();for(this.renderShape(),t=0;t<e;t+=1)(this.stylesList[t]._mdf||this._isFirstFrame)&&(this.stylesList[t].msElem&&(this.stylesList[t].msElem.setAttribute("d",this.stylesList[t].d),this.stylesList[t].d="M0 0"+this.stylesList[t].d),this.stylesList[t].pElem.setAttribute("d",this.stylesList[t].d||"M0 0"))},SVGShapeElement.prototype.renderShape=function(){var t,e,r=this.animatedContents.length;for(t=0;t<r;t+=1)e=this.animatedContents[t],(this._isFirstFrame||e.element._isAnimated)&&!0!==e.data&&e.fn(e.data,e.element,this._isFirstFrame)},SVGShapeElement.prototype.destroy=function(){this.destroyBaseElement(),this.shapesData=null,this.itemsData=null},CVContextData.prototype.duplicate=function(){var t=2*this._length,e=this.savedOp;this.savedOp=createTypedArray("float32",t),this.savedOp.set(e);var r=0;for(r=this._length;r<t;r+=1)this.saved[r]=createTypedArray("float32",16);this._length=t},CVContextData.prototype.reset=function(){this.cArrPos=0,this.cTr.reset(),this.cO=1},CVBaseElement.prototype={createElements:function(){},initRendererElement:function(){},createContainerElements:function(){this.canvasContext=this.globalData.canvasContext,this.renderableEffectsManager=new CVEffects(this)},createContent:function(){},setBlendMode:function(){var t=this.globalData;if(t.blendMode!==this.data.bm){t.blendMode=this.data.bm;var e=getBlendMode(this.data.bm);t.canvasContext.globalCompositeOperation=e}},createRenderableComponents:function(){this.maskManager=new CVMaskElement(this.data,this)},hideElement:function(){this.hidden||this.isInRange&&!this.isTransparent||(this.hidden=!0)},showElement:function(){this.isInRange&&!this.isTransparent&&(this.hidden=!1,this._isFirstFrame=!0,this.maskManager._isFirstFrame=!0)},renderFrame:function(){this.hidden||this.data.hd||(this.renderTransform(),this.renderRenderable(),this.setBlendMode(),this.globalData.renderer.save(),this.globalData.renderer.ctxTransform(this.finalTransform.mat.props),this.globalData.renderer.ctxOpacity(this.finalTransform.mProp.o.v),this.renderInnerContent(),this.globalData.renderer.restore(),this.maskManager.hasMasks&&this.globalData.renderer.restore(!0),this._isFirstFrame&&(this._isFirstFrame=!1))},destroy:function(){this.canvasContext=null,this.data=null,this.globalData=null,this.maskManager.destroy()},mHelper:new Matrix},CVBaseElement.prototype.hide=CVBaseElement.prototype.hideElement,CVBaseElement.prototype.show=CVBaseElement.prototype.showElement,extendPrototype([CanvasRenderer,ICompElement,CVBaseElement],CVCompElement),CVCompElement.prototype.renderInnerContent=function(){var t;for(t=this.layers.length-1;0<=t;t-=1)(this.completeLayers||this.elements[t])&&this.elements[t].renderFrame()},CVCompElement.prototype.destroy=function(){var t;for(t=this.layers.length-1;0<=t;t-=1)this.elements[t]&&this.elements[t].destroy();this.layers=null,this.elements=null},CVMaskElement.prototype.renderFrame=function(){if(this.hasMasks){var t,e,r,i,s=this.element.finalTransform.mat,a=this.element.canvasContext,n=this.masksProperties.length;for(a.beginPath(),t=0;t<n;t++)if("n"!==this.masksProperties[t].mode){this.masksProperties[t].inv&&(a.moveTo(0,0),a.lineTo(this.element.globalData.compSize.w,0),a.lineTo(this.element.globalData.compSize.w,this.element.globalData.compSize.h),a.lineTo(0,this.element.globalData.compSize.h),a.lineTo(0,0)),i=this.viewData[t].v,e=s.applyToPointArray(i.v[0][0],i.v[0][1],0),a.moveTo(e[0],e[1]);var o,h=i._length;for(o=1;o<h;o++)r=s.applyToTriplePoints(i.o[o-1],i.i[o],i.v[o]),a.bezierCurveTo(r[0],r[1],r[2],r[3],r[4],r[5]);r=s.applyToTriplePoints(i.o[o-1],i.i[0],i.v[0]),a.bezierCurveTo(r[0],r[1],r[2],r[3],r[4],r[5])}this.element.globalData.renderer.save(!0),a.clip()}},CVMaskElement.prototype.getMaskProperty=MaskElement.prototype.getMaskProperty,CVMaskElement.prototype.destroy=function(){this.element=null},extendPrototype([BaseElement,TransformElement,CVBaseElement,IShapeElement,HierarchyElement,FrameElement,RenderableElement],CVShapeElement),CVShapeElement.prototype.initElement=RenderableDOMElement.prototype.initElement,CVShapeElement.prototype.transformHelper={opacity:1,_opMdf:!1},CVShapeElement.prototype.dashResetter=[],CVShapeElement.prototype.createContent=function(){this.searchShapes(this.shapesData,this.itemsData,this.prevViewData,!0,[])},CVShapeElement.prototype.createStyleElement=function(t,e){var r={data:t,type:t.ty,preTransforms:this.transformsManager.addTransformSequence(e),transforms:[],elements:[],closed:!0===t.hd},i={};if("fl"==t.ty||"st"==t.ty?(i.c=PropertyFactory.getProp(this,t.c,1,255,this),i.c.k||(r.co="rgb("+bm_floor(i.c.v[0])+","+bm_floor(i.c.v[1])+","+bm_floor(i.c.v[2])+")")):"gf"!==t.ty&&"gs"!==t.ty||(i.s=PropertyFactory.getProp(this,t.s,1,null,this),i.e=PropertyFactory.getProp(this,t.e,1,null,this),i.h=PropertyFactory.getProp(this,t.h||{k:0},0,.01,this),i.a=PropertyFactory.getProp(this,t.a||{k:0},0,degToRads,this),i.g=new GradientProperty(this,t.g,this)),i.o=PropertyFactory.getProp(this,t.o,0,.01,this),"st"==t.ty||"gs"==t.ty){if(r.lc=this.lcEnum[t.lc]||"round",r.lj=this.ljEnum[t.lj]||"round",1==t.lj&&(r.ml=t.ml),i.w=PropertyFactory.getProp(this,t.w,0,null,this),i.w.k||(r.wi=i.w.v),t.d){var s=new DashProperty(this,t.d,"canvas",this);i.d=s,i.d.k||(r.da=i.d.dashArray,r.do=i.d.dashoffset[0])}}else r.r=2===t.r?"evenodd":"nonzero";return this.stylesList.push(r),i.style=r,i},CVShapeElement.prototype.createGroupElement=function(t){return{it:[],prevViewData:[]}},CVShapeElement.prototype.createTransformElement=function(t){return{transform:{opacity:1,_opMdf:!1,key:this.transformsManager.getNewKey(),op:PropertyFactory.getProp(this,t.o,0,.01,this),mProps:TransformPropertyFactory.getTransformProperty(this,t,this)}}},CVShapeElement.prototype.createShapeElement=function(t){var e=new CVShapeData(this,t,this.stylesList,this.transformsManager);return this.shapes.push(e),this.addShapeToModifiers(e),e},CVShapeElement.prototype.reloadShapes=function(){this._isFirstFrame=!0;var t,e=this.itemsData.length;for(t=0;t<e;t+=1)this.prevViewData[t]=this.itemsData[t];for(this.searchShapes(this.shapesData,this.itemsData,this.prevViewData,!0,[]),e=this.dynamicProperties.length,t=0;t<e;t+=1)this.dynamicProperties[t].getValue();this.renderModifiers(),this.transformsManager.processSequences(this._isFirstFrame)},CVShapeElement.prototype.addTransformToStyleList=function(t){var e,r=this.stylesList.length;for(e=0;e<r;e+=1)this.stylesList[e].closed||this.stylesList[e].transforms.push(t)},CVShapeElement.prototype.removeTransformFromStyleList=function(){var t,e=this.stylesList.length;for(t=0;t<e;t+=1)this.stylesList[t].closed||this.stylesList[t].transforms.pop()},CVShapeElement.prototype.closeStyles=function(t){var e,r=t.length;for(e=0;e<r;e+=1)t[e].closed=!0},CVShapeElement.prototype.searchShapes=function(t,e,r,i,s){var a,n,o,h,p,l,m=t.length-1,f=[],c=[],d=[].concat(s);for(a=m;0<=a;a-=1){if((h=this.searchProcessedElement(t[a]))?e[a]=r[h-1]:t[a]._shouldRender=i,"fl"==t[a].ty||"st"==t[a].ty||"gf"==t[a].ty||"gs"==t[a].ty)h?e[a].style.closed=!1:e[a]=this.createStyleElement(t[a],d),f.push(e[a].style);else if("gr"==t[a].ty){if(h)for(o=e[a].it.length,n=0;n<o;n+=1)e[a].prevViewData[n]=e[a].it[n];else e[a]=this.createGroupElement(t[a]);this.searchShapes(t[a].it,e[a].it,e[a].prevViewData,i,d)}else"tr"==t[a].ty?(h||(l=this.createTransformElement(t[a]),e[a]=l),d.push(e[a]),this.addTransformToStyleList(e[a])):"sh"==t[a].ty||"rc"==t[a].ty||"el"==t[a].ty||"sr"==t[a].ty?h||(e[a]=this.createShapeElement(t[a])):"tm"==t[a].ty||"rd"==t[a].ty?(h?(p=e[a]).closed=!1:((p=ShapeModifiers.getModifier(t[a].ty)).init(this,t[a]),e[a]=p,this.shapeModifiers.push(p)),c.push(p)):"rp"==t[a].ty&&(h?(p=e[a]).closed=!0:(p=ShapeModifiers.getModifier(t[a].ty),(e[a]=p).init(this,t,a,e),this.shapeModifiers.push(p),i=!1),c.push(p));this.addProcessedElement(t[a],a+1)}for(this.removeTransformFromStyleList(),this.closeStyles(f),m=c.length,a=0;a<m;a+=1)c[a].closed=!0},CVShapeElement.prototype.renderInnerContent=function(){this.transformHelper.opacity=1,this.transformHelper._opMdf=!1,this.renderModifiers(),this.transformsManager.processSequences(this._isFirstFrame),this.renderShape(this.transformHelper,this.shapesData,this.itemsData,!0)},CVShapeElement.prototype.renderShapeTransform=function(t,e){(t._opMdf||e.op._mdf||this._isFirstFrame)&&(e.opacity=t.opacity,e.opacity*=e.op.v,e._opMdf=!0)},CVShapeElement.prototype.drawLayer=function(){var t,e,r,i,s,a,n,o,h,p=this.stylesList.length,l=this.globalData.renderer,m=this.globalData.canvasContext;for(t=0;t<p;t+=1)if(("st"!==(o=(h=this.stylesList[t]).type)&&"gs"!==o||0!==h.wi)&&h.data._shouldRender&&0!==h.coOp&&0!==this.globalData.currentGlobalAlpha){for(l.save(),a=h.elements,"st"===o||"gs"===o?(m.strokeStyle="st"===o?h.co:h.grd,m.lineWidth=h.wi,m.lineCap=h.lc,m.lineJoin=h.lj,m.miterLimit=h.ml||0):m.fillStyle="fl"===o?h.co:h.grd,l.ctxOpacity(h.coOp),"st"!==o&&"gs"!==o&&m.beginPath(),l.ctxTransform(h.preTransforms.finalTransform.props),r=a.length,e=0;e<r;e+=1){for("st"!==o&&"gs"!==o||(m.beginPath(),h.da&&(m.setLineDash(h.da),m.lineDashOffset=h.do)),s=(n=a[e].trNodes).length,i=0;i<s;i+=1)"m"==n[i].t?m.moveTo(n[i].p[0],n[i].p[1]):"c"==n[i].t?m.bezierCurveTo(n[i].pts[0],n[i].pts[1],n[i].pts[2],n[i].pts[3],n[i].pts[4],n[i].pts[5]):m.closePath();"st"!==o&&"gs"!==o||(m.stroke(),h.da&&m.setLineDash(this.dashResetter))}"st"!==o&&"gs"!==o&&m.fill(h.r),l.restore()}},CVShapeElement.prototype.renderShape=function(t,e,r,i){var s,a;for(a=t,s=e.length-1;0<=s;s-=1)"tr"==e[s].ty?(a=r[s].transform,this.renderShapeTransform(t,a)):"sh"==e[s].ty||"el"==e[s].ty||"rc"==e[s].ty||"sr"==e[s].ty?this.renderPath(e[s],r[s]):"fl"==e[s].ty?this.renderFill(e[s],r[s],a):"st"==e[s].ty?this.renderStroke(e[s],r[s],a):"gf"==e[s].ty||"gs"==e[s].ty?this.renderGradientFill(e[s],r[s],a):"gr"==e[s].ty?this.renderShape(a,e[s].it,r[s].it):e[s].ty;i&&this.drawLayer()},CVShapeElement.prototype.renderStyledShape=function(t,e){if(this._isFirstFrame||e._mdf||t.transforms._mdf){var r,i,s,a=t.trNodes,n=e.paths,o=n._length;a.length=0;var h=t.transforms.finalTransform;for(s=0;s<o;s+=1){var p=n.shapes[s];if(p&&p.v){for(i=p._length,r=1;r<i;r+=1)1===r&&a.push({t:"m",p:h.applyToPointArray(p.v[0][0],p.v[0][1],0)}),a.push({t:"c",pts:h.applyToTriplePoints(p.o[r-1],p.i[r],p.v[r])});1===i&&a.push({t:"m",p:h.applyToPointArray(p.v[0][0],p.v[0][1],0)}),p.c&&i&&(a.push({t:"c",pts:h.applyToTriplePoints(p.o[r-1],p.i[0],p.v[0])}),a.push({t:"z"}))}}t.trNodes=a}},CVShapeElement.prototype.renderPath=function(t,e){if(!0!==t.hd&&t._shouldRender){var r,i=e.styledShapes.length;for(r=0;r<i;r+=1)this.renderStyledShape(e.styledShapes[r],e.sh)}},CVShapeElement.prototype.renderFill=function(t,e,r){var i=e.style;(e.c._mdf||this._isFirstFrame)&&(i.co="rgb("+bm_floor(e.c.v[0])+","+bm_floor(e.c.v[1])+","+bm_floor(e.c.v[2])+")"),(e.o._mdf||r._opMdf||this._isFirstFrame)&&(i.coOp=e.o.v*r.opacity)},CVShapeElement.prototype.renderGradientFill=function(t,e,r){var i=e.style;if(!i.grd||e.g._mdf||e.s._mdf||e.e._mdf||1!==t.t&&(e.h._mdf||e.a._mdf)){var s=this.globalData.canvasContext,a=e.s.v,n=e.e.v;if(1===t.t)f=s.createLinearGradient(a[0],a[1],n[0],n[1]);else var o=Math.sqrt(Math.pow(a[0]-n[0],2)+Math.pow(a[1]-n[1],2)),h=Math.atan2(n[1]-a[1],n[0]-a[0]),p=o*(1<=e.h.v?.99:e.h.v<=-1?-.99:e.h.v),l=Math.cos(h+e.a.v)*p+a[0],m=Math.sin(h+e.a.v)*p+a[1],f=s.createRadialGradient(l,m,0,a[0],a[1],o);var c,d=t.g.p,u=e.g.c,y=1;for(c=0;c<d;c+=1)e.g._hasOpacity&&e.g._collapsable&&(y=e.g.o[2*c+1]),f.addColorStop(u[4*c]/100,"rgba("+u[4*c+1]+","+u[4*c+2]+","+u[4*c+3]+","+y+")");i.grd=f}i.coOp=e.o.v*r.opacity},CVShapeElement.prototype.renderStroke=function(t,e,r){var i=e.style,s=e.d;s&&(s._mdf||this._isFirstFrame)&&(i.da=s.dashArray,i.do=s.dashoffset[0]),(e.c._mdf||this._isFirstFrame)&&(i.co="rgb("+bm_floor(e.c.v[0])+","+bm_floor(e.c.v[1])+","+bm_floor(e.c.v[2])+")"),(e.o._mdf||r._opMdf||this._isFirstFrame)&&(i.coOp=e.o.v*r.opacity),(e.w._mdf||this._isFirstFrame)&&(i.wi=e.w.v)},CVShapeElement.prototype.destroy=function(){this.shapesData=null,this.globalData=null,this.canvasContext=null,this.stylesList.length=0,this.itemsData.length=0},extendPrototype([BaseElement,TransformElement,CVBaseElement,HierarchyElement,FrameElement,RenderableElement],CVSolidElement),CVSolidElement.prototype.initElement=SVGShapeElement.prototype.initElement,CVSolidElement.prototype.prepareFrame=IImageElement.prototype.prepareFrame,CVSolidElement.prototype.renderInnerContent=function(){var t=this.canvasContext;t.fillStyle=this.data.sc,t.fillRect(0,0,this.data.sw,this.data.sh)},CVEffects.prototype.renderFrame=function(){};var animationManager=(tJ={},uJ=[],vJ=0,wJ=0,xJ=0,yJ=!0,zJ=!1,tJ.registerAnimation=BJ,tJ.loadAnimation=function(t){var e=new AnimationItem;return FJ(e,null),e.setParams(t),e},tJ.setSpeed=function(t,e){var r;for(r=0;r<wJ;r+=1)uJ[r].animation.setSpeed(t,e)},tJ.setDirection=function(t,e){var r;for(r=0;r<wJ;r+=1)uJ[r].animation.setDirection(t,e)},tJ.play=function(t){var e;for(e=0;e<wJ;e+=1)uJ[e].animation.play(t)},tJ.pause=function(t){var e;for(e=0;e<wJ;e+=1)uJ[e].animation.pause(t)},tJ.stop=function(t){var e;for(e=0;e<wJ;e+=1)uJ[e].animation.stop(t)},tJ.togglePause=function(t){var e;for(e=0;e<wJ;e+=1)uJ[e].animation.togglePause(t)},tJ.searchAnimations=function(t,e,r){var i,s=[].concat([].slice.call(document.getElementsByClassName("lottie")),[].slice.call(document.getElementsByClassName("bodymovin"))),a=s.length;for(i=0;i<a;i+=1)r&&s[i].setAttribute("data-bm-type",r),BJ(s[i],t);if(e&&0===a){r||(r="svg");var n=document.getElementsByTagName("body")[0];n.innerHTML="";var o=createTag("div");o.style.width="100%",o.style.height="100%",o.setAttribute("data-bm-type",r),n.appendChild(o),BJ(o,t)}},tJ.resize=function(){var t;for(t=0;t<wJ;t+=1)uJ[t].animation.resize()},tJ.goToAndStop=function(t,e,r){var i;for(i=0;i<wJ;i+=1)uJ[i].animation.goToAndStop(t,e,r)},tJ.destroy=function(t){var e;for(e=wJ-1;0<=e;e-=1)uJ[e].animation.destroy(t)},tJ.freeze=function(){zJ=!0},tJ.unfreeze=function(){zJ=!1,TJ()},tJ.getRegisteredAnimations=function(){var t,e=uJ.length,r=[];for(t=0;t<e;t+=1)r.push(uJ[t].animation);return r},tJ),tJ,uJ,vJ,wJ,xJ,yJ,zJ,PK,QK,RK,SK,TK,UK,VK;function AJ(t){for(var e=0,r=t.target;e<wJ;)uJ[e].animation===r&&(uJ.splice(e,1),e-=1,wJ-=1,r.isPaused||EJ()),e+=1}function BJ(t,e){if(!t)return null;for(var r=0;r<wJ;){if(uJ[r].elem==t&&null!==uJ[r].elem)return uJ[r].animation;r+=1}var i=new AnimationItem;return FJ(i,t),i.setData(t,e),i}function DJ(){xJ+=1,TJ()}function EJ(){xJ-=1}function FJ(t,e){t.addEventListener("destroy",AJ),t.addEventListener("_active",DJ),t.addEventListener("_idle",EJ),uJ.push({elem:e,animation:t}),wJ+=1}function KJ(t){var e,r=t-vJ;for(e=0;e<wJ;e+=1)uJ[e].animation.advanceTime(r);vJ=t,xJ&&!zJ?window.requestAnimationFrame(KJ):yJ=!0}function LJ(t){vJ=t,window.requestAnimationFrame(KJ)}function TJ(){!zJ&&xJ&&yJ&&(window.requestAnimationFrame(LJ),yJ=!1)}function WK(t){for(var e=0,r=t.target;e<SK;)QK[e].animation===r&&(QK.splice(e,1),e-=1,SK-=1,r.isPaused||$K()),e+=1}function ZK(){TK+=1,nL()}function $K(){TK-=1}function _K(t,e){t.addEventListener("destroy",WK),t.addEventListener("_active",ZK),t.addEventListener("_idle",$K),QK.push({elem:e,animation:t}),SK+=1}function eL(t){var e,r=t-RK;for(e=0;e<SK;e+=1)QK[e].animation.advanceTime(r);RK=t,TK&&!VK?requestAnimationFrame(eL):UK=!0}function fL(t){RK=t,requestAnimationFrame(eL)}function nL(){!VK&&TK&&UK&&(requestAnimationFrame(fL),UK=!1)}PK={},QK=[],RK=0,SK=0,TK=0,UK=!0,VK=!1,PK.registerAnimation=function(t,e){if(!t)return null;for(var r=0;r<SK;){if(QK[r].elem==t&&null!==QK[r].elem)return QK[r].animation;r+=1}var i=new AnimationItem;return _K(i,t),i.setData(t,e),i},PK.loadAnimation=function(t){var e=new AnimationItem;return _K(e,null),e.setParams(t),e},PK.setSpeed=function(t,e){var r;for(r=0;r<SK;r+=1)QK[r].animation.setSpeed(t,e)},PK.setDirection=function(t,e){var r;for(r=0;r<SK;r+=1)QK[r].animation.setDirection(t,e)},PK.play=function(t){var e;for(e=0;e<SK;e+=1)QK[e].animation.play(t)},PK.pause=function(t){var e;for(e=0;e<SK;e+=1)QK[e].animation.pause(t)},PK.stop=function(t){var e;for(e=0;e<SK;e+=1)QK[e].animation.stop(t)},PK.togglePause=function(t){var e;for(e=0;e<SK;e+=1)QK[e].animation.togglePause(t)},PK.searchAnimations=function(t,e,r){throw new Error("Cannot access DOM from worker thread")},PK.resize=function(){var t;for(t=0;t<SK;t+=1)QK[t].animation.resize()},PK.goToAndStop=function(t,e,r){var i;for(i=0;i<SK;i+=1)QK[i].animation.goToAndStop(t,e,r)},PK.destroy=function(t){var e;for(e=SK-1;0<=e;e-=1)QK[e].animation.destroy(t)},PK.freeze=function(){VK=!0},PK.unfreeze=function(){VK=!1,nL()},PK.getRegisteredAnimations=function(){var t,e=QK.length,r=[];for(t=0;t<e;t+=1)r.push(QK[t].animation);return r},animationManager=PK;var AnimationItem=function(){this._cbs=[],this.name="",this.path="",this.isLoaded=!1,this.currentFrame=0,this.currentRawFrame=0,this.totalFrames=0,this.frameRate=0,this.frameMult=0,this.playSpeed=1,this.playDirection=1,this.playCount=0,this.animationData={},this.assets=[],this.isPaused=!0,this.autoplay=!1,this.loop=!0,this.renderer=null,this.animationID=createElementID(),this.assetsPath="",this.timeCompleted=0,this.segmentPos=0,this.subframeEnabled=subframeEnabled,this.segments=[],this._idle=!0,this._completedLoop=!1,this.projectInterface=ProjectInterface(),this.imagePreloader=new ImagePreloader};extendPrototype([BaseEvent],AnimationItem),AnimationItem.prototype.setParams=function(t){t.context&&(this.context=t.context),(t.wrapper||t.container)&&(this.wrapper=t.wrapper||t.container);var e=t.animType?t.animType:t.renderer?t.renderer:"svg";switch(e){case"canvas":this.renderer=new CanvasRenderer(this,t.rendererSettings);break;case"svg":this.renderer=new SVGRenderer(this,t.rendererSettings);break;default:this.renderer=new HybridRenderer(this,t.rendererSettings)}this.renderer.setProjectInterface(this.projectInterface),this.animType=e,""===t.loop||null===t.loop||(!1===t.loop?this.loop=!1:!0===t.loop?this.loop=!0:this.loop=parseInt(t.loop)),this.autoplay=!("autoplay"in t)||t.autoplay,this.name=t.name?t.name:"",this.autoloadSegments=!t.hasOwnProperty("autoloadSegments")||t.autoloadSegments,this.assetsPath=t.assetsPath,t.animationData?this.configAnimation(t.animationData):t.path&&("json"!=t.path.substr(-4)&&("/"!=t.path.substr(-1,1)&&(t.path+="/"),t.path+="data.json"),-1!=t.path.lastIndexOf("\\")?this.path=t.path.substr(0,t.path.lastIndexOf("\\")+1):this.path=t.path.substr(0,t.path.lastIndexOf("/")+1),this.fileName=t.path.substr(t.path.lastIndexOf("/")+1),this.fileName=this.fileName.substr(0,this.fileName.lastIndexOf(".json")),assetLoader.load(t.path,this.configAnimation.bind(this),function(){this.trigger("data_failed")}.bind(this)))},AnimationItem.prototype.setData=function(t,e){var r={wrapper:t,animationData:e?"object"==typeof e?e:JSON.parse(e):null},i=t.attributes;r.path=i.getNamedItem("data-animation-path")?i.getNamedItem("data-animation-path").value:i.getNamedItem("data-bm-path")?i.getNamedItem("data-bm-path").value:i.getNamedItem("bm-path")?i.getNamedItem("bm-path").value:"",r.animType=i.getNamedItem("data-anim-type")?i.getNamedItem("data-anim-type").value:i.getNamedItem("data-bm-type")?i.getNamedItem("data-bm-type").value:i.getNamedItem("bm-type")?i.getNamedItem("bm-type").value:i.getNamedItem("data-bm-renderer")?i.getNamedItem("data-bm-renderer").value:i.getNamedItem("bm-renderer")?i.getNamedItem("bm-renderer").value:"canvas";var s=i.getNamedItem("data-anim-loop")?i.getNamedItem("data-anim-loop").value:i.getNamedItem("data-bm-loop")?i.getNamedItem("data-bm-loop").value:i.getNamedItem("bm-loop")?i.getNamedItem("bm-loop").value:"";""===s||(r.loop="false"!==s&&("true"===s||parseInt(s)));var a=i.getNamedItem("data-anim-autoplay")?i.getNamedItem("data-anim-autoplay").value:i.getNamedItem("data-bm-autoplay")?i.getNamedItem("data-bm-autoplay").value:!i.getNamedItem("bm-autoplay")||i.getNamedItem("bm-autoplay").value;r.autoplay="false"!==a,r.name=i.getNamedItem("data-name")?i.getNamedItem("data-name").value:i.getNamedItem("data-bm-name")?i.getNamedItem("data-bm-name").value:i.getNamedItem("bm-name")?i.getNamedItem("bm-name").value:"","false"===(i.getNamedItem("data-anim-prerender")?i.getNamedItem("data-anim-prerender").value:i.getNamedItem("data-bm-prerender")?i.getNamedItem("data-bm-prerender").value:i.getNamedItem("bm-prerender")?i.getNamedItem("bm-prerender").value:"")&&(r.prerender=!1),this.setParams(r)},AnimationItem.prototype.includeLayers=function(t){t.op>this.animationData.op&&(this.animationData.op=t.op,this.totalFrames=Math.floor(t.op-this.animationData.ip));var e,r,i=this.animationData.layers,s=i.length,a=t.layers,n=a.length;for(r=0;r<n;r+=1)for(e=0;e<s;){if(i[e].id==a[r].id){i[e]=a[r];break}e+=1}if((t.chars||t.fonts)&&(this.renderer.globalData.fontManager.addChars(t.chars),this.renderer.globalData.fontManager.addFonts(t.fonts,this.renderer.globalData.defs)),t.assets)for(s=t.assets.length,e=0;e<s;e+=1)this.animationData.assets.push(t.assets[e]);this.animationData.__complete=!1,dataManager.completeData(this.animationData,this.renderer.globalData.fontManager),this.renderer.includeLayers(t.layers),expressionsPlugin&&expressionsPlugin.initExpressions(this),this.loadNextSegment()},AnimationItem.prototype.loadNextSegment=function(){var t=this.animationData.segments;if(!t||0===t.length||!this.autoloadSegments)return this.trigger("data_ready"),void(this.timeCompleted=this.totalFrames);var e=t.shift();this.timeCompleted=e.time*this.frameRate;var r=this.path+this.fileName+"_"+this.segmentPos+".json";this.segmentPos+=1,assetLoader.load(r,this.includeLayers.bind(this),function(){this.trigger("data_failed")}.bind(this))},AnimationItem.prototype.loadSegments=function(){this.animationData.segments||(this.timeCompleted=this.totalFrames),this.loadNextSegment()},AnimationItem.prototype.imagesLoaded=function(){this.trigger("loaded_images"),this.checkLoaded()},AnimationItem.prototype.preloadImages=function(){this.imagePreloader.setAssetsPath(this.assetsPath),this.imagePreloader.setPath(this.path),this.imagePreloader.loadAssets(this.animationData.assets,this.imagesLoaded.bind(this))},AnimationItem.prototype.configAnimation=function(t){this.renderer&&(this.animationData=t,this.totalFrames=Math.floor(this.animationData.op-this.animationData.ip),this.renderer.configAnimation(t),t.assets||(t.assets=[]),this.renderer.searchExtraCompositions(t.assets),this.assets=this.animationData.assets,this.frameRate=this.animationData.fr,this.firstFrame=Math.round(this.animationData.ip),this.frameMult=this.animationData.fr/1e3,this.trigger("config_ready"),this.preloadImages(),this.loadSegments(),this.updaFrameModifier(),this.waitForFontsLoaded())},AnimationItem.prototype.waitForFontsLoaded=function(){this.renderer&&(this.renderer.globalData.fontManager.loaded()?this.checkLoaded():setTimeout(this.waitForFontsLoaded.bind(this),20))},AnimationItem.prototype.checkLoaded=function(){this.isLoaded||!this.renderer.globalData.fontManager.loaded()||!this.imagePreloader.loaded()&&"canvas"===this.renderer.rendererType||(this.isLoaded=!0,dataManager.completeData(this.animationData,this.renderer.globalData.fontManager),expressionsPlugin&&expressionsPlugin.initExpressions(this),this.renderer.initItems(),setTimeout(function(){this.trigger("DOMLoaded")}.bind(this),0),this.gotoFrame(),this.autoplay&&this.play())},AnimationItem.prototype.resize=function(){this.renderer.updateContainerSize()},AnimationItem.prototype.setSubframe=function(t){this.subframeEnabled=!!t},AnimationItem.prototype.gotoFrame=function(){this.currentFrame=this.subframeEnabled?this.currentRawFrame:~~this.currentRawFrame,this.timeCompleted!==this.totalFrames&&this.currentFrame>this.timeCompleted&&(this.currentFrame=this.timeCompleted),this.trigger("enterFrame"),this.renderFrame()},AnimationItem.prototype.renderFrame=function(){!1!==this.isLoaded&&this.renderer.renderFrame(this.currentFrame+this.firstFrame)},AnimationItem.prototype.play=function(t){t&&this.name!=t||!0===this.isPaused&&(this.isPaused=!1,this._idle&&(this._idle=!1,this.trigger("_active")))},AnimationItem.prototype.pause=function(t){t&&this.name!=t||!1===this.isPaused&&(this.isPaused=!0,this._idle=!0,this.trigger("_idle"))},AnimationItem.prototype.togglePause=function(t){t&&this.name!=t||(!0===this.isPaused?this.play():this.pause())},AnimationItem.prototype.stop=function(t){t&&this.name!=t||(this.pause(),this.playCount=0,this._completedLoop=!1,this.setCurrentRawFrameValue(0))},AnimationItem.prototype.goToAndStop=function(t,e,r){r&&this.name!=r||(e?this.setCurrentRawFrameValue(t):this.setCurrentRawFrameValue(t*this.frameModifier),this.pause())},AnimationItem.prototype.goToAndPlay=function(t,e,r){this.goToAndStop(t,e,r),this.play()},AnimationItem.prototype.advanceTime=function(t){if(!0!==this.isPaused&&!1!==this.isLoaded){var e=this.currentRawFrame+t*this.frameModifier,r=!1;e>=this.totalFrames-1&&0<this.frameModifier?this.loop&&this.playCount!==this.loop?e>=this.totalFrames?(this.playCount+=1,this.checkSegments(e%this.totalFrames)||(this.setCurrentRawFrameValue(e%this.totalFrames),this._completedLoop=!0,this.trigger("loopComplete"))):this.setCurrentRawFrameValue(e):this.checkSegments(e>this.totalFrames?e%this.totalFrames:0)||(r=!0,e=this.totalFrames-1):e<0?this.checkSegments(e%this.totalFrames)||(!this.loop||this.playCount--<=0&&!0!==this.loop?(r=!0,e=0):(this.setCurrentRawFrameValue(this.totalFrames+e%this.totalFrames),this._completedLoop?this.trigger("loopComplete"):this._completedLoop=!0)):this.setCurrentRawFrameValue(e),r&&(this.setCurrentRawFrameValue(e),this.pause(),this.trigger("complete"))}},AnimationItem.prototype.adjustSegment=function(t,e){this.playCount=0,t[1]<t[0]?(0<this.frameModifier&&(this.playSpeed<0?this.setSpeed(-this.playSpeed):this.setDirection(-1)),this.timeCompleted=this.totalFrames=t[0]-t[1],this.firstFrame=t[1],this.setCurrentRawFrameValue(this.totalFrames-.001-e)):t[1]>t[0]&&(this.frameModifier<0&&(this.playSpeed<0?this.setSpeed(-this.playSpeed):this.setDirection(1)),this.timeCompleted=this.totalFrames=t[1]-t[0],this.firstFrame=t[0],this.setCurrentRawFrameValue(.001+e)),this.trigger("segmentStart")},AnimationItem.prototype.setSegment=function(t,e){var r=-1;this.isPaused&&(this.currentRawFrame+this.firstFrame<t?r=t:this.currentRawFrame+this.firstFrame>e&&(r=e-t)),this.firstFrame=t,this.timeCompleted=this.totalFrames=e-t,-1!==r&&this.goToAndStop(r,!0)},AnimationItem.prototype.playSegments=function(t,e){if(e&&(this.segments.length=0),"object"==typeof t[0]){var r,i=t.length;for(r=0;r<i;r+=1)this.segments.push(t[r])}else this.segments.push(t);this.segments.length&&e&&this.adjustSegment(this.segments.shift(),0),this.isPaused&&this.play()},AnimationItem.prototype.resetSegments=function(t){this.segments.length=0,this.segments.push([this.animationData.ip,this.animationData.op]),t&&this.checkSegments(0)},AnimationItem.prototype.checkSegments=function(t){return!!this.segments.length&&(this.adjustSegment(this.segments.shift(),t),!0)},AnimationItem.prototype.destroy=function(t){t&&this.name!=t||!this.renderer||(this.renderer.destroy(),this.imagePreloader.destroy(),this.trigger("destroy"),this._cbs=null,this.onEnterFrame=this.onLoopComplete=this.onComplete=this.onSegmentStart=this.onDestroy=null,this.renderer=null)},AnimationItem.prototype.setCurrentRawFrameValue=function(t){this.currentRawFrame=t,this.gotoFrame()},AnimationItem.prototype.setSpeed=function(t){this.playSpeed=t,this.updaFrameModifier()},AnimationItem.prototype.setDirection=function(t){this.playDirection=t<0?-1:1,this.updaFrameModifier()},AnimationItem.prototype.updaFrameModifier=function(){this.frameModifier=this.frameMult*this.playSpeed*this.playDirection},AnimationItem.prototype.getPath=function(){return this.path},AnimationItem.prototype.getAssetsPath=function(t){var e="";if(t.e)e=t.p;else if(this.assetsPath){var r=t.p;-1!==r.indexOf("images/")&&(r=r.split("/")[1]),e=this.assetsPath+r}else e=this.path,e+=t.u?t.u:"",e+=t.p;return e},AnimationItem.prototype.getAssetData=function(t){for(var e=0,r=this.assets.length;e<r;){if(t==this.assets[e].id)return this.assets[e];e+=1}},AnimationItem.prototype.hide=function(){this.renderer.hide()},AnimationItem.prototype.show=function(){this.renderer.show()},AnimationItem.prototype.getDuration=function(t){return t?this.totalFrames:this.totalFrames/this.frameRate},AnimationItem.prototype.trigger=function(t){if(this._cbs&&this._cbs[t])switch(t){case"enterFrame":this.triggerEvent(t,new BMEnterFrameEvent(t,this.currentFrame,this.totalFrames,this.frameModifier));break;case"loopComplete":this.triggerEvent(t,new BMCompleteLoopEvent(t,this.loop,this.playCount,this.frameMult));break;case"complete":this.triggerEvent(t,new BMCompleteEvent(t,this.frameMult));break;case"segmentStart":this.triggerEvent(t,new BMSegmentStartEvent(t,this.firstFrame,this.totalFrames));break;case"destroy":this.triggerEvent(t,new BMDestroyEvent(t,this));break;default:this.triggerEvent(t)}"enterFrame"===t&&this.onEnterFrame&&this.onEnterFrame.call(this,new BMEnterFrameEvent(t,this.currentFrame,this.totalFrames,this.frameMult)),"loopComplete"===t&&this.onLoopComplete&&this.onLoopComplete.call(this,new BMCompleteLoopEvent(t,this.loop,this.playCount,this.frameMult)),"complete"===t&&this.onComplete&&this.onComplete.call(this,new BMCompleteEvent(t,this.frameMult)),"segmentStart"===t&&this.onSegmentStart&&this.onSegmentStart.call(this,new BMSegmentStartEvent(t,this.firstFrame,this.totalFrames)),"destroy"===t&&this.onDestroy&&this.onDestroy.call(this,new BMDestroyEvent(t,this))},AnimationItem.prototype.setParams=function(t){t.context&&(this.context=t.context);var e=t.animType?t.animType:t.renderer?t.renderer:"svg";switch(e){case"canvas":this.renderer=new CanvasRenderer(this,t.rendererSettings);break;default:throw new Error("Only canvas renderer is supported when using worker.")}if(this.renderer.setProjectInterface(this.projectInterface),this.animType=e,""===t.loop||null===t.loop||(!1===t.loop?this.loop=!1:!0===t.loop?this.loop=!0:this.loop=parseInt(t.loop)),this.autoplay=!("autoplay"in t)||t.autoplay,this.name=t.name?t.name:"",this.autoloadSegments=!t.hasOwnProperty("autoloadSegments")||t.autoloadSegments,this.assetsPath=null,t.animationData)this.configAnimation(t.animationData);else if(t.path)throw new Error("Canvas worker renderer cannot load animation from url")},AnimationItem.prototype.setData=function(t,e){throw new Error("Cannot set data on wrapper for canvas worker renderer")},AnimationItem.prototype.includeLayers=function(t){t.op>this.animationData.op&&(this.animationData.op=t.op,this.totalFrames=Math.floor(t.op-this.animationData.ip));var e,r,i=this.animationData.layers,s=i.length,a=t.layers,n=a.length;for(r=0;r<n;r+=1)for(e=0;e<s;){if(i[e].id==a[r].id){i[e]=a[r];break}e+=1}this.animationData.__complete=!1,dataManager.completeData(this.animationData,this.renderer.globalData.fontManager),this.renderer.includeLayers(t.layers),expressionsPlugin&&expressionsPlugin.initExpressions(this),this.loadNextSegment()},AnimationItem.prototype.loadNextSegment=function(){var t=this.animationData.segments;if(t&&0!==t.length&&this.autoloadSegments)throw new Error("Cannot load multiple segments in worker.");this.timeCompleted=this.totalFrames},AnimationItem.prototype.loadSegments=function(){this.animationData.segments||(this.timeCompleted=this.totalFrames),this.loadNextSegment()},AnimationItem.prototype.imagesLoaded=null,AnimationItem.prototype.preloadImages=null,AnimationItem.prototype.configAnimation=function(t){this.renderer&&(this.animationData=t,this.totalFrames=Math.floor(this.animationData.op-this.animationData.ip),this.renderer.configAnimation(t),t.assets||(t.assets=[]),this.renderer.searchExtraCompositions(t.assets),this.assets=this.animationData.assets,this.frameRate=this.animationData.fr,this.firstFrame=Math.round(this.animationData.ip),this.frameMult=this.animationData.fr/1e3,this.loadSegments(),this.updaFrameModifier(),this.checkLoaded())},AnimationItem.prototype.waitForFontsLoaded=null,AnimationItem.prototype.checkLoaded=function(){this.isLoaded||(this.isLoaded=!0,dataManager.completeData(this.animationData,null),expressionsPlugin&&expressionsPlugin.initExpressions(this),this.renderer.initItems(),this.gotoFrame())},AnimationItem.prototype.destroy=function(t){t&&this.name!=t||!this.renderer||(this.renderer.destroy(),this._cbs=null,this.onEnterFrame=this.onLoopComplete=this.onComplete=this.onSegmentStart=this.onDestroy=null,this.renderer=null)},AnimationItem.prototype.getPath=null;var Expressions=(xN={},xN.initExpressions=function(t){var e=0,r=[];t.renderer.compInterface=CompExpressionInterface(t.renderer),t.renderer.globalData.projectInterface.registerComposition(t.renderer),t.renderer.globalData.pushExpression=function(){e+=1},t.renderer.globalData.popExpression=function(){0==(e-=1)&&function(){var t,e=r.length;for(t=0;t<e;t+=1)r[t].release();r.length=0}()},t.renderer.globalData.registerExpressionProperty=function(t){-1===r.indexOf(t)&&r.push(t)}},xN),xN;expressionsPlugin=Expressions;var ExpressionManager=function(){var ob={},Math=BMMath,window=null,document=null;function $bm_isInstanceOfArray(t){return t.constructor===Array||t.constructor===Float32Array}function isNumerable(t,e){return"number"===t||"boolean"===t||"string"===t||e instanceof Number}function $bm_neg(t){var e=typeof t;if("number"==e||"boolean"==e||t instanceof Number)return-t;if($bm_isInstanceOfArray(t)){var r,i=t.length,s=[];for(r=0;r<i;r+=1)s[r]=-t[r];return s}return t.propType?t.v:void 0}var easeInBez=BezierFactory.getBezierEasing(.333,0,.833,.833,"easeIn").get,easeOutBez=BezierFactory.getBezierEasing(.167,.167,.667,1,"easeOut").get,easeInOutBez=BezierFactory.getBezierEasing(.33,0,.667,1,"easeInOut").get;function sum(t,e){var r=typeof t,i=typeof e;if("string"==r||"string"==i)return t+e;if(isNumerable(r,t)&&isNumerable(i,e))return t+e;if($bm_isInstanceOfArray(t)&&isNumerable(i,e))return(t=t.slice(0))[0]=t[0]+e,t;if(isNumerable(r,t)&&$bm_isInstanceOfArray(e))return(e=e.slice(0))[0]=t+e[0],e;if($bm_isInstanceOfArray(t)&&$bm_isInstanceOfArray(e)){for(var s=0,a=t.length,n=e.length,o=[];s<a||s<n;)("number"==typeof t[s]||t[s]instanceof Number)&&("number"==typeof e[s]||e[s]instanceof Number)?o[s]=t[s]+e[s]:o[s]=void 0===e[s]?t[s]:t[s]||e[s],s+=1;return o}return 0}var add=sum;function sub(t,e){var r=typeof t,i=typeof e;if(isNumerable(r,t)&&isNumerable(i,e))return"string"==r&&(t=parseInt(t)),"string"==i&&(e=parseInt(e)),t-e;if($bm_isInstanceOfArray(t)&&isNumerable(i,e))return(t=t.slice(0))[0]=t[0]-e,t;if(isNumerable(r,t)&&$bm_isInstanceOfArray(e))return(e=e.slice(0))[0]=t-e[0],e;if($bm_isInstanceOfArray(t)&&$bm_isInstanceOfArray(e)){for(var s=0,a=t.length,n=e.length,o=[];s<a||s<n;)("number"==typeof t[s]||t[s]instanceof Number)&&("number"==typeof e[s]||e[s]instanceof Number)?o[s]=t[s]-e[s]:o[s]=void 0===e[s]?t[s]:t[s]||e[s],s+=1;return o}return 0}function mul(t,e){var r,i,s,a=typeof t,n=typeof e;if(isNumerable(a,t)&&isNumerable(n,e))return t*e;if($bm_isInstanceOfArray(t)&&isNumerable(n,e)){for(s=t.length,r=createTypedArray("float32",s),i=0;i<s;i+=1)r[i]=t[i]*e;return r}if(isNumerable(a,t)&&$bm_isInstanceOfArray(e)){for(s=e.length,r=createTypedArray("float32",s),i=0;i<s;i+=1)r[i]=t*e[i];return r}return 0}function div(t,e){var r,i,s,a=typeof t,n=typeof e;if(isNumerable(a,t)&&isNumerable(n,e))return t/e;if($bm_isInstanceOfArray(t)&&isNumerable(n,e)){for(s=t.length,r=createTypedArray("float32",s),i=0;i<s;i+=1)r[i]=t[i]/e;return r}if(isNumerable(a,t)&&$bm_isInstanceOfArray(e)){for(s=e.length,r=createTypedArray("float32",s),i=0;i<s;i+=1)r[i]=t/e[i];return r}return 0}function mod(t,e){return"string"==typeof t&&(t=parseInt(t)),"string"==typeof e&&(e=parseInt(e)),t%e}var $bm_sum=sum,$bm_sub=sub,$bm_mul=mul,$bm_div=div,$bm_mod=mod;function clamp(t,e,r){if(r<e){var i=r;r=e,e=i}return Math.min(Math.max(t,e),r)}function radiansToDegrees(t){return t/degToRads}var radians_to_degrees=radiansToDegrees;function degreesToRadians(t){return t*degToRads}var degrees_to_radians=radiansToDegrees,helperLengthArray=[0,0,0,0,0,0];function length(t,e){if("number"==typeof t||t instanceof Number)return e=e||0,Math.abs(t-e);e||(e=helperLengthArray);var r,i=Math.min(t.length,e.length),s=0;for(r=0;r<i;r+=1)s+=Math.pow(e[r]-t[r],2);return Math.sqrt(s)}function normalize(t){return div(t,length(t))}function rgbToHsl(t){var e,r,i=t[0],s=t[1],a=t[2],n=Math.max(i,s,a),o=Math.min(i,s,a),h=(n+o)/2;if(n==o)e=r=0;else{var p=n-o;switch(r=.5<h?p/(2-n-o):p/(n+o),n){case i:e=(s-a)/p+(s<a?6:0);break;case s:e=(a-i)/p+2;break;case a:e=(i-s)/p+4}e/=6}return[e,r,h,t[3]]}function hue2rgb(t,e,r){return r<0&&(r+=1),1<r&&(r-=1),r<1/6?t+6*(e-t)*r:r<.5?e:r<2/3?t+(e-t)*(2/3-r)*6:t}function hslToRgb(t){var e,r,i,s=t[0],a=t[1],n=t[2];if(0===a)e=r=i=n;else{var o=n<.5?n*(1+a):n+a-n*a,h=2*n-o;e=hue2rgb(h,o,s+1/3),r=hue2rgb(h,o,s),i=hue2rgb(h,o,s-1/3)}return[e,r,i,t[3]]}function linear(t,e,r,i,s){if(void 0!==i&&void 0!==s||(i=e,s=r,e=0,r=1),r<e){var a=r;r=e,e=a}if(t<=e)return i;if(r<=t)return s;var n=r===e?0:(t-e)/(r-e);if(!i.length)return i+(s-i)*n;var o,h=i.length,p=createTypedArray("float32",h);for(o=0;o<h;o+=1)p[o]=i[o]+(s[o]-i[o])*n;return p}function random(t,e){if(void 0===e&&(void 0===t?(t=0,e=1):(e=t,t=void 0)),e.length){var r,i=e.length;t||(t=createTypedArray("float32",i));var s=createTypedArray("float32",i),a=BMMath.random();for(r=0;r<i;r+=1)s[r]=t[r]+a*(e[r]-t[r]);return s}return void 0===t&&(t=0),t+BMMath.random()*(e-t)}function createPath(t,e,r,i){var s,a=t.length,n=shape_pool.newElement();n.setPathData(!!i,a);var o,h,p=[0,0];for(s=0;s<a;s+=1)o=e&&e[s]?e[s]:p,h=r&&r[s]?r[s]:p,n.setTripleAt(t[s][0],t[s][1],h[0]+t[s][0],h[1]+t[s][1],o[0]+t[s][0],o[1]+t[s][1],s,!0);return n}function initiateExpression(elem,data,property){var val=data.x,needsVelocity=/velocity(?![\w\d])/.test(val),_needsRandom=-1!==val.indexOf("random"),elemType=elem.data.ty,transform,$bm_transform,content,effect,thisProperty=property;thisProperty.valueAtTime=thisProperty.getValueAtTime,Object.defineProperty(thisProperty,"value",{get:function(){return thisProperty.v}}),elem.comp.frameDuration=1/elem.comp.globalData.frameRate,elem.comp.displayStartTime=0;var inPoint=elem.data.ip/elem.comp.globalData.frameRate,outPoint=elem.data.op/elem.comp.globalData.frameRate,width=elem.data.sw?elem.data.sw:0,height=elem.data.sh?elem.data.sh:0,name=elem.data.nm,loopIn,loop_in,loopOut,loop_out,smooth,toWorld,fromWorld,fromComp,toComp,fromCompToSurface,position,rotation,anchorPoint,scale,thisLayer,thisComp,mask,valueAtTime,velocityAtTime,__expression_functions=[],scoped_bm_rt;if(data.xf){var i,len=data.xf.length;for(i=0;i<len;i+=1)__expression_functions[i]=eval("(function(){ return "+data.xf[i]+"}())")}var expression_function=eval("[function _expression_function(){"+val+";scoped_bm_rt=$bm_rt}]")[0],numKeys=property.kf?data.k.length:0,active=!this.data||!0!==this.data.hd,wiggle=function(t,e){var r,i,s=this.pv.length?this.pv.length:1,a=createTypedArray("float32",s);var n=Math.floor(5*time);for(i=r=0;r<n;){for(i=0;i<s;i+=1)a[i]+=-e+2*e*BMMath.random();r+=1}var o=5*time,h=o-Math.floor(o),p=createTypedArray("float32",s);if(1<s){for(i=0;i<s;i+=1)p[i]=this.pv[i]+a[i]+(-e+2*e*BMMath.random())*h;return p}return this.pv+a[0]+(-e+2*e*BMMath.random())*h}.bind(this);function loopInDuration(t,e){return loopIn(t,e,!0)}function loopOutDuration(t,e){return loopOut(t,e,!0)}thisProperty.loopIn&&(loopIn=thisProperty.loopIn.bind(thisProperty),loop_in=loopIn),thisProperty.loopOut&&(loopOut=thisProperty.loopOut.bind(thisProperty),loop_out=loopOut),thisProperty.smooth&&(smooth=thisProperty.smooth.bind(thisProperty)),this.getValueAtTime&&(valueAtTime=this.getValueAtTime.bind(this)),this.getVelocityAtTime&&(velocityAtTime=this.getVelocityAtTime.bind(this));var comp=elem.comp.globalData.projectInterface.bind(elem.comp.globalData.projectInterface),time,velocity,value,text,textIndex,textTotal,selectorValue;function lookAt(t,e){var r=[e[0]-t[0],e[1]-t[1],e[2]-t[2]],i=Math.atan2(r[0],Math.sqrt(r[1]*r[1]+r[2]*r[2]))/degToRads;return[-Math.atan2(r[1],r[2])/degToRads,i,0]}function easeOut(t,e,r,i,s){return applyEase(easeOutBez,t,e,r,i,s)}function easeIn(t,e,r,i,s){return applyEase(easeInBez,t,e,r,i,s)}function ease(t,e,r,i,s){return applyEase(easeInOutBez,t,e,r,i,s)}function applyEase(t,e,r,i,s,a){void 0===s?(s=r,a=i):e=(e-r)/(i-r);var n=t(e=1<e?1:e<0?0:e);if($bm_isInstanceOfArray(s)){var o,h=s.length,p=createTypedArray("float32",h);for(o=0;o<h;o+=1)p[o]=(a[o]-s[o])*n+s[o];return p}return(a-s)*n+s}function nearestKey(t){var e,r,i,s=data.k.length;if(data.k.length&&"number"!=typeof data.k[0])if(r=-1,(t*=elem.comp.globalData.frameRate)<data.k[0].t)r=1,i=data.k[0].t;else{for(e=0;e<s-1;e+=1){if(t===data.k[e].t){r=e+1,i=data.k[e].t;break}if(t>data.k[e].t&&t<data.k[e+1].t){i=t-data.k[e].t>data.k[e+1].t-t?(r=e+2,data.k[e+1].t):(r=e+1,data.k[e].t);break}}-1===r&&(r=e+1,i=data.k[e].t)}else i=r=0;var a={};return a.index=r,a.time=i/elem.comp.globalData.frameRate,a}function key(t){var e,r,i,s;if(!data.k.length||"number"==typeof data.k[0])throw new Error("The property has no keyframe at index "+t);for(t-=1,e={time:data.k[t].t/elem.comp.globalData.frameRate,value:[]},i=(s=t!==data.k.length-1||data.k[t].h?data.k[t].s:data.k[t].s||0===data.k[t].s?data.k[t-1].s:data.k[t].e).length,r=0;r<i;r+=1)e[r]=s[r],e.value[r]=s[r];return e}function framesToTime(t,e){return e||(e=elem.comp.globalData.frameRate),t/e}function timeToFrames(t,e){return t||0===t||(t=time),e||(e=elem.comp.globalData.frameRate),t*e}function seedRandom(t){BMMath.seedrandom(randSeed+t)}function sourceRectAtTime(){return elem.sourceRectAtTime()}function substring(t,e){return"string"==typeof value?void 0===e?value.substring(t):value.substring(t,e):""}function substr(t,e){return"string"==typeof value?void 0===e?value.substr(t):value.substr(t,e):""}var index=elem.data.ind,hasParent=!(!elem.hierarchy||!elem.hierarchy.length),parent,randSeed=Math.floor(1e6*Math.random()),globalData=elem.globalData;function executeExpression(t){return value=t,_needsRandom&&seedRandom(randSeed),this.frameExpressionId===elem.globalData.frameId&&"textSelector"!==this.propType?value:("textSelector"===this.propType&&(textIndex=this.textIndex,textTotal=this.textTotal,selectorValue=this.selectorValue),thisLayer||(text=elem.layerInterface.text,thisLayer=elem.layerInterface,thisComp=elem.comp.compInterface,toWorld=thisLayer.toWorld.bind(thisLayer),fromWorld=thisLayer.fromWorld.bind(thisLayer),fromComp=thisLayer.fromComp.bind(thisLayer),toComp=thisLayer.toComp.bind(thisLayer),mask=thisLayer.mask?thisLayer.mask.bind(thisLayer):null,fromCompToSurface=fromComp),transform||(transform=elem.layerInterface("ADBE Transform Group"),($bm_transform=transform)&&(anchorPoint=transform.anchorPoint)),4!==elemType||content||(content=thisLayer("ADBE Root Vectors Group")),effect||(effect=thisLayer(4)),(hasParent=!(!elem.hierarchy||!elem.hierarchy.length))&&!parent&&(parent=elem.hierarchy[0].layerInterface),time=this.comp.renderedFrame/this.comp.globalData.frameRate,needsVelocity&&(velocity=velocityAtTime(time)),expression_function(),this.frameExpressionId=elem.globalData.frameId,"shape"===scoped_bm_rt.propType&&(scoped_bm_rt=scoped_bm_rt.v),scoped_bm_rt)}return executeExpression}return ob.initiateExpression=initiateExpression,ob}(),expressionHelpers={searchExpressions:function(t,e,r){e.x&&(r.k=!0,r.x=!0,r.initiateExpression=ExpressionManager.initiateExpression,r.effectsSequence.push(r.initiateExpression(t,e,r).bind(r)))},getSpeedAtTime:function(t){var e=this.getValueAtTime(t),r=this.getValueAtTime(t+-.01),i=0;if(e.length){var s;for(s=0;s<e.length;s+=1)i+=Math.pow(r[s]-e[s],2);i=100*Math.sqrt(i)}else i=0;return i},getVelocityAtTime:function(t){if(void 0!==this.vel)return this.vel;var e,r,i=this.getValueAtTime(t),s=this.getValueAtTime(t+-.001);if(i.length)for(e=createTypedArray("float32",i.length),r=0;r<i.length;r+=1)e[r]=(s[r]-i[r])/-.001;else e=(s-i)/-.001;return e},getValueAtTime:function(t){return t*=this.elem.globalData.frameRate,(t-=this.offsetTime)!==this._cachingAtTime.lastFrame&&(this._cachingAtTime.lastIndex=this._cachingAtTime.lastFrame<t?this._cachingAtTime.lastIndex:0,this._cachingAtTime.value=this.interpolateValue(t,this._cachingAtTime),this._cachingAtTime.lastFrame=t),this._cachingAtTime.value},getStaticValueAtTime:function(){return this.pv},setGroupProperty:function(t){this.propertyGroup=t}};!function(){function o(t,e,r){if(!this.k||!this.keyframes)return this.pv;t=t?t.toLowerCase():"";var i,s,a,n,o,h=this.comp.renderedFrame,p=this.keyframes,l=p[p.length-1].t;if(h<=l)return this.pv;if(r?s=l-(i=e?Math.abs(l-elem.comp.globalData.frameRate*e):Math.max(0,l-this.elem.data.ip)):((!e||e>p.length-1)&&(e=p.length-1),i=l-(s=p[p.length-1-e].t)),"pingpong"===t){if(Math.floor((h-s)/i)%2!=0)return this.getValueAtTime((i-(h-s)%i+s)/this.comp.globalData.frameRate,0)}else{if("offset"===t){var m=this.getValueAtTime(s/this.comp.globalData.frameRate,0),f=this.getValueAtTime(l/this.comp.globalData.frameRate,0),c=this.getValueAtTime(((h-s)%i+s)/this.comp.globalData.frameRate,0),d=Math.floor((h-s)/i);if(this.pv.length){for(n=(o=new Array(m.length)).length,a=0;a<n;a+=1)o[a]=(f[a]-m[a])*d+c[a];return o}return(f-m)*d+c}if("continue"===t){var u=this.getValueAtTime(l/this.comp.globalData.frameRate,0),y=this.getValueAtTime((l-.001)/this.comp.globalData.frameRate,0);if(this.pv.length){for(n=(o=new Array(u.length)).length,a=0;a<n;a+=1)o[a]=u[a]+(u[a]-y[a])*((h-l)/this.comp.globalData.frameRate)/5e-4;return o}return u+(h-l)/.001*(u-y)}}return this.getValueAtTime(((h-s)%i+s)/this.comp.globalData.frameRate,0)}function h(t,e,r){if(!this.k)return this.pv;t=t?t.toLowerCase():"";var i,s,a,n,o,h=this.comp.renderedFrame,p=this.keyframes,l=p[0].t;if(l<=h)return this.pv;if(r?s=l+(i=e?Math.abs(elem.comp.globalData.frameRate*e):Math.max(0,this.elem.data.op-l)):((!e||e>p.length-1)&&(e=p.length-1),i=(s=p[e].t)-l),"pingpong"===t){if(Math.floor((l-h)/i)%2==0)return this.getValueAtTime(((l-h)%i+l)/this.comp.globalData.frameRate,0)}else{if("offset"===t){var m=this.getValueAtTime(l/this.comp.globalData.frameRate,0),f=this.getValueAtTime(s/this.comp.globalData.frameRate,0),c=this.getValueAtTime((i-(l-h)%i+l)/this.comp.globalData.frameRate,0),d=Math.floor((l-h)/i)+1;if(this.pv.length){for(n=(o=new Array(m.length)).length,a=0;a<n;a+=1)o[a]=c[a]-(f[a]-m[a])*d;return o}return c-(f-m)*d}if("continue"===t){var u=this.getValueAtTime(l/this.comp.globalData.frameRate,0),y=this.getValueAtTime((l+.001)/this.comp.globalData.frameRate,0);if(this.pv.length){for(n=(o=new Array(u.length)).length,a=0;a<n;a+=1)o[a]=u[a]+(u[a]-y[a])*(l-h)/.001;return o}return u+(u-y)*(l-h)/.001}}return this.getValueAtTime((i-(l-h)%i+l)/this.comp.globalData.frameRate,0)}function p(t,e){if(!this.k)return this.pv;if(t=.5*(t||.4),(e=Math.floor(e||5))<=1)return this.pv;var r,i,s=this.comp.renderedFrame/this.comp.globalData.frameRate,a=s-t,n=1<e?(s+t-a)/(e-1):1,o=0,h=0;for(r=this.pv.length?createTypedArray("float32",this.pv.length):0;o<e;){if(i=this.getValueAtTime(a+o*n),this.pv.length)for(h=0;h<this.pv.length;h+=1)r[h]+=i[h];else r+=i;o+=1}if(this.pv.length)for(h=0;h<this.pv.length;h+=1)r[h]/=e;else r/=e;return r}var s=TransformPropertyFactory.getTransformProperty;TransformPropertyFactory.getTransformProperty=function(t,e,r){var i=s(t,e,r);return i.dynamicProperties.length?i.getValueAtTime=function(t){console.warn("Transform at time not supported")}.bind(i):i.getValueAtTime=function(t){}.bind(i),i.setGroupProperty=expressionHelpers.setGroupProperty,i};var l=PropertyFactory.getProp;PropertyFactory.getProp=function(t,e,r,i,s){var a=l(t,e,r,i,s);a.kf?a.getValueAtTime=expressionHelpers.getValueAtTime.bind(a):a.getValueAtTime=expressionHelpers.getStaticValueAtTime.bind(a),a.setGroupProperty=expressionHelpers.setGroupProperty,a.loopOut=o,a.loopIn=h,a.smooth=p,a.getVelocityAtTime=expressionHelpers.getVelocityAtTime.bind(a),a.getSpeedAtTime=expressionHelpers.getSpeedAtTime.bind(a),a.numKeys=1===e.a?e.k.length:0,a.propertyIndex=e.ix;var n=0;return 0!==r&&(n=createTypedArray("float32",1===e.a?e.k[0].s.length:e.k.length)),a._cachingAtTime={lastFrame:initialDefaultFrame,lastIndex:0,value:n},expressionHelpers.searchExpressions(t,e,a),a.k&&s.addDynamicProperty(a),a};var t=ShapePropertyFactory.getConstructorFunction(),e=ShapePropertyFactory.getKeyframedConstructorFunction();function r(){}r.prototype={vertices:function(t,e){this.k&&this.getValue();var r=this.v;void 0!==e&&(r=this.getValueAtTime(e,0));var i,s=r._length,a=r[t],n=r.v,o=createSizedArray(s);for(i=0;i<s;i+=1)o[i]="i"===t||"o"===t?[a[i][0]-n[i][0],a[i][1]-n[i][1]]:[a[i][0],a[i][1]];return o},points:function(t){return this.vertices("v",t)},inTangents:function(t){return this.vertices("i",t)},outTangents:function(t){return this.vertices("o",t)},isClosed:function(){return this.v.c},pointOnPath:function(t,e){var r=this.v;void 0!==e&&(r=this.getValueAtTime(e,0)),this._segmentsLength||(this._segmentsLength=bez.getSegmentsLength(r));for(var i,s=this._segmentsLength,a=s.lengths,n=s.totalLength*t,o=0,h=a.length,p=0;o<h;){if(p+a[o].addedLength>n){var l=o,m=r.c&&o===h-1?0:o+1,f=(n-p)/a[o].addedLength;i=bez.getPointInSegment(r.v[l],r.v[m],r.o[l],r.i[m],f,a[o]);break}p+=a[o].addedLength,o+=1}return i||(i=r.c?[r.v[0][0],r.v[0][1]]:[r.v[r._length-1][0],r.v[r._length-1][1]]),i},vectorOnPath:function(t,e,r){t=1==t?this.v.c?0:.999:t;var i=this.pointOnPath(t,e),s=this.pointOnPath(t+.001,e),a=s[0]-i[0],n=s[1]-i[1],o=Math.sqrt(Math.pow(a,2)+Math.pow(n,2));return"tangent"===r?[a/o,n/o]:[-n/o,a/o]},tangentOnPath:function(t,e){return this.vectorOnPath(t,e,"tangent")},normalOnPath:function(t,e){return this.vectorOnPath(t,e,"normal")},setGroupProperty:expressionHelpers.setGroupProperty,getValueAtTime:expressionHelpers.getStaticValueAtTime},extendPrototype([r],t),extendPrototype([r],e),e.prototype.getValueAtTime=function(t){return this._cachingAtTime||(this._cachingAtTime={shapeValue:shape_pool.clone(this.pv),lastIndex:0,lastTime:initialDefaultFrame}),t*=this.elem.globalData.frameRate,(t-=this.offsetTime)!==this._cachingAtTime.lastTime&&(this._cachingAtTime.lastIndex=this._cachingAtTime.lastTime<t?this._caching.lastIndex:0,this._cachingAtTime.lastTime=t,this.interpolateShape(t,this._cachingAtTime.shapeValue,this._cachingAtTime)),this._cachingAtTime.shapeValue},e.prototype.initiateExpression=ExpressionManager.initiateExpression;var n=ShapePropertyFactory.getShapeProp;ShapePropertyFactory.getShapeProp=function(t,e,r,i,s){var a=n(t,e,r,i,s);return a.propertyIndex=e.ix,a.lock=!1,3===r?expressionHelpers.searchExpressions(t,e.pt,a):4===r&&expressionHelpers.searchExpressions(t,e.ks,a),a.k&&t.addDynamicProperty(a),a}}(),TextProperty.prototype.getExpressionValue=function(t,e){var r=this.calculateExpression(e);if(t.t===r)return t;var i={};return this.copyData(i,t),i.t=r.toString(),i.__complete=!1,i},TextProperty.prototype.searchProperty=function(){var t=this.searchKeyframes(),e=this.searchExpressions();return this.kf=t||e,this.kf},TextProperty.prototype.searchExpressions=function(){if(this.data.d.x)return this.calculateExpression=ExpressionManager.initiateExpression.bind(this)(this.elem,this.data.d,this),this.addEffect(this.getExpressionValue.bind(this)),!0};var ShapeExpressionInterface=function(t,e,r){var i;function s(t){if("number"==typeof t)return i[t-1];for(var e=0,r=i.length;e<r;){if(i[e]._name===t)return i[e];e+=1}}return s.propertyGroup=r,i=DT(t,e,s),s.numProperties=i.length,s};function DT(t,e,r){var i,s=[],a=t?t.length:0;for(i=0;i<a;i+=1)"gr"==t[i].ty?s.push(FT(t[i],e[i],r)):"fl"==t[i].ty?s.push(GT(t[i],e[i],r)):"st"==t[i].ty?s.push(HT(t[i],e[i],r)):"tm"==t[i].ty?s.push(IT(t[i],e[i],r)):"tr"==t[i].ty||("el"==t[i].ty?s.push(KT(t[i],e[i],r)):"sr"==t[i].ty?s.push(LT(t[i],e[i],r)):"sh"==t[i].ty?s.push(PT(t[i],e[i],r)):"rc"==t[i].ty?s.push(MT(t[i],e[i],r)):"rd"==t[i].ty?s.push(NT(t[i],e[i],r)):"rp"==t[i].ty&&s.push(OT(t[i],e[i],r)));return s}function FT(t,e,r){var i=function(t){switch(t){case"ADBE Vectors Group":case"Contents":case 2:return i.content;default:return i.transform}};i.propertyGroup=function(t){return 1===t?i:r(t-1)};var s=function(t,e,r){function i(t){for(var e=0,r=s.length;e<r;){if(s[e]._name===t||s[e].mn===t||s[e].propertyIndex===t||s[e].ix===t||s[e].ind===t)return s[e];e+=1}if("number"==typeof t)return s[t-1]}var s;return i.propertyGroup=function(t){return 1===t?i:r(t-1)},s=DT(t.it,e.it,i.propertyGroup),i.numProperties=s.length,i.propertyIndex=t.cix,i._name=t.nm,i}(t,e,i.propertyGroup),a=function(e,t,r){function i(t){return 1==t?s:r(--t)}t.transform.mProps.o.setGroupProperty(i),t.transform.mProps.p.setGroupProperty(i),t.transform.mProps.a.setGroupProperty(i),t.transform.mProps.s.setGroupProperty(i),t.transform.mProps.r.setGroupProperty(i),t.transform.mProps.sk&&(t.transform.mProps.sk.setGroupProperty(i),t.transform.mProps.sa.setGroupProperty(i));function s(t){return e.a.ix===t||"Anchor Point"===t?s.anchorPoint:e.o.ix===t||"Opacity"===t?s.opacity:e.p.ix===t||"Position"===t?s.position:e.r.ix===t||"Rotation"===t||"ADBE Vector Rotation"===t?s.rotation:e.s.ix===t||"Scale"===t?s.scale:e.sk&&e.sk.ix===t||"Skew"===t?s.skew:e.sa&&e.sa.ix===t||"Skew Axis"===t?s.skewAxis:void 0}return t.transform.op.setGroupProperty(i),Object.defineProperties(s,{opacity:{get:ExpressionPropertyInterface(t.transform.mProps.o)},position:{get:ExpressionPropertyInterface(t.transform.mProps.p)},anchorPoint:{get:ExpressionPropertyInterface(t.transform.mProps.a)},scale:{get:ExpressionPropertyInterface(t.transform.mProps.s)},rotation:{get:ExpressionPropertyInterface(t.transform.mProps.r)},skew:{get:ExpressionPropertyInterface(t.transform.mProps.sk)},skewAxis:{get:ExpressionPropertyInterface(t.transform.mProps.sa)},_name:{value:e.nm}}),s.ty="tr",s.mn=e.mn,s.propertyGroup=r,s}(t.it[t.it.length-1],e.it[e.it.length-1],i.propertyGroup);return i.content=s,i.transform=a,Object.defineProperty(i,"_name",{get:function(){return t.nm}}),i.numProperties=t.np,i.propertyIndex=t.ix,i.nm=t.nm,i.mn=t.mn,i}function GT(t,e,r){function i(t){return"Color"===t||"color"===t?i.color:"Opacity"===t||"opacity"===t?i.opacity:void 0}return Object.defineProperties(i,{color:{get:ExpressionPropertyInterface(e.c)},opacity:{get:ExpressionPropertyInterface(e.o)},_name:{value:t.nm},mn:{value:t.mn}}),e.c.setGroupProperty(r),e.o.setGroupProperty(r),i}function HT(t,e,r){function i(t){return 1===t?ob:r(t-1)}function s(t){return 1===t?h:i(t-1)}var a,n,o=t.d?t.d.length:0,h={};for(a=0;a<o;a+=1)n=a,Object.defineProperty(h,t.d[n].nm,{get:ExpressionPropertyInterface(e.d.dataProps[n].p)}),e.d.dataProps[a].p.setGroupProperty(s);function p(t){return"Color"===t||"color"===t?p.color:"Opacity"===t||"opacity"===t?p.opacity:"Stroke Width"===t||"stroke width"===t?p.strokeWidth:void 0}return Object.defineProperties(p,{color:{get:ExpressionPropertyInterface(e.c)},opacity:{get:ExpressionPropertyInterface(e.o)},strokeWidth:{get:ExpressionPropertyInterface(e.w)},dash:{get:function(){return h}},_name:{value:t.nm},mn:{value:t.mn}}),e.c.setGroupProperty(i),e.o.setGroupProperty(i),e.w.setGroupProperty(i),p}function IT(e,t,r){function i(t){return 1==t?s:r(--t)}function s(t){return t===e.e.ix||"End"===t||"end"===t?s.end:t===e.s.ix?s.start:t===e.o.ix?s.offset:void 0}return s.propertyIndex=e.ix,t.s.setGroupProperty(i),t.e.setGroupProperty(i),t.o.setGroupProperty(i),s.propertyIndex=e.ix,s.propertyGroup=r,Object.defineProperties(s,{start:{get:ExpressionPropertyInterface(t.s)},end:{get:ExpressionPropertyInterface(t.e)},offset:{get:ExpressionPropertyInterface(t.o)},_name:{value:e.nm}}),s.mn=e.mn,s}function KT(e,t,r){function i(t){return 1==t?a:r(--t)}a.propertyIndex=e.ix;var s="tm"===t.sh.ty?t.sh.prop:t.sh;function a(t){return e.p.ix===t?a.position:e.s.ix===t?a.size:void 0}return s.s.setGroupProperty(i),s.p.setGroupProperty(i),Object.defineProperties(a,{size:{get:ExpressionPropertyInterface(s.s)},position:{get:ExpressionPropertyInterface(s.p)},_name:{value:e.nm}}),a.mn=e.mn,a}function LT(e,t,r){function i(t){return 1==t?a:r(--t)}var s="tm"===t.sh.ty?t.sh.prop:t.sh;function a(t){return e.p.ix===t?a.position:e.r.ix===t?a.rotation:e.pt.ix===t?a.points:e.or.ix===t||"ADBE Vector Star Outer Radius"===t?a.outerRadius:e.os.ix===t?a.outerRoundness:!e.ir||e.ir.ix!==t&&"ADBE Vector Star Inner Radius"!==t?e.is&&e.is.ix===t?a.innerRoundness:void 0:a.innerRadius}return a.propertyIndex=e.ix,s.or.setGroupProperty(i),s.os.setGroupProperty(i),s.pt.setGroupProperty(i),s.p.setGroupProperty(i),s.r.setGroupProperty(i),e.ir&&(s.ir.setGroupProperty(i),s.is.setGroupProperty(i)),Object.defineProperties(a,{position:{get:ExpressionPropertyInterface(s.p)},rotation:{get:ExpressionPropertyInterface(s.r)},points:{get:ExpressionPropertyInterface(s.pt)},outerRadius:{get:ExpressionPropertyInterface(s.or)},outerRoundness:{get:ExpressionPropertyInterface(s.os)},innerRadius:{get:ExpressionPropertyInterface(s.ir)},innerRoundness:{get:ExpressionPropertyInterface(s.is)},_name:{value:e.nm}}),a.mn=e.mn,a}function MT(e,t,r){function i(t){return 1==t?a:r(--t)}var s="tm"===t.sh.ty?t.sh.prop:t.sh;function a(t){return e.p.ix===t?a.position:e.r.ix===t?a.roundness:e.s.ix===t||"Size"===t||"ADBE Vector Rect Size"===t?a.size:void 0}return a.propertyIndex=e.ix,s.p.setGroupProperty(i),s.s.setGroupProperty(i),s.r.setGroupProperty(i),Object.defineProperties(a,{position:{get:ExpressionPropertyInterface(s.p)},roundness:{get:ExpressionPropertyInterface(s.r)},size:{get:ExpressionPropertyInterface(s.s)},_name:{value:e.nm}}),a.mn=e.mn,a}function NT(e,t,r){var i=t;function s(t){if(e.r.ix===t||"Round Corners 1"===t)return s.radius}return s.propertyIndex=e.ix,i.rd.setGroupProperty(function(t){return 1==t?s:r(--t)}),Object.defineProperties(s,{radius:{get:ExpressionPropertyInterface(i.rd)},_name:{value:e.nm}}),s.mn=e.mn,s}function OT(e,t,r){function i(t){return 1==t?a:r(--t)}var s=t;function a(t){return e.c.ix===t||"Copies"===t?a.copies:e.o.ix===t||"Offset"===t?a.offset:void 0}return a.propertyIndex=e.ix,s.c.setGroupProperty(i),s.o.setGroupProperty(i),Object.defineProperties(a,{copies:{get:ExpressionPropertyInterface(s.c)},offset:{get:ExpressionPropertyInterface(s.o)},_name:{value:e.nm}}),a.mn=e.mn,a}function PT(t,e,r){var i=e.sh;function s(t){if("Shape"===t||"shape"===t||"Path"===t||"path"===t||"ADBE Vector Shape"===t||2===t)return s.path}return i.setGroupProperty(function(t){return 1==t?s:r(--t)}),Object.defineProperties(s,{path:{get:function(){return i.k&&i.getValue(),i}},shape:{get:function(){return i.k&&i.getValue(),i}},_name:{value:t.nm},ix:{value:t.ix},mn:{value:t.mn}}),s}var TextExpressionInterface=function(e){var r;function t(){}return Object.defineProperty(t,"sourceText",{get:function(){e.textProperty.getValue();var t=e.textProperty.currentData.t;return void 0!==t&&(e.textProperty.currentData.t=void 0,(r=new String(t)).value=t||new String(t)),r}}),t},LayerExpressionInterface=function(e){var r;function i(t){switch(t){case"ADBE Root Vectors Group":case"Contents":case 2:return i.shapeInterface;case 1:case 6:case"Transform":case"transform":case"ADBE Transform Group":return r;case 4:case"ADBE Effect Parade":case"effects":case"Effects":return i.effect}}i.toWorld=_V,i.fromWorld=aW,i.toComp=_V,i.fromComp=bW,i.sampleImage=cW,i.sourceRectAtTime=e.sourceRectAtTime.bind(e);var t=getDescriptor(r=TransformExpressionInterface((i._elem=e).finalTransform.mProp),"anchorPoint");return Object.defineProperties(i,{hasParent:{get:function(){return e.hierarchy.length}},parent:{get:function(){return e.hierarchy[0].layerInterface}},rotation:getDescriptor(r,"rotation"),scale:getDescriptor(r,"scale"),position:getDescriptor(r,"position"),opacity:getDescriptor(r,"opacity"),anchorPoint:t,anchor_point:t,transform:{get:function(){return r}},active:{get:function(){return e.isInRange}}}),i.startTime=e.data.st,i.index=e.data.ind,i.source=e.data.refId,i.height=0===e.data.ty?e.data.h:100,i.width=0===e.data.ty?e.data.w:100,i.inPoint=e.data.ip/e.comp.globalData.frameRate,i.outPoint=e.data.op/e.comp.globalData.frameRate,i._name=e.data.nm,i.registerMaskInterface=function(t){i.mask=new MaskManagerInterface(t,e)},i.registerEffectsInterface=function(t){i.effect=t},i};function _V(t,e){var r=new Matrix;if(r.reset(),this._elem.finalTransform.mProp.applyToMatrix(r),this._elem.hierarchy&&this._elem.hierarchy.length){var i,s=this._elem.hierarchy.length;for(i=0;i<s;i+=1)this._elem.hierarchy[i].finalTransform.mProp.applyToMatrix(r);return r.applyToPointArray(t[0],t[1],t[2]||0)}return r.applyToPointArray(t[0],t[1],t[2]||0)}function aW(t,e){var r=new Matrix;if(r.reset(),this._elem.finalTransform.mProp.applyToMatrix(r),this._elem.hierarchy&&this._elem.hierarchy.length){var i,s=this._elem.hierarchy.length;for(i=0;i<s;i+=1)this._elem.hierarchy[i].finalTransform.mProp.applyToMatrix(r);return r.inversePoint(t)}return r.inversePoint(t)}function bW(t){var e=new Matrix;if(e.reset(),this._elem.finalTransform.mProp.applyToMatrix(e),this._elem.hierarchy&&this._elem.hierarchy.length){var r,i=this._elem.hierarchy.length;for(r=0;r<i;r+=1)this._elem.hierarchy[r].finalTransform.mProp.applyToMatrix(e);return e.inversePoint(t)}return e.inversePoint(t)}function cW(){return[1,1,1,1]}var CompExpressionInterface=function(i){function t(t){for(var e=0,r=i.layers.length;e<r;){if(i.layers[e].nm===t||i.layers[e].ind===t)return i.elements[e].layerInterface;e+=1}return null}return Object.defineProperty(t,"_name",{value:i.data.nm}),(t.layer=t).pixelAspect=1,t.height=i.data.h||i.globalData.compSize.h,t.width=i.data.w||i.globalData.compSize.w,t.pixelAspect=1,t.frameDuration=1/i.globalData.frameRate,t.displayStartTime=0,t.numLayers=i.layers.length,t},TransformExpressionInterface=function(t){function e(t){switch(t){case"scale":case"Scale":case"ADBE Scale":case 6:return e.scale;case"rotation":case"Rotation":case"ADBE Rotation":case"ADBE Rotate Z":case 10:return e.rotation;case"ADBE Rotate X":return e.xRotation;case"ADBE Rotate Y":return e.yRotation;case"position":case"Position":case"ADBE Position":case 2:return e.position;case"ADBE Position_0":return e.xPosition;case"ADBE Position_1":return e.yPosition;case"ADBE Position_2":return e.zPosition;case"anchorPoint":case"AnchorPoint":case"Anchor Point":case"ADBE AnchorPoint":case 1:return e.anchorPoint;case"opacity":case"Opacity":case 11:return e.opacity}}if(Object.defineProperty(e,"rotation",{get:ExpressionPropertyInterface(t.r||t.rz)}),Object.defineProperty(e,"zRotation",{get:ExpressionPropertyInterface(t.rz||t.r)}),Object.defineProperty(e,"xRotation",{get:ExpressionPropertyInterface(t.rx)}),Object.defineProperty(e,"yRotation",{get:ExpressionPropertyInterface(t.ry)}),Object.defineProperty(e,"scale",{get:ExpressionPropertyInterface(t.s)}),t.p)var r=ExpressionPropertyInterface(t.p);return Object.defineProperty(e,"position",{get:function(){return t.p?r():[t.px.v,t.py.v,t.pz?t.pz.v:0]}}),Object.defineProperty(e,"xPosition",{get:ExpressionPropertyInterface(t.px)}),Object.defineProperty(e,"yPosition",{get:ExpressionPropertyInterface(t.py)}),Object.defineProperty(e,"zPosition",{get:ExpressionPropertyInterface(t.pz)}),Object.defineProperty(e,"anchorPoint",{get:ExpressionPropertyInterface(t.a)}),Object.defineProperty(e,"opacity",{get:ExpressionPropertyInterface(t.o)}),Object.defineProperty(e,"skew",{get:ExpressionPropertyInterface(t.sk)}),Object.defineProperty(e,"skewAxis",{get:ExpressionPropertyInterface(t.sa)}),Object.defineProperty(e,"orientation",{get:ExpressionPropertyInterface(t.or)}),e},ProjectInterface=function(){function t(t){for(var e=0,r=this.compositions.length;e<r;){if(this.compositions[e].data&&this.compositions[e].data.nm===t)return this.compositions[e].prepareFrame&&this.compositions[e].data.xt&&this.compositions[e].prepareFrame(this.currentFrame),this.compositions[e].compInterface;e+=1}}return t.compositions=[],t.currentFrame=0,t.registerComposition=LW,t};function LW(t){this.compositions.push(t)}var EffectsExpressionInterface={createEffectsInterface:function(s,t){if(s.effectsManager){var e,a=[],r=s.data.ef,i=s.effectsManager.effectElements.length;for(e=0;e<i;e+=1)a.push(TW(r[e],s.effectsManager.effectElements[e],t,s));return function(t){for(var e=s.data.ef||[],r=0,i=e.length;r<i;){if(t===e[r].nm||t===e[r].mn||t===e[r].ix)return a[r];r+=1}}}}};function TW(s,t,e,r){var i,a=[],n=s.ef.length;for(i=0;i<n;i+=1)5===s.ef[i].ty?a.push(TW(s.ef[i],t.effectElements[i],t.effectElements[i].propertyGroup,r)):a.push(UW(t.effectElements[i],s.ef[i].ty,r,o));function o(t){return 1===t?h:e(t-1)}var h=function(t){for(var e=s.ef,r=0,i=e.length;r<i;){if(t===e[r].nm||t===e[r].mn||t===e[r].ix)return 5===e[r].ty?a[r]:a[r]();r+=1}return a[0]()};return h.propertyGroup=o,"ADBE Color Control"===s.mn&&Object.defineProperty(h,"color",{get:function(){return a[0]()}}),Object.defineProperty(h,"numProperties",{get:function(){return s.np}}),h.active=h.enabled=0!==s.en,h}function UW(t,e,r,i){var s=ExpressionPropertyInterface(t.p);return t.p.setGroupProperty&&t.p.setGroupProperty(i),function(){return 10===e?r.comp.compInterface(t.p.v):s()}}var MaskManagerInterface=function(){function a(t,e){this._mask=t,this._data=e}Object.defineProperty(a.prototype,"maskPath",{get:function(){return this._mask.prop.k&&this._mask.prop.getValue(),this._mask.prop}});return function(e,t){var r,i=createSizedArray(e.viewData.length),s=e.viewData.length;for(r=0;r<s;r+=1)i[r]=new a(e.viewData[r],e.masksProperties[r]);return function(t){for(r=0;r<s;){if(e.masksProperties[r].nm===t)return i[r];r+=1}}}}(),ExpressionPropertyInterface=(KX={pv:0,v:0,mult:1},LX={pv:[0,0,0],v:[0,0,0],mult:1},function(t){return t?"unidimensional"===t.propType?function(t){t&&"pv"in t||(t=KX);var e=1/t.mult,r=t.pv*e,i=new Number(r);return i.value=r,MX(i,t,"unidimensional"),function(){return t.k&&t.getValue(),r=t.v*e,i.value!==r&&((i=new Number(r)).value=r,MX(i,t,"unidimensional")),i}}(t):function(e){e&&"pv"in e||(e=LX);var r=1/e.mult,i=e.pv.length,s=createTypedArray("float32",i),a=createTypedArray("float32",i);return s.value=a,MX(s,e,"multidimensional"),function(){e.k&&e.getValue();for(var t=0;t<i;t+=1)s[t]=a[t]=e.v[t]*r;return s}}(t):PX}),KX,LX,fY,gY;function MX(i,s,a){Object.defineProperty(i,"velocity",{get:function(){return s.getVelocityAtTime(s.comp.currentFrame)}}),i.numKeys=s.keyframes?s.keyframes.length:0,i.key=function(t){if(i.numKeys){var e="";e="s"in s.keyframes[t-1]?s.keyframes[t-1].s:"e"in s.keyframes[t-2]?s.keyframes[t-2].e:s.keyframes[t-2].s;var r="unidimensional"===a?new Number(e):Object.assign({},e);return r.time=s.keyframes[t-1].t/s.elem.comp.globalData.frameRate,r}return 0},i.valueAtTime=s.getValueAtTime,i.speedAtTime=s.getSpeedAtTime,i.velocityAtTime=s.getVelocityAtTime,i.propertyGroup=s.propertyGroup}function PX(){return KX}function hY(t,e){return this.textIndex=t+1,this.textTotal=e,this.v=this.getValue()*this.mult,this.v}function SliderEffect(t,e,r){this.p=PropertyFactory.getProp(e,t.v,0,0,r)}function AngleEffect(t,e,r){this.p=PropertyFactory.getProp(e,t.v,0,0,r)}function ColorEffect(t,e,r){this.p=PropertyFactory.getProp(e,t.v,1,0,r)}function PointEffect(t,e,r){this.p=PropertyFactory.getProp(e,t.v,1,0,r)}function LayerIndexEffect(t,e,r){this.p=PropertyFactory.getProp(e,t.v,0,0,r)}function MaskIndexEffect(t,e,r){this.p=PropertyFactory.getProp(e,t.v,0,0,r)}function CheckboxEffect(t,e,r){this.p=PropertyFactory.getProp(e,t.v,0,0,r)}function NoValueEffect(){this.p={}}function EffectsManager(t,e){var r=t.ef||[];this.effectElements=[];var i,s,a=r.length;for(i=0;i<a;i++)s=new GroupEffect(r[i],e),this.effectElements.push(s)}function GroupEffect(t,e){this.init(t,e)}fY=function(t,e){this.pv=1,this.comp=t.comp,this.elem=t,this.mult=.01,this.propType="textSelector",this.textTotal=e.totalChars,this.selectorValue=100,this.lastValue=[1,1,1],this.k=!0,this.x=!0,this.getValue=ExpressionManager.initiateExpression.bind(this)(t,e,this),this.getMult=hY,this.getVelocityAtTime=expressionHelpers.getVelocityAtTime,this.kf?this.getValueAtTime=expressionHelpers.getValueAtTime.bind(this):this.getValueAtTime=expressionHelpers.getStaticValueAtTime.bind(this),this.setGroupProperty=expressionHelpers.setGroupProperty},gY=TextSelectorProp.getTextSelectorProp,TextSelectorProp.getTextSelectorProp=function(t,e,r){return 1===e.t?new fY(t,e,r):gY(t,e,r)},extendPrototype([DynamicPropertyContainer],GroupEffect),GroupEffect.prototype.getValue=GroupEffect.prototype.iterateDynamicProperties,GroupEffect.prototype.init=function(t,e){this.data=t,this.effectElements=[],this.initDynamicPropertyContainer(e);var r,i,s=this.data.ef.length,a=this.data.ef;for(r=0;r<s;r+=1){switch(i=null,a[r].ty){case 0:i=new SliderEffect(a[r],e,this);break;case 1:i=new AngleEffect(a[r],e,this);break;case 2:i=new ColorEffect(a[r],e,this);break;case 3:i=new PointEffect(a[r],e,this);break;case 4:case 7:i=new CheckboxEffect(a[r],e,this);break;case 10:i=new LayerIndexEffect(a[r],e,this);break;case 11:i=new MaskIndexEffect(a[r],e,this);break;case 5:i=new EffectsManager(a[r],e,this);break;default:i=new NoValueEffect(a[r],e,this)}i&&this.effectElements.push(i)}};var lottiejs={},_isFrozen=!1;function loadAnimation(t){return animationManager.loadAnimation(t)}function setQuality(t){if("string"==typeof t)switch(t){case"high":defaultCurveSegments=200;break;case"medium":defaultCurveSegments=50;break;case"low":defaultCurveSegments=10}else!isNaN(t)&&1<t&&(defaultCurveSegments=t);roundValues(!(50<=defaultCurveSegments))}lottiejs.play=animationManager.play,lottiejs.pause=animationManager.pause,lottiejs.togglePause=animationManager.togglePause,lottiejs.setSpeed=animationManager.setSpeed,lottiejs.setDirection=animationManager.setDirection,lottiejs.stop=animationManager.stop,lottiejs.registerAnimation=animationManager.registerAnimation,lottiejs.loadAnimation=loadAnimation,lottiejs.resize=animationManager.resize,lottiejs.goToAndStop=animationManager.goToAndStop,lottiejs.destroy=animationManager.destroy,lottiejs.setQuality=setQuality,lottiejs.freeze=animationManager.freeze,lottiejs.unfreeze=animationManager.unfreeze,lottiejs.getRegisteredAnimations=animationManager.getRegisteredAnimations,lottiejs.version="5.5.2";var renderer="";return lottiejs}({}),currentAnimation=null;onmessage=function(t){if(t&&t.data){var e=null;if(currentAnimation)e=currentAnimation.renderer.canvasContext.canvas;else{if(!t.data.canvas)return;e=t.data.canvas}if(t.data.drawSize&&(e.height=t.data.drawSize.height,e.width=t.data.drawSize.width,currentAnimation&&currentAnimation.resize()),!currentAnimation){if(!t.data.animationData||!t.data.params)return;var r=t.data.params,i=e.getContext("2d");(currentAnimation=lottiejs.loadAnimation({renderer:"canvas",loop:r.loop,autoplay:r.autoplay,animationData:t.data.animationData,rendererSettings:{context:i,scaleMode:"noScale",clearCanvas:!0}})).play()}}};
\ No newline at end of file
+var lottiejs=function(window){"use strict";var svgNS="http://www.w3.org/2000/svg",locationHref="",initialDefaultFrame=-999999,subframeEnabled=!0,expressionsPlugin,isSafari=/^((?!chrome|android).)*safari/i.test(navigator.userAgent),cachedColors={},bm_rounder=Math.round,bm_rnd,bm_pow=Math.pow,bm_sqrt=Math.sqrt,bm_abs=Math.abs,bm_floor=Math.floor,bm_max=Math.max,bm_min=Math.min,blitter=10,BMMath={};function ProjectInterface(){return{}}!function(){var t,e=["abs","acos","acosh","asin","asinh","atan","atanh","atan2","ceil","cbrt","expm1","clz32","cos","cosh","exp","floor","fround","hypot","imul","log","log1p","log2","log10","max","min","pow","random","round","sign","sin","sinh","sqrt","tan","tanh","trunc","E","LN10","LN2","LOG10E","LOG2E","PI","SQRT1_2","SQRT2"],r=e.length;for(t=0;t<r;t+=1)BMMath[e[t]]=Math[e[t]]}(),BMMath.random=Math.random,BMMath.abs=function(t){if("object"==typeof t&&t.length){var e,r=createSizedArray(t.length),i=t.length;for(e=0;e<i;e+=1)r[e]=Math.abs(t[e]);return r}return Math.abs(t)};var defaultCurveSegments=150,degToRads=Math.PI/180,roundCorner=.5519;function roundValues(t){bm_rnd=t?Math.round:function(t){return t}}function styleDiv(t){t.style.position="absolute",t.style.top=0,t.style.left=0,t.style.display="block",t.style.transformOrigin=t.style.webkitTransformOrigin="0 0",t.style.backfaceVisibility=t.style.webkitBackfaceVisibility="visible",t.style.transformStyle=t.style.webkitTransformStyle=t.style.mozTransformStyle="preserve-3d"}function BMEnterFrameEvent(t,e,r,i){this.type=t,this.currentTime=e,this.totalTime=r,this.direction=i<0?-1:1}function BMCompleteEvent(t,e){this.type=t,this.direction=e<0?-1:1}function BMCompleteLoopEvent(t,e,r,i){this.type=t,this.currentLoop=r,this.totalLoops=e,this.direction=i<0?-1:1}function BMSegmentStartEvent(t,e,r){this.type=t,this.firstFrame=e,this.totalFrames=r}function BMDestroyEvent(t,e){this.type=t,this.target=e}roundValues(!1);var createElementID=(B=0,function(){return"__lottie_element_"+ ++B}),B;function HSVtoRGB(t,e,r){var i,s,a,n,o,h,p,l;switch(h=r*(1-e),p=r*(1-(o=6*t-(n=Math.floor(6*t)))*e),l=r*(1-(1-o)*e),n%6){case 0:i=r,s=l,a=h;break;case 1:i=p,s=r,a=h;break;case 2:i=h,s=r,a=l;break;case 3:i=h,s=p,a=r;break;case 4:i=l,s=h,a=r;break;case 5:i=r,s=h,a=p}return[i,s,a]}function RGBtoHSV(t,e,r){var i,s=Math.max(t,e,r),a=Math.min(t,e,r),n=s-a,o=0===s?0:n/s,h=s/255;switch(s){case a:i=0;break;case t:i=e-r+n*(e<r?6:0),i/=6*n;break;case e:i=r-t+2*n,i/=6*n;break;case r:i=t-e+4*n,i/=6*n}return[i,o,h]}function addSaturationToRGB(t,e){var r=RGBtoHSV(255*t[0],255*t[1],255*t[2]);return r[1]+=e,1<r[1]?r[1]=1:r[1]<=0&&(r[1]=0),HSVtoRGB(r[0],r[1],r[2])}function addBrightnessToRGB(t,e){var r=RGBtoHSV(255*t[0],255*t[1],255*t[2]);return r[2]+=e,1<r[2]?r[2]=1:r[2]<0&&(r[2]=0),HSVtoRGB(r[0],r[1],r[2])}function addHueToRGB(t,e){var r=RGBtoHSV(255*t[0],255*t[1],255*t[2]);return r[0]+=e/360,1<r[0]?r[0]-=1:r[0]<0&&(r[0]+=1),HSVtoRGB(r[0],r[1],r[2])}var rgbToHex=function(){var t,e,i=[];for(t=0;t<256;t+=1)e=t.toString(16),i[t]=1==e.length?"0"+e:e;return function(t,e,r){return t<0&&(t=0),e<0&&(e=0),r<0&&(r=0),"#"+i[t]+i[e]+i[r]}}();function BaseEvent(){}BaseEvent.prototype={triggerEvent:function(t,e){if(this._cbs[t])for(var r=this._cbs[t].length,i=0;i<r;i++)this._cbs[t][i](e)},addEventListener:function(t,e){return this._cbs[t]||(this._cbs[t]=[]),this._cbs[t].push(e),function(){this.removeEventListener(t,e)}.bind(this)},removeEventListener:function(t,e){if(e){if(this._cbs[t]){for(var r=0,i=this._cbs[t].length;r<i;)this._cbs[t][r]===e&&(this._cbs[t].splice(r,1),r-=1,i-=1),r+=1;this._cbs[t].length||(this._cbs[t]=null)}}else this._cbs[t]=null}};var createTypedArray="function"==typeof Uint8ClampedArray&&"function"==typeof Float32Array?function(t,e){return"float32"===t?new Float32Array(e):"int16"===t?new Int16Array(e):"uint8c"===t?new Uint8ClampedArray(e):void 0}:function(t,e){var r,i=0,s=[];switch(t){case"int16":case"uint8c":r=1;break;default:r=1.1}for(i=0;i<e;i+=1)s.push(r);return s};function createSizedArray(t){return Array.apply(null,{length:t})}function createTag(t){return document.createElement(t)}function DynamicPropertyContainer(){}DynamicPropertyContainer.prototype={addDynamicProperty:function(t){-1===this.dynamicProperties.indexOf(t)&&(this.dynamicProperties.push(t),this.container.addDynamicProperty(this),this._isAnimated=!0)},iterateDynamicProperties:function(){this._mdf=!1;var t,e=this.dynamicProperties.length;for(t=0;t<e;t+=1)this.dynamicProperties[t].getValue(),this.dynamicProperties[t]._mdf&&(this._mdf=!0)},initDynamicPropertyContainer:function(t){this.container=t,this.dynamicProperties=[],this._mdf=!1,this._isAnimated=!1}};var getBlendMode=(Ja={0:"source-over",1:"multiply",2:"screen",3:"overlay",4:"darken",5:"lighten",6:"color-dodge",7:"color-burn",8:"hard-light",9:"soft-light",10:"difference",11:"exclusion",12:"hue",13:"saturation",14:"color",15:"luminosity"},function(t){return Ja[t]||""}),Ja,Matrix=(La=Math.cos,Ma=Math.sin,Na=Math.tan,Oa=Math.round,function(){this.reset=Pa,this.rotate=Qa,this.rotateX=Ra,this.rotateY=Sa,this.rotateZ=Ta,this.skew=Va,this.skewFromAxis=Wa,this.shear=Ua,this.scale=Xa,this.setTransform=Ya,this.translate=Za,this.transform=$a,this.applyToPoint=db,this.applyToX=eb,this.applyToY=fb,this.applyToZ=gb,this.applyToPointArray=kb,this.applyToTriplePoints=jb,this.applyToPointStringified=lb,this.toCSS=mb,this.to2dCSS=pb,this.clone=bb,this.cloneFromProps=cb,this.equals=ab,this.inversePoints=ib,this.inversePoint=hb,this._t=this.transform,this.isIdentity=_a,this._identity=!0,this._identityCalculated=!1,this.props=createTypedArray("float32",16),this.reset()}),La,Ma,Na,Oa;function Pa(){return this.props[0]=1,this.props[1]=0,this.props[2]=0,this.props[3]=0,this.props[4]=0,this.props[5]=1,this.props[6]=0,this.props[7]=0,this.props[8]=0,this.props[9]=0,this.props[10]=1,this.props[11]=0,this.props[12]=0,this.props[13]=0,this.props[14]=0,this.props[15]=1,this}function Qa(t){if(0===t)return this;var e=La(t),r=Ma(t);return this._t(e,-r,0,0,r,e,0,0,0,0,1,0,0,0,0,1)}function Ra(t){if(0===t)return this;var e=La(t),r=Ma(t);return this._t(1,0,0,0,0,e,-r,0,0,r,e,0,0,0,0,1)}function Sa(t){if(0===t)return this;var e=La(t),r=Ma(t);return this._t(e,0,r,0,0,1,0,0,-r,0,e,0,0,0,0,1)}function Ta(t){if(0===t)return this;var e=La(t),r=Ma(t);return this._t(e,-r,0,0,r,e,0,0,0,0,1,0,0,0,0,1)}function Ua(t,e){return this._t(1,e,t,1,0,0)}function Va(t,e){return this.shear(Na(t),Na(e))}function Wa(t,e){var r=La(e),i=Ma(e);return this._t(r,i,0,0,-i,r,0,0,0,0,1,0,0,0,0,1)._t(1,0,0,0,Na(t),1,0,0,0,0,1,0,0,0,0,1)._t(r,-i,0,0,i,r,0,0,0,0,1,0,0,0,0,1)}function Xa(t,e,r){return r||0===r||(r=1),1===t&&1===e&&1===r?this:this._t(t,0,0,0,0,e,0,0,0,0,r,0,0,0,0,1)}function Ya(t,e,r,i,s,a,n,o,h,p,l,m,f,c,d,u){return this.props[0]=t,this.props[1]=e,this.props[2]=r,this.props[3]=i,this.props[4]=s,this.props[5]=a,this.props[6]=n,this.props[7]=o,this.props[8]=h,this.props[9]=p,this.props[10]=l,this.props[11]=m,this.props[12]=f,this.props[13]=c,this.props[14]=d,this.props[15]=u,this}function Za(t,e,r){return r=r||0,0!==t||0!==e||0!==r?this._t(1,0,0,0,0,1,0,0,0,0,1,0,t,e,r,1):this}function $a(t,e,r,i,s,a,n,o,h,p,l,m,f,c,d,u){var y=this.props;if(1===t&&0===e&&0===r&&0===i&&0===s&&1===a&&0===n&&0===o&&0===h&&0===p&&1===l&&0===m)return y[12]=y[12]*t+y[15]*f,y[13]=y[13]*a+y[15]*c,y[14]=y[14]*l+y[15]*d,y[15]=y[15]*u,this._identityCalculated=!1,this;var g=y[0],v=y[1],P=y[2],b=y[3],x=y[4],_=y[5],S=y[6],T=y[7],A=y[8],C=y[9],E=y[10],k=y[11],D=y[12],I=y[13],M=y[14],w=y[15];return y[0]=g*t+v*s+P*h+b*f,y[1]=g*e+v*a+P*p+b*c,y[2]=g*r+v*n+P*l+b*d,y[3]=g*i+v*o+P*m+b*u,y[4]=x*t+_*s+S*h+T*f,y[5]=x*e+_*a+S*p+T*c,y[6]=x*r+_*n+S*l+T*d,y[7]=x*i+_*o+S*m+T*u,y[8]=A*t+C*s+E*h+k*f,y[9]=A*e+C*a+E*p+k*c,y[10]=A*r+C*n+E*l+k*d,y[11]=A*i+C*o+E*m+k*u,y[12]=D*t+I*s+M*h+w*f,y[13]=D*e+I*a+M*p+w*c,y[14]=D*r+I*n+M*l+w*d,y[15]=D*i+I*o+M*m+w*u,this._identityCalculated=!1,this}function _a(){return this._identityCalculated||(this._identity=!(1!==this.props[0]||0!==this.props[1]||0!==this.props[2]||0!==this.props[3]||0!==this.props[4]||1!==this.props[5]||0!==this.props[6]||0!==this.props[7]||0!==this.props[8]||0!==this.props[9]||1!==this.props[10]||0!==this.props[11]||0!==this.props[12]||0!==this.props[13]||0!==this.props[14]||1!==this.props[15]),this._identityCalculated=!0),this._identity}function ab(t){for(var e=0;e<16;){if(t.props[e]!==this.props[e])return!1;e+=1}return!0}function bb(t){var e;for(e=0;e<16;e+=1)t.props[e]=this.props[e]}function cb(t){var e;for(e=0;e<16;e+=1)this.props[e]=t[e]}function db(t,e,r){return{x:t*this.props[0]+e*this.props[4]+r*this.props[8]+this.props[12],y:t*this.props[1]+e*this.props[5]+r*this.props[9]+this.props[13],z:t*this.props[2]+e*this.props[6]+r*this.props[10]+this.props[14]}}function eb(t,e,r){return t*this.props[0]+e*this.props[4]+r*this.props[8]+this.props[12]}function fb(t,e,r){return t*this.props[1]+e*this.props[5]+r*this.props[9]+this.props[13]}function gb(t,e,r){return t*this.props[2]+e*this.props[6]+r*this.props[10]+this.props[14]}function hb(t){var e=this.props[0]*this.props[5]-this.props[1]*this.props[4],r=this.props[5]/e,i=-this.props[1]/e,s=-this.props[4]/e,a=this.props[0]/e,n=(this.props[4]*this.props[13]-this.props[5]*this.props[12])/e,o=-(this.props[0]*this.props[13]-this.props[1]*this.props[12])/e;return[t[0]*r+t[1]*s+n,t[0]*i+t[1]*a+o,0]}function ib(t){var e,r=t.length,i=[];for(e=0;e<r;e+=1)i[e]=hb(t[e]);return i}function jb(t,e,r){var i=createTypedArray("float32",6);if(this.isIdentity())i[0]=t[0],i[1]=t[1],i[2]=e[0],i[3]=e[1],i[4]=r[0],i[5]=r[1];else{var s=this.props[0],a=this.props[1],n=this.props[4],o=this.props[5],h=this.props[12],p=this.props[13];i[0]=t[0]*s+t[1]*n+h,i[1]=t[0]*a+t[1]*o+p,i[2]=e[0]*s+e[1]*n+h,i[3]=e[0]*a+e[1]*o+p,i[4]=r[0]*s+r[1]*n+h,i[5]=r[0]*a+r[1]*o+p}return i}function kb(t,e,r){return this.isIdentity()?[t,e,r]:[t*this.props[0]+e*this.props[4]+r*this.props[8]+this.props[12],t*this.props[1]+e*this.props[5]+r*this.props[9]+this.props[13],t*this.props[2]+e*this.props[6]+r*this.props[10]+this.props[14]]}function lb(t,e){if(this.isIdentity())return t+","+e;var r=this.props;return Math.round(100*(t*r[0]+e*r[4]+r[12]))/100+","+Math.round(100*(t*r[1]+e*r[5]+r[13]))/100}function mb(){for(var t=0,e=this.props,r="matrix3d(";t<16;)r+=Oa(1e4*e[t])/1e4,r+=15===t?")":",",t+=1;return r}function nb(t){return t<1e-6&&0<t||-1e-6<t&&t<0?Oa(1e4*t)/1e4:t}function pb(){var t=this.props;return"matrix("+nb(t[0])+","+nb(t[1])+","+nb(t[4])+","+nb(t[5])+","+nb(t[12])+","+nb(t[13])+")"}!function(o,h){var p,l=this,m=256,f=6,c="random",d=h.pow(m,f),u=h.pow(2,52),y=2*u,g=m-1;function v(t){var e,r=t.length,n=this,i=0,s=n.i=n.j=0,a=n.S=[];for(r||(t=[r++]);i<m;)a[i]=i++;for(i=0;i<m;i++)a[i]=a[s=g&s+t[i%r]+(e=a[i])],a[s]=e;n.g=function(t){for(var e,r=0,i=n.i,s=n.j,a=n.S;t--;)e=a[i=g&i+1],r=r*m+a[g&(a[i]=a[s=g&s+e])+(a[s]=e)];return n.i=i,n.j=s,r}}function P(t,e){return e.i=t.i,e.j=t.j,e.S=t.S.slice(),e}function b(t,e){for(var r,i=t+"",s=0;s<i.length;)e[g&s]=g&(r^=19*e[g&s])+i.charCodeAt(s++);return x(e)}function x(t){return String.fromCharCode.apply(0,t)}h["seed"+c]=function(t,e,r){function i(){for(var t=n.g(f),e=d,r=0;t<u;)t=(t+r)*m,e*=m,r=n.g(1);for(;y<=t;)t/=2,e/=2,r>>>=1;return(t+r)/e}var s=[],a=b(function t(e,r){var i,s=[],a=typeof e;if(r&&"object"==a)for(i in e)try{s.push(t(e[i],r-1))}catch(t){}return s.length?s:"string"==a?e:e+"\0"}((e=!0===e?{entropy:!0}:e||{}).entropy?[t,x(o)]:null===t?function(){try{if(p)return x(p.randomBytes(m));var t=new Uint8Array(m);return(l.crypto||l.msCrypto).getRandomValues(t),x(t)}catch(t){var e=l.navigator,r=e&&e.plugins;return[+new Date,l,r,l.screen,x(o)]}}():t,3),s),n=new v(s);return i.int32=function(){return 0|n.g(4)},i.quick=function(){return n.g(4)/4294967296},i.double=i,b(x(n.S),o),(e.pass||r||function(t,e,r,i){return i&&(i.S&&P(i,n),t.state=function(){return P(n,{})}),r?(h[c]=t,e):t})(i,a,"global"in e?e.global:this==h,e.state)},b(h.random(),o)}([],BMMath);var BezierFactory=(_e={getBezierEasing:function(t,e,r,i,s){var a=s||("bez_"+t+"_"+e+"_"+r+"_"+i).replace(/\./g,"p");if(af[a])return af[a];var n=new rf([t,e,r,i]);return af[a]=n}},af={},gf=11,hf=1/(gf-1),jf="function"==typeof Float32Array,rf.prototype={get:function(t){var e=this._p[0],r=this._p[1],i=this._p[2],s=this._p[3];return this._precomputed||this._precompute(),e===r&&i===s?t:0===t?0:1===t?1:nf(this._getTForX(t),r,s)},_precompute:function(){var t=this._p[0],e=this._p[1],r=this._p[2],i=this._p[3];this._precomputed=!0,t===e&&r===i||this._calcSampleValues()},_calcSampleValues:function(){for(var t=this._p[0],e=this._p[2],r=0;r<gf;++r)this._mSampleValues[r]=nf(r*hf,t,e)},_getTForX:function(t){for(var e=this._p[0],r=this._p[2],i=this._mSampleValues,s=0,a=1,n=gf-1;a!==n&&i[a]<=t;++a)s+=hf;var o=s+(t-i[--a])/(i[a+1]-i[a])*hf,h=of(o,e,r);return.001<=h?function(t,e,r,i){for(var s=0;s<4;++s){var a=of(e,r,i);if(0===a)return e;e-=(nf(e,r,i)-t)/a}return e}(t,o,e,r):0===h?o:function(t,e,r,i,s){for(var a,n,o=0;0<(a=nf(n=e+(r-e)/2,i,s)-t)?r=n:e=n,1e-7<Math.abs(a)&&++o<10;);return n}(t,s,s+hf,e,r)}},_e),_e,af,gf,hf,jf;function kf(t,e){return 1-3*e+3*t}function lf(t,e){return 3*e-6*t}function mf(t){return 3*t}function nf(t,e,r){return((kf(e,r)*t+lf(e,r))*t+mf(e))*t}function of(t,e,r){return 3*kf(e,r)*t*t+2*lf(e,r)*t+mf(e)}function rf(t){this._p=t,this._mSampleValues=jf?new Float32Array(gf):new Array(gf),this._precomputed=!1,this.get=this.get.bind(this)}function extendPrototype(t,e){var r,i,s=t.length;for(r=0;r<s;r+=1)for(var a in i=t[r].prototype)i.hasOwnProperty(a)&&(e.prototype[a]=i[a])}function getDescriptor(t,e){return Object.getOwnPropertyDescriptor(t,e)}function createProxyFunction(t){function e(){}return e.prototype=t,e}function bezFunction(){Math;function y(t,e,r,i,s,a){var n=t*i+e*s+r*a-s*i-a*t-r*e;return-.001<n&&n<.001}var l=function(t,e,r,i){var s,a,n,o,h,p,l=defaultCurveSegments,m=0,f=[],c=[],d=bezier_length_pool.newElement();for(n=r.length,s=0;s<l;s+=1){for(h=s/(l-1),a=p=0;a<n;a+=1)o=bm_pow(1-h,3)*t[a]+3*bm_pow(1-h,2)*h*r[a]+3*(1-h)*bm_pow(h,2)*i[a]+bm_pow(h,3)*e[a],f[a]=o,null!==c[a]&&(p+=bm_pow(f[a]-c[a],2)),c[a]=f[a];p&&(m+=p=bm_sqrt(p)),d.percents[s]=h,d.lengths[s]=m}return d.addedLength=m,d};function g(t){this.segmentLength=0,this.points=new Array(t)}function v(t,e){this.partialLength=t,this.point=e}var P,t=(P={},function(t,e,r,i){var s=(t[0]+"_"+t[1]+"_"+e[0]+"_"+e[1]+"_"+r[0]+"_"+r[1]+"_"+i[0]+"_"+i[1]).replace(/\./g,"p");if(!P[s]){var a,n,o,h,p,l,m,f=defaultCurveSegments,c=0,d=null;2===t.length&&(t[0]!=e[0]||t[1]!=e[1])&&y(t[0],t[1],e[0],e[1],t[0]+r[0],t[1]+r[1])&&y(t[0],t[1],e[0],e[1],e[0]+i[0],e[1]+i[1])&&(f=2);var u=new g(f);for(o=r.length,a=0;a<f;a+=1){for(m=createSizedArray(o),p=a/(f-1),n=l=0;n<o;n+=1)h=bm_pow(1-p,3)*t[n]+3*bm_pow(1-p,2)*p*(t[n]+r[n])+3*(1-p)*bm_pow(p,2)*(e[n]+i[n])+bm_pow(p,3)*e[n],m[n]=h,null!==d&&(l+=bm_pow(m[n]-d[n],2));c+=l=bm_sqrt(l),u.points[a]=new v(l,m),d=m}u.segmentLength=c,P[s]=u}return P[s]});function D(t,e){var r=e.percents,i=e.lengths,s=r.length,a=bm_floor((s-1)*t),n=t*e.addedLength,o=0;if(a===s-1||0===a||n===i[a])return r[a];for(var h=i[a]>n?-1:1,p=!0;p;)if(i[a]<=n&&i[a+1]>n?(o=(n-i[a])/(i[a+1]-i[a]),p=!1):a+=h,a<0||s-1<=a){if(a===s-1)return r[a];p=!1}return r[a]+(r[a+1]-r[a])*o}var I=createTypedArray("float32",8);return{getSegmentsLength:function(t){var e,r=segments_length_pool.newElement(),i=t.c,s=t.v,a=t.o,n=t.i,o=t._length,h=r.lengths,p=0;for(e=0;e<o-1;e+=1)h[e]=l(s[e],s[e+1],a[e],n[e+1]),p+=h[e].addedLength;return i&&o&&(h[e]=l(s[e],s[0],a[e],n[0]),p+=h[e].addedLength),r.totalLength=p,r},getNewSegment:function(t,e,r,i,s,a,n){var o,h=D(s=s<0?0:1<s?1:s,n),p=D(a=1<a?1:a,n),l=t.length,m=1-h,f=1-p,c=m*m*m,d=h*m*m*3,u=h*h*m*3,y=h*h*h,g=m*m*f,v=h*m*f+m*h*f+m*m*p,P=h*h*f+m*h*p+h*m*p,b=h*h*p,x=m*f*f,_=h*f*f+m*p*f+m*f*p,S=h*p*f+m*p*p+h*f*p,T=h*p*p,A=f*f*f,C=p*f*f+f*p*f+f*f*p,E=p*p*f+f*p*p+p*f*p,k=p*p*p;for(o=0;o<l;o+=1)I[4*o]=Math.round(1e3*(c*t[o]+d*r[o]+u*i[o]+y*e[o]))/1e3,I[4*o+1]=Math.round(1e3*(g*t[o]+v*r[o]+P*i[o]+b*e[o]))/1e3,I[4*o+2]=Math.round(1e3*(x*t[o]+_*r[o]+S*i[o]+T*e[o]))/1e3,I[4*o+3]=Math.round(1e3*(A*t[o]+C*r[o]+E*i[o]+k*e[o]))/1e3;return I},getPointInSegment:function(t,e,r,i,s,a){var n=D(s,a),o=1-n;return[Math.round(1e3*(o*o*o*t[0]+(n*o*o+o*n*o+o*o*n)*r[0]+(n*n*o+o*n*n+n*o*n)*i[0]+n*n*n*e[0]))/1e3,Math.round(1e3*(o*o*o*t[1]+(n*o*o+o*n*o+o*o*n)*r[1]+(n*n*o+o*n*n+n*o*n)*i[1]+n*n*n*e[1]))/1e3]},buildBezierData:t,pointOnLine2D:y,pointOnLine3D:function(t,e,r,i,s,a,n,o,h){if(0===r&&0===a&&0===h)return y(t,e,i,s,n,o);var p,l=Math.sqrt(Math.pow(i-t,2)+Math.pow(s-e,2)+Math.pow(a-r,2)),m=Math.sqrt(Math.pow(n-t,2)+Math.pow(o-e,2)+Math.pow(h-r,2)),f=Math.sqrt(Math.pow(n-i,2)+Math.pow(o-s,2)+Math.pow(h-a,2));return-1e-4<(p=m<l?f<l?l-m-f:f-m-l:m<f?f-m-l:m-l-f)&&p<1e-4}}}!function(){for(var a=0,t=["ms","moz","webkit","o"],e=0;e<t.length&&!window.requestAnimationFrame;++e)window.requestAnimationFrame=window[t[e]+"RequestAnimationFrame"],window.cancelAnimationFrame=window[t[e]+"CancelAnimationFrame"]||window[t[e]+"CancelRequestAnimationFrame"];window.requestAnimationFrame||(window.requestAnimationFrame=function(t,e){var r=(new Date).getTime(),i=Math.max(0,16-(r-a)),s=setTimeout(function(){t(r+i)},i);return a=r+i,s}),window.cancelAnimationFrame||(window.cancelAnimationFrame=function(t){clearTimeout(t)})}();var bez=bezFunction();function dataFunctionManager(){function m(t,e,r){var i,s,a,n,o,h,p=t.length;for(s=0;s<p;s+=1)if("ks"in(i=t[s])&&!i.completed){if(i.completed=!0,i.tt&&(t[s-1].td=i.tt),[],-1,i.hasMask){var l=i.masksProperties;for(n=l.length,a=0;a<n;a+=1)if(l[a].pt.k.i)d(l[a].pt.k);else for(h=l[a].pt.k.length,o=0;o<h;o+=1)l[a].pt.k[o].s&&d(l[a].pt.k[o].s[0]),l[a].pt.k[o].e&&d(l[a].pt.k[o].e[0])}0===i.ty?(i.layers=f(i.refId,e),m(i.layers,e,r)):4===i.ty?c(i.shapes):5==i.ty&&b(i,r)}}function f(t,e){for(var r=0,i=e.length;r<i;){if(e[r].id===t)return e[r].layers.__used?JSON.parse(JSON.stringify(e[r].layers)):(e[r].layers.__used=!0,e[r].layers);r+=1}}function c(t){var e,r,i;for(e=t.length-1;0<=e;e-=1)if("sh"==t[e].ty){if(t[e].ks.k.i)d(t[e].ks.k);else for(i=t[e].ks.k.length,r=0;r<i;r+=1)t[e].ks.k[r].s&&d(t[e].ks.k[r].s[0]),t[e].ks.k[r].e&&d(t[e].ks.k[r].e[0]);!0}else"gr"==t[e].ty&&c(t[e].it)}function d(t){var e,r=t.i.length;for(e=0;e<r;e+=1)t.i[e][0]+=t.v[e][0],t.i[e][1]+=t.v[e][1],t.o[e][0]+=t.v[e][0],t.o[e][1]+=t.v[e][1]}function o(t,e){var r=e?e.split("."):[100,100,100];return t[0]>r[0]||!(r[0]>t[0])&&(t[1]>r[1]||!(r[1]>t[1])&&(t[2]>r[2]||!(r[2]>t[2])&&void 0))}var i,r=(i=[4,4,14],function(t){if(o(i,t.v)&&(s(t.layers),t.assets)){var e,r=t.assets.length;for(e=0;e<r;e+=1)t.assets[e].layers&&s(t.assets[e].layers)}});function s(t){var e,r,i,s=t.length;for(e=0;e<s;e+=1)5===t[e].ty&&(r=t[e],void 0,i=r.t.d,r.t.d={k:[{s:i,t:0}]})}var h,a,n=(h=[4,7,99],function(t){if(t.chars&&!o(h,t.v)){var e,r,i,s,a,n=t.chars.length;for(e=0;e<n;e+=1)if(t.chars[e].data&&t.chars[e].data.shapes)for(i=(a=t.chars[e].data.shapes[0].it).length,r=0;r<i;r+=1)(s=a[r].ks.k).__converted||(d(a[r].ks.k),s.__converted=!0)}}),p=(a=[4,1,9],function(t){if(o(a,t.v)&&(u(t.layers),t.assets)){var e,r=t.assets.length;for(e=0;e<r;e+=1)t.assets[e].layers&&u(t.assets[e].layers)}});function l(t){var e,r,i,s=t.length;for(e=0;e<s;e+=1)if("gr"===t[e].ty)l(t[e].it);else if("fl"===t[e].ty||"st"===t[e].ty)if(t[e].c.k&&t[e].c.k[0].i)for(i=t[e].c.k.length,r=0;r<i;r+=1)t[e].c.k[r].s&&(t[e].c.k[r].s[0]/=255,t[e].c.k[r].s[1]/=255,t[e].c.k[r].s[2]/=255,t[e].c.k[r].s[3]/=255),t[e].c.k[r].e&&(t[e].c.k[r].e[0]/=255,t[e].c.k[r].e[1]/=255,t[e].c.k[r].e[2]/=255,t[e].c.k[r].e[3]/=255);else t[e].c.k[0]/=255,t[e].c.k[1]/=255,t[e].c.k[2]/=255,t[e].c.k[3]/=255}function u(t){var e,r=t.length;for(e=0;e<r;e+=1)4===t[e].ty&&l(t[e].shapes)}var y,g=(y=[4,4,18],function(t){if(o(y,t.v)&&(P(t.layers),t.assets)){var e,r=t.assets.length;for(e=0;e<r;e+=1)t.assets[e].layers&&P(t.assets[e].layers)}});function v(t){var e,r,i;for(e=t.length-1;0<=e;e-=1)if("sh"==t[e].ty){if(t[e].ks.k.i)t[e].ks.k.c=t[e].closed;else for(i=t[e].ks.k.length,r=0;r<i;r+=1)t[e].ks.k[r].s&&(t[e].ks.k[r].s[0].c=t[e].closed),t[e].ks.k[r].e&&(t[e].ks.k[r].e[0].c=t[e].closed);!0}else"gr"==t[e].ty&&v(t[e].it)}function P(t){var e,r,i,s,a,n,o=t.length;for(r=0;r<o;r+=1){if((e=t[r]).hasMask){var h=e.masksProperties;for(s=h.length,i=0;i<s;i+=1)if(h[i].pt.k.i)h[i].pt.k.c=h[i].cl;else for(n=h[i].pt.k.length,a=0;a<n;a+=1)h[i].pt.k[a].s&&(h[i].pt.k[a].s[0].c=h[i].cl),h[i].pt.k[a].e&&(h[i].pt.k[a].e[0].c=h[i].cl)}4===e.ty&&v(e.shapes)}}function b(t,e){0!==t.t.a.length||"m"in t.t.p||(t.singleShape=!0)}var t={completeData:function(t,e){t.__complete||(p(t),r(t),n(t),g(t),m(t.layers,t.assets,e),t.__complete=!0)}};return t.checkColors=p,t.checkChars=n,t.checkShapes=g,t.completeLayers=m,t}var dataManager=dataFunctionManager();dataManager.completeData=function(t,e){t.__complete||(this.checkColors(t),this.checkChars(t),this.checkShapes(t),this.completeLayers(t.layers,t.assets,e),t.__complete=!0)};var FontManager=function(){var a={w:0,size:0,shapes:[]},t=[];function u(t,e){var r=createTag("span");r.style.fontFamily=e;var i=createTag("span");i.innerHTML="giItT1WQy@!-/#",r.style.position="absolute",r.style.left="-10000px",r.style.top="-10000px",r.style.fontSize="300px",r.style.fontVariant="normal",r.style.fontStyle="normal",r.style.fontWeight="normal",r.style.letterSpacing="0",r.appendChild(i),document.body.appendChild(r);var s=i.offsetWidth;return i.style.fontFamily=t+", "+e,{node:i,w:s,parent:r}}t=t.concat([2304,2305,2306,2307,2362,2363,2364,2364,2366,2367,2368,2369,2370,2371,2372,2373,2374,2375,2376,2377,2378,2379,2380,2381,2382,2383,2387,2388,2389,2390,2391,2402,2403]);function e(){this.fonts=[],this.chars=null,this.typekitLoaded=0,this.isLoaded=!1,this.initTime=Date.now()}return e.getCombinedCharacterCodes=function(){return t},e.prototype.addChars=function(t){if(t){this.chars||(this.chars=[]);var e,r,i,s=t.length,a=this.chars.length;for(e=0;e<s;e+=1){for(r=0,i=!1;r<a;)this.chars[r].style===t[e].style&&this.chars[r].fFamily===t[e].fFamily&&this.chars[r].ch===t[e].ch&&(i=!0),r+=1;i||(this.chars.push(t[e]),a+=1)}}},e.prototype.addFonts=function(t,e){if(t){if(this.chars)return this.isLoaded=!0,void(this.fonts=t.list);var r,i,s,a,n=t.list,o=n.length,h=o;for(r=0;r<o;r+=1){var p,l,m=!0;if(n[r].loaded=!1,n[r].monoCase=u(n[r].fFamily,"monospace"),n[r].sansCase=u(n[r].fFamily,"sans-serif"),n[r].fPath){if("p"===n[r].fOrigin||3===n[r].origin){if(0<(p=document.querySelectorAll('style[f-forigin="p"][f-family="'+n[r].fFamily+'"], style[f-origin="3"][f-family="'+n[r].fFamily+'"]')).length&&(m=!1),m){var f=createTag("style");f.setAttribute("f-forigin",n[r].fOrigin),f.setAttribute("f-origin",n[r].origin),f.setAttribute("f-family",n[r].fFamily),f.type="text/css",f.innerHTML="@font-face {font-family: "+n[r].fFamily+"; font-style: normal; src: url('"+n[r].fPath+"');}",e.appendChild(f)}}else if("g"===n[r].fOrigin||1===n[r].origin){for(p=document.querySelectorAll('link[f-forigin="g"], link[f-origin="1"]'),l=0;l<p.length;l++)-1!==p[l].href.indexOf(n[r].fPath)&&(m=!1);if(m){var c=createTag("link");c.setAttribute("f-forigin",n[r].fOrigin),c.setAttribute("f-origin",n[r].origin),c.type="text/css",c.rel="stylesheet",c.href=n[r].fPath,document.body.appendChild(c)}}else if("t"===n[r].fOrigin||2===n[r].origin){for(p=document.querySelectorAll('script[f-forigin="t"], script[f-origin="2"]'),l=0;l<p.length;l++)n[r].fPath===p[l].src&&(m=!1);if(m){var d=createTag("link");d.setAttribute("f-forigin",n[r].fOrigin),d.setAttribute("f-origin",n[r].origin),d.setAttribute("rel","stylesheet"),d.setAttribute("href",n[r].fPath),e.appendChild(d)}}}else n[r].loaded=!0,h-=1;n[r].helper=(i=e,s=n[r],a=void 0,(a=createNS("text")).style.fontSize="100px",a.setAttribute("font-family",s.fFamily),a.setAttribute("font-style",s.fStyle),a.setAttribute("font-weight",s.fWeight),a.textContent="1",s.fClass?(a.style.fontFamily="inherit",a.setAttribute("class",s.fClass)):a.style.fontFamily=s.fFamily,i.appendChild(a),createTag("canvas").getContext("2d").font=s.fWeight+" "+s.fStyle+" 100px "+s.fFamily,a),n[r].cache={},this.fonts.push(n[r])}0===h?this.isLoaded=!0:setTimeout(this.checkLoadedFonts.bind(this),100)}else this.isLoaded=!0},e.prototype.getCharData=function(t,e,r){for(var i=0,s=this.chars.length;i<s;){if(this.chars[i].ch===t&&this.chars[i].style===e&&this.chars[i].fFamily===r)return this.chars[i];i+=1}return console&&console.warn&&console.warn("Missing character from exported characters list: ",t,e,r),a},e.prototype.getFontByName=function(t){for(var e=0,r=this.fonts.length;e<r;){if(this.fonts[e].fName===t)return this.fonts[e];e+=1}return this.fonts[0]},e.prototype.measureText=function(t,e,r){var i=this.getFontByName(e),s=t.charCodeAt(0);if(!i.cache[s+1]){var a=i.helper;if(" "===t){a.textContent="|"+t+"|";var n=a.getComputedTextLength();a.textContent="||";var o=a.getComputedTextLength();i.cache[s+1]=(n-o)/100}else a.textContent=t,i.cache[s+1]=a.getComputedTextLength()/100}return i.cache[s+1]*r},e.prototype.checkLoadedFonts=function(){var t,e,r,i=this.fonts.length,s=i;for(t=0;t<i;t+=1)this.fonts[t].loaded?s-=1:"n"===this.fonts[t].fOrigin||0===this.fonts[t].origin?this.fonts[t].loaded=!0:(e=this.fonts[t].monoCase.node,r=this.fonts[t].monoCase.w,e.offsetWidth!==r?(s-=1,this.fonts[t].loaded=!0):(e=this.fonts[t].sansCase.node,r=this.fonts[t].sansCase.w,e.offsetWidth!==r&&(s-=1,this.fonts[t].loaded=!0)),this.fonts[t].loaded&&(this.fonts[t].sansCase.parent.parentNode.removeChild(this.fonts[t].sansCase.parent),this.fonts[t].monoCase.parent.parentNode.removeChild(this.fonts[t].monoCase.parent)));0!==s&&Date.now()-this.initTime<5e3?setTimeout(this.checkLoadedFonts.bind(this),20):setTimeout(function(){this.isLoaded=!0}.bind(this),0)},e.prototype.loaded=function(){return this.isLoaded},e}();FontManager=function(){this.fonts=[],this.chars=null,this.typekitLoaded=0,this.isLoaded=!1,this.initTime=Date.now()};var PropertyFactory=(km=initialDefaultFrame,lm=Math.abs,{getProp:function(t,e,r,i,s){var a;if(e.k.length)if("number"==typeof e.k[0])a=new vm(t,e,i,s);else switch(r){case 0:a=new wm(t,e,i,s);break;case 1:a=new xm(t,e,i,s)}else a=new um(t,e,i,s);return a.effectsSequence.length&&s.addDynamicProperty(a),a}}),km,lm;function mm(t,e){var r,i=this.offsetTime;"multidimensional"===this.propType&&(r=createTypedArray("float32",this.pv.length));for(var s,a,n,o,h,p,l,m,f=e.lastIndex,c=f,d=this.keyframes.length-1,u=!0;u;){if(s=this.keyframes[c],a=this.keyframes[c+1],c===d-1&&t>=a.t-i){s.h&&(s=a),f=0;break}if(a.t-i>t){f=c;break}c<d-1?c+=1:(f=0,u=!1)}var y,g=a.t-i,v=s.t-i;if(s.to){s.bezierData||(s.bezierData=bez.buildBezierData(s.s,a.s||s.e,s.to,s.ti));var P=s.bezierData;if(g<=t||t<v){var b=g<=t?P.points.length-1:0;for(o=P.points[b].point.length,n=0;n<o;n+=1)r[n]=P.points[b].point[n]}else{s.__fnct?m=s.__fnct:(m=BezierFactory.getBezierEasing(s.o.x,s.o.y,s.i.x,s.i.y,s.n).get,s.__fnct=m),h=m((t-v)/(g-v));var x,_=P.segmentLength*h,S=e.lastFrame<t&&e._lastKeyframeIndex===c?e._lastAddedLength:0;for(l=e.lastFrame<t&&e._lastKeyframeIndex===c?e._lastPoint:0,u=!0,p=P.points.length;u;){if(S+=P.points[l].partialLength,0==_||0===h||l===P.points.length-1){for(o=P.points[l].point.length,n=0;n<o;n+=1)r[n]=P.points[l].point[n];break}if(S<=_&&_<S+P.points[l+1].partialLength){for(x=(_-S)/P.points[l+1].partialLength,o=P.points[l].point.length,n=0;n<o;n+=1)r[n]=P.points[l].point[n]+(P.points[l+1].point[n]-P.points[l].point[n])*x;break}l<p-1?l+=1:u=!1}e._lastPoint=l,e._lastAddedLength=S-P.points[l].partialLength,e._lastKeyframeIndex=c}}else{var T,A,C,E,k;if(d=s.s.length,y=a.s||s.e,this.sh&&1!==s.h)if(g<=t)r[0]=y[0],r[1]=y[1],r[2]=y[2];else if(t<=v)r[0]=s.s[0],r[1]=s.s[1],r[2]=s.s[2];else{!function(t,e){var r=e[0],i=e[1],s=e[2],a=e[3],n=Math.atan2(2*i*a-2*r*s,1-2*i*i-2*s*s),o=Math.asin(2*r*i+2*s*a),h=Math.atan2(2*r*a-2*i*s,1-2*r*r-2*s*s);t[0]=n/degToRads,t[1]=o/degToRads,t[2]=h/degToRads}(r,function(t,e,r){var i,s,a,n,o,h=[],p=t[0],l=t[1],m=t[2],f=t[3],c=e[0],d=e[1],u=e[2],y=e[3];(s=p*c+l*d+m*u+f*y)<0&&(s=-s,c=-c,d=-d,u=-u,y=-y);o=1e-6<1-s?(i=Math.acos(s),a=Math.sin(i),n=Math.sin((1-r)*i)/a,Math.sin(r*i)/a):(n=1-r,r);return h[0]=n*p+o*c,h[1]=n*l+o*d,h[2]=n*m+o*u,h[3]=n*f+o*y,h}(pm(s.s),pm(y),(t-v)/(g-v)))}else for(c=0;c<d;c+=1)1!==s.h&&(h=g<=t?1:t<v?0:(s.o.x.constructor===Array?(s.__fnct||(s.__fnct=[]),s.__fnct[c]?m=s.__fnct[c]:(T=void 0===s.o.x[c]?s.o.x[0]:s.o.x[c],A=void 0===s.o.y[c]?s.o.y[0]:s.o.y[c],C=void 0===s.i.x[c]?s.i.x[0]:s.i.x[c],E=void 0===s.i.y[c]?s.i.y[0]:s.i.y[c],m=BezierFactory.getBezierEasing(T,A,C,E).get,s.__fnct[c]=m)):s.__fnct?m=s.__fnct:(T=s.o.x,A=s.o.y,C=s.i.x,E=s.i.y,m=BezierFactory.getBezierEasing(T,A,C,E).get,s.__fnct=m),m((t-v)/(g-v)))),y=a.s||s.e,k=1===s.h?s.s[c]:s.s[c]+(y[c]-s.s[c])*h,1===d?r=k:r[c]=k}return e.lastIndex=f,r}function pm(t){var e=t[0]*degToRads,r=t[1]*degToRads,i=t[2]*degToRads,s=Math.cos(e/2),a=Math.cos(r/2),n=Math.cos(i/2),o=Math.sin(e/2),h=Math.sin(r/2),p=Math.sin(i/2);return[o*h*n+s*a*p,o*a*n+s*h*p,s*h*n-o*a*p,s*a*n-o*h*p]}function qm(){var t=this.comp.renderedFrame-this.offsetTime,e=this.keyframes[0].t-this.offsetTime,r=this.keyframes[this.keyframes.length-1].t-this.offsetTime;if(!(t===this._caching.lastFrame||this._caching.lastFrame!==km&&(this._caching.lastFrame>=r&&r<=t||this._caching.lastFrame<e&&t<e))){this._caching.lastFrame>=t&&(this._caching._lastKeyframeIndex=-1,this._caching.lastIndex=0);var i=this.interpolateValue(t,this._caching);this.pv=i}return this._caching.lastFrame=t,this.pv}function rm(t){var e;if("unidimensional"===this.propType)e=t*this.mult,1e-5<lm(this.v-e)&&(this.v=e,this._mdf=!0);else for(var r=0,i=this.v.length;r<i;)e=t[r]*this.mult,1e-5<lm(this.v[r]-e)&&(this.v[r]=e,this._mdf=!0),r+=1}function sm(){if(this.elem.globalData.frameId!==this.frameId&&this.effectsSequence.length)if(this.lock)this.setVValue(this.pv);else{this.lock=!0,this._mdf=this._isFirstFrame;var t,e=this.effectsSequence.length,r=this.kf?this.pv:this.data.k;for(t=0;t<e;t+=1)r=this.effectsSequence[t](r);this.setVValue(r),this._isFirstFrame=!1,this.lock=!1,this.frameId=this.elem.globalData.frameId}}function tm(t){this.effectsSequence.push(t),this.container.addDynamicProperty(this)}function um(t,e,r,i){this.propType="unidimensional",this.mult=r||1,this.data=e,this.v=r?e.k*r:e.k,this.pv=e.k,this._mdf=!1,this.elem=t,this.container=i,this.comp=t.comp,this.k=!1,this.kf=!1,this.vel=0,this.effectsSequence=[],this._isFirstFrame=!0,this.getValue=sm,this.setVValue=rm,this.addEffect=tm}function vm(t,e,r,i){this.propType="multidimensional",this.mult=r||1,this.data=e,this._mdf=!1,this.elem=t,this.container=i,this.comp=t.comp,this.k=!1,this.kf=!1,this.frameId=-1;var s,a=e.k.length;this.v=createTypedArray("float32",a),this.pv=createTypedArray("float32",a);createTypedArray("float32",a);for(this.vel=createTypedArray("float32",a),s=0;s<a;s+=1)this.v[s]=e.k[s]*this.mult,this.pv[s]=e.k[s];this._isFirstFrame=!0,this.effectsSequence=[],this.getValue=sm,this.setVValue=rm,this.addEffect=tm}function wm(t,e,r,i){this.propType="unidimensional",this.keyframes=e.k,this.offsetTime=t.data.st,this.frameId=-1,this._caching={lastFrame:km,lastIndex:0,value:0,_lastKeyframeIndex:-1},this.k=!0,this.kf=!0,this.data=e,this.mult=r||1,this.elem=t,this.container=i,this.comp=t.comp,this.v=km,this.pv=km,this._isFirstFrame=!0,this.getValue=sm,this.setVValue=rm,this.interpolateValue=mm,this.effectsSequence=[qm.bind(this)],this.addEffect=tm}function xm(t,e,r,i){this.propType="multidimensional";var s,a,n,o,h,p=e.k.length;for(s=0;s<p-1;s+=1)e.k[s].to&&e.k[s].s&&e.k[s].e&&(a=e.k[s].s,n=e.k[s].e,o=e.k[s].to,h=e.k[s].ti,(2===a.length&&(a[0]!==n[0]||a[1]!==n[1])&&bez.pointOnLine2D(a[0],a[1],n[0],n[1],a[0]+o[0],a[1]+o[1])&&bez.pointOnLine2D(a[0],a[1],n[0],n[1],n[0]+h[0],n[1]+h[1])||3===a.length&&(a[0]!==n[0]||a[1]!==n[1]||a[2]!==n[2])&&bez.pointOnLine3D(a[0],a[1],a[2],n[0],n[1],n[2],a[0]+o[0],a[1]+o[1],a[2]+o[2])&&bez.pointOnLine3D(a[0],a[1],a[2],n[0],n[1],n[2],n[0]+h[0],n[1]+h[1],n[2]+h[2]))&&(e.k[s].to=null,e.k[s].ti=null),a[0]===n[0]&&a[1]===n[1]&&0===o[0]&&0===o[1]&&0===h[0]&&0===h[1]&&(2===a.length||a[2]===n[2]&&0===o[2]&&0===h[2])&&(e.k[s].to=null,e.k[s].ti=null));this.effectsSequence=[qm.bind(this)],this.keyframes=e.k,this.offsetTime=t.data.st,this.k=!0,this.kf=!0,this._isFirstFrame=!0,this.mult=r||1,this.elem=t,this.container=i,this.comp=t.comp,this.getValue=sm,this.setVValue=rm,this.interpolateValue=mm,this.frameId=-1;var l=e.k[0].s.length;for(this.v=createTypedArray("float32",l),this.pv=createTypedArray("float32",l),s=0;s<l;s+=1)this.v[s]=km,this.pv[s]=km;this._caching={lastFrame:km,lastIndex:0,value:createTypedArray("float32",l)},this.addEffect=tm}var TransformPropertyFactory=(Qo.prototype={applyToMatrix:function(t){var e=this._mdf;this.iterateDynamicProperties(),this._mdf=this._mdf||e,this.a&&t.translate(-this.a.v[0],-this.a.v[1],this.a.v[2]),this.s&&t.scale(this.s.v[0],this.s.v[1],this.s.v[2]),this.sk&&t.skewFromAxis(-this.sk.v,this.sa.v),this.r?t.rotate(-this.r.v):t.rotateZ(-this.rz.v).rotateY(this.ry.v).rotateX(this.rx.v).rotateZ(-this.or.v[2]).rotateY(this.or.v[1]).rotateX(this.or.v[0]),this.data.p.s?this.data.p.z?t.translate(this.px.v,this.py.v,-this.pz.v):t.translate(this.px.v,this.py.v,0):t.translate(this.p.v[0],this.p.v[1],-this.p.v[2])},getValue:function(t){if(this.elem.globalData.frameId!==this.frameId){if(this._isDirty&&(this.precalculateMatrix(),this._isDirty=!1),this.iterateDynamicProperties(),this._mdf||t){if(this.v.cloneFromProps(this.pre.props),this.appliedTransformations<1&&this.v.translate(-this.a.v[0],-this.a.v[1],this.a.v[2]),this.appliedTransformations<2&&this.v.scale(this.s.v[0],this.s.v[1],this.s.v[2]),this.sk&&this.appliedTransformations<3&&this.v.skewFromAxis(-this.sk.v,this.sa.v),this.r&&this.appliedTransformations<4?this.v.rotate(-this.r.v):!this.r&&this.appliedTransformations<4&&this.v.rotateZ(-this.rz.v).rotateY(this.ry.v).rotateX(this.rx.v).rotateZ(-this.or.v[2]).rotateY(this.or.v[1]).rotateX(this.or.v[0]),this.autoOriented){var e,r,i=this.elem.globalData.frameRate;if(this.p&&this.p.keyframes&&this.p.getValueAtTime)r=this.p._caching.lastFrame+this.p.offsetTime<=this.p.keyframes[0].t?(e=this.p.getValueAtTime((this.p.keyframes[0].t+.01)/i,0),this.p.getValueAtTime(this.p.keyframes[0].t/i,0)):this.p._caching.lastFrame+this.p.offsetTime>=this.p.keyframes[this.p.keyframes.length-1].t?(e=this.p.getValueAtTime(this.p.keyframes[this.p.keyframes.length-1].t/i,0),this.p.getValueAtTime((this.p.keyframes[this.p.keyframes.length-1].t-.01)/i,0)):(e=this.p.pv,this.p.getValueAtTime((this.p._caching.lastFrame+this.p.offsetTime-.01)/i,this.p.offsetTime));else if(this.px&&this.px.keyframes&&this.py.keyframes&&this.px.getValueAtTime&&this.py.getValueAtTime){e=[],r=[];var s=this.px,a=this.py;s._caching.lastFrame+s.offsetTime<=s.keyframes[0].t?(e[0]=s.getValueAtTime((s.keyframes[0].t+.01)/i,0),e[1]=a.getValueAtTime((a.keyframes[0].t+.01)/i,0),r[0]=s.getValueAtTime(s.keyframes[0].t/i,0),r[1]=a.getValueAtTime(a.keyframes[0].t/i,0)):s._caching.lastFrame+s.offsetTime>=s.keyframes[s.keyframes.length-1].t?(e[0]=s.getValueAtTime(s.keyframes[s.keyframes.length-1].t/i,0),e[1]=a.getValueAtTime(a.keyframes[a.keyframes.length-1].t/i,0),r[0]=s.getValueAtTime((s.keyframes[s.keyframes.length-1].t-.01)/i,0),r[1]=a.getValueAtTime((a.keyframes[a.keyframes.length-1].t-.01)/i,0)):(e=[s.pv,a.pv],r[0]=s.getValueAtTime((s._caching.lastFrame+s.offsetTime-.01)/i,s.offsetTime),r[1]=a.getValueAtTime((a._caching.lastFrame+a.offsetTime-.01)/i,a.offsetTime))}this.v.rotate(-Math.atan2(e[1]-r[1],e[0]-r[0]))}this.data.p&&this.data.p.s?this.data.p.z?this.v.translate(this.px.v,this.py.v,-this.pz.v):this.v.translate(this.px.v,this.py.v,0):this.v.translate(this.p.v[0],this.p.v[1],-this.p.v[2])}this.frameId=this.elem.globalData.frameId}},precalculateMatrix:function(){if(!this.a.k&&(this.pre.translate(-this.a.v[0],-this.a.v[1],this.a.v[2]),this.appliedTransformations=1,!this.s.effectsSequence.length)){if(this.pre.scale(this.s.v[0],this.s.v[1],this.s.v[2]),this.appliedTransformations=2,this.sk){if(this.sk.effectsSequence.length||this.sa.effectsSequence.length)return;this.pre.skewFromAxis(-this.sk.v,this.sa.v),this.appliedTransformations=3}if(this.r){if(this.r.effectsSequence.length)return;this.pre.rotate(-this.r.v),this.appliedTransformations=4}else this.rz.effectsSequence.length||this.ry.effectsSequence.length||this.rx.effectsSequence.length||this.or.effectsSequence.length||(this.pre.rotateZ(-this.rz.v).rotateY(this.ry.v).rotateX(this.rx.v).rotateZ(-this.or.v[2]).rotateY(this.or.v[1]).rotateX(this.or.v[0]),this.appliedTransformations=4)}},autoOrient:function(){}},extendPrototype([DynamicPropertyContainer],Qo),Qo.prototype.addDynamicProperty=function(t){this._addDynamicProperty(t),this.elem.addDynamicProperty(t),this._isDirty=!0},Qo.prototype._addDynamicProperty=DynamicPropertyContainer.prototype.addDynamicProperty,{getTransformProperty:function(t,e,r){return new Qo(t,e,r)}});function Qo(t,e,r){if(this.elem=t,this.frameId=-1,this.propType="transform",this.data=e,this.v=new Matrix,this.pre=new Matrix,this.appliedTransformations=0,this.initDynamicPropertyContainer(r||t),e.p&&e.p.s?(this.px=PropertyFactory.getProp(t,e.p.x,0,0,this),this.py=PropertyFactory.getProp(t,e.p.y,0,0,this),e.p.z&&(this.pz=PropertyFactory.getProp(t,e.p.z,0,0,this))):this.p=PropertyFactory.getProp(t,e.p||{k:[0,0,0]},1,0,this),e.rx){if(this.rx=PropertyFactory.getProp(t,e.rx,0,degToRads,this),this.ry=PropertyFactory.getProp(t,e.ry,0,degToRads,this),this.rz=PropertyFactory.getProp(t,e.rz,0,degToRads,this),e.or.k[0].ti){var i,s=e.or.k.length;for(i=0;i<s;i+=1)e.or.k[i].to=e.or.k[i].ti=null}this.or=PropertyFactory.getProp(t,e.or,1,degToRads,this),this.or.sh=!0}else this.r=PropertyFactory.getProp(t,e.r||{k:0},0,degToRads,this);e.sk&&(this.sk=PropertyFactory.getProp(t,e.sk,0,degToRads,this),this.sa=PropertyFactory.getProp(t,e.sa,0,degToRads,this)),this.a=PropertyFactory.getProp(t,e.a||{k:[0,0,0]},1,0,this),this.s=PropertyFactory.getProp(t,e.s||{k:[100,100,100]},1,.01,this),e.o?this.o=PropertyFactory.getProp(t,e.o,0,.01,t):this.o={_mdf:!1,v:1},this._isDirty=!0,this.dynamicProperties.length||this.getValue(!0)}function ShapePath(){this.c=!1,this._length=0,this._maxLength=8,this.v=createSizedArray(this._maxLength),this.o=createSizedArray(this._maxLength),this.i=createSizedArray(this._maxLength)}ShapePath.prototype.setPathData=function(t,e){this.c=t,this.setLength(e);for(var r=0;r<e;)this.v[r]=point_pool.newElement(),this.o[r]=point_pool.newElement(),this.i[r]=point_pool.newElement(),r+=1},ShapePath.prototype.setLength=function(t){for(;this._maxLength<t;)this.doubleArrayLength();this._length=t},ShapePath.prototype.doubleArrayLength=function(){this.v=this.v.concat(createSizedArray(this._maxLength)),this.i=this.i.concat(createSizedArray(this._maxLength)),this.o=this.o.concat(createSizedArray(this._maxLength)),this._maxLength*=2},ShapePath.prototype.setXYAt=function(t,e,r,i,s){var a;switch(this._length=Math.max(this._length,i+1),this._length>=this._maxLength&&this.doubleArrayLength(),r){case"v":a=this.v;break;case"i":a=this.i;break;case"o":a=this.o}a[i]&&(!a[i]||s)||(a[i]=point_pool.newElement()),a[i][0]=t,a[i][1]=e},ShapePath.prototype.setTripleAt=function(t,e,r,i,s,a,n,o){this.setXYAt(t,e,"v",n,o),this.setXYAt(r,i,"o",n,o),this.setXYAt(s,a,"i",n,o)},ShapePath.prototype.reverse=function(){var t=new ShapePath;t.setPathData(this.c,this._length);var e=this.v,r=this.o,i=this.i,s=0;this.c&&(t.setTripleAt(e[0][0],e[0][1],i[0][0],i[0][1],r[0][0],r[0][1],0,!1),s=1);var a,n=this._length-1,o=this._length;for(a=s;a<o;a+=1)t.setTripleAt(e[n][0],e[n][1],i[n][0],i[n][1],r[n][0],r[n][1],a,!1),n-=1;return t};var ShapePropertyFactory=function(){var s=-999999;function t(t,e,r){var i,s,a,n,o,h,p,l,m,f=r.lastIndex,c=this.keyframes;if(t<c[0].t-this.offsetTime)i=c[0].s[0],a=!0,f=0;else if(t>=c[c.length-1].t-this.offsetTime)i=c[c.length-1].s?c[c.length-1].s[0]:c[c.length-2].e[0],a=!0;else{for(var d,u,y=f,g=c.length-1,v=!0;v&&(d=c[y],!((u=c[y+1]).t-this.offsetTime>t));)y<g-1?y+=1:v=!1;if(f=y,!(a=1===d.h)){if(t>=u.t-this.offsetTime)l=1;else if(t<d.t-this.offsetTime)l=0;else{var P;d.__fnct?P=d.__fnct:(P=BezierFactory.getBezierEasing(d.o.x,d.o.y,d.i.x,d.i.y).get,d.__fnct=P),l=P((t-(d.t-this.offsetTime))/(u.t-this.offsetTime-(d.t-this.offsetTime)))}s=u.s?u.s[0]:d.e[0]}i=d.s[0]}for(h=e._length,p=i.i[0].length,r.lastIndex=f,n=0;n<h;n+=1)for(o=0;o<p;o+=1)m=a?i.i[n][o]:i.i[n][o]+(s.i[n][o]-i.i[n][o])*l,e.i[n][o]=m,m=a?i.o[n][o]:i.o[n][o]+(s.o[n][o]-i.o[n][o])*l,e.o[n][o]=m,m=a?i.v[n][o]:i.v[n][o]+(s.v[n][o]-i.v[n][o])*l,e.v[n][o]=m}function a(){this.paths=this.localShapeCollection}function e(t){!function(t,e){if(t._length!==e._length||t.c!==e.c)return!1;var r,i=t._length;for(r=0;r<i;r+=1)if(t.v[r][0]!==e.v[r][0]||t.v[r][1]!==e.v[r][1]||t.o[r][0]!==e.o[r][0]||t.o[r][1]!==e.o[r][1]||t.i[r][0]!==e.i[r][0]||t.i[r][1]!==e.i[r][1])return!1;return!0}(this.v,t)&&(this.v=shape_pool.clone(t),this.localShapeCollection.releaseShapes(),this.localShapeCollection.addShape(this.v),this._mdf=!0,this.paths=this.localShapeCollection)}function r(){if(this.elem.globalData.frameId!==this.frameId&&this.effectsSequence.length)if(this.lock)this.setVValue(this.pv);else{this.lock=!0,this._mdf=!1;var t,e=this.kf?this.pv:this.data.ks?this.data.ks.k:this.data.pt.k,r=this.effectsSequence.length;for(t=0;t<r;t+=1)e=this.effectsSequence[t](e);this.setVValue(e),this.lock=!1,this.frameId=this.elem.globalData.frameId}}function n(t,e,r){this.propType="shape",this.comp=t.comp,this.container=t,this.elem=t,this.data=e,this.k=!1,this.kf=!1,this._mdf=!1;var i=3===r?e.pt.k:e.ks.k;this.v=shape_pool.clone(i),this.pv=shape_pool.clone(this.v),this.localShapeCollection=shapeCollection_pool.newShapeCollection(),this.paths=this.localShapeCollection,this.paths.addShape(this.v),this.reset=a,this.effectsSequence=[]}function i(t){this.effectsSequence.push(t),this.container.addDynamicProperty(this)}function o(t,e,r){this.propType="shape",this.comp=t.comp,this.elem=t,this.container=t,this.offsetTime=t.data.st,this.keyframes=3===r?e.pt.k:e.ks.k,this.k=!0,this.kf=!0;var i=this.keyframes[0].s[0].i.length;this.keyframes[0].s[0].i[0].length;this.v=shape_pool.newElement(),this.v.setPathData(this.keyframes[0].s[0].c,i),this.pv=shape_pool.clone(this.v),this.localShapeCollection=shapeCollection_pool.newShapeCollection(),this.paths=this.localShapeCollection,this.paths.addShape(this.v),this.lastFrame=s,this.reset=a,this._caching={lastFrame:s,lastIndex:0},this.effectsSequence=[function(){var t=this.comp.renderedFrame-this.offsetTime,e=this.keyframes[0].t-this.offsetTime,r=this.keyframes[this.keyframes.length-1].t-this.offsetTime,i=this._caching.lastFrame;return i!==s&&(i<e&&t<e||r<i&&r<t)||(this._caching.lastIndex=i<t?this._caching.lastIndex:0,this.interpolateShape(t,this.pv,this._caching)),this._caching.lastFrame=t,this.pv}.bind(this)]}n.prototype.interpolateShape=t,n.prototype.getValue=r,n.prototype.setVValue=e,n.prototype.addEffect=i,o.prototype.getValue=r,o.prototype.interpolateShape=t,o.prototype.setVValue=e,o.prototype.addEffect=i;var h,p=(h=roundCorner,l.prototype={reset:a,getValue:function(){this.elem.globalData.frameId!==this.frameId&&(this.frameId=this.elem.globalData.frameId,this.iterateDynamicProperties(),this._mdf&&this.convertEllToPath())},convertEllToPath:function(){var t=this.p.v[0],e=this.p.v[1],r=this.s.v[0]/2,i=this.s.v[1]/2,s=3!==this.d,a=this.v;a.v[0][0]=t,a.v[0][1]=e-i,a.v[1][0]=s?t+r:t-r,a.v[1][1]=e,a.v[2][0]=t,a.v[2][1]=e+i,a.v[3][0]=s?t-r:t+r,a.v[3][1]=e,a.i[0][0]=s?t-r*h:t+r*h,a.i[0][1]=e-i,a.i[1][0]=s?t+r:t-r,a.i[1][1]=e-i*h,a.i[2][0]=s?t+r*h:t-r*h,a.i[2][1]=e+i,a.i[3][0]=s?t-r:t+r,a.i[3][1]=e+i*h,a.o[0][0]=s?t+r*h:t-r*h,a.o[0][1]=e-i,a.o[1][0]=s?t+r:t-r,a.o[1][1]=e+i*h,a.o[2][0]=s?t-r*h:t+r*h,a.o[2][1]=e+i,a.o[3][0]=s?t-r:t+r,a.o[3][1]=e-i*h}},extendPrototype([DynamicPropertyContainer],l),l);function l(t,e){this.v=shape_pool.newElement(),this.v.setPathData(!0,4),this.localShapeCollection=shapeCollection_pool.newShapeCollection(),this.paths=this.localShapeCollection,this.localShapeCollection.addShape(this.v),this.d=e.d,this.elem=t,this.comp=t.comp,this.frameId=-1,this.initDynamicPropertyContainer(t),this.p=PropertyFactory.getProp(t,e.p,1,0,this),this.s=PropertyFactory.getProp(t,e.s,1,0,this),this.dynamicProperties.length?this.k=!0:(this.k=!1,this.convertEllToPath())}var m=(f.prototype={reset:a,getValue:function(){this.elem.globalData.frameId!==this.frameId&&(this.frameId=this.elem.globalData.frameId,this.iterateDynamicProperties(),this._mdf&&this.convertToPath())},convertStarToPath:function(){var t,e,r,i,s=2*Math.floor(this.pt.v),a=2*Math.PI/s,n=!0,o=this.or.v,h=this.ir.v,p=this.os.v,l=this.is.v,m=2*Math.PI*o/(2*s),f=2*Math.PI*h/(2*s),c=-Math.PI/2;c+=this.r.v;var d=3===this.data.d?-1:1;for(t=this.v._length=0;t<s;t+=1){r=n?p:l,i=n?m:f;var u=(e=n?o:h)*Math.cos(c),y=e*Math.sin(c),g=0===u&&0===y?0:y/Math.sqrt(u*u+y*y),v=0===u&&0===y?0:-u/Math.sqrt(u*u+y*y);u+=+this.p.v[0],y+=+this.p.v[1],this.v.setTripleAt(u,y,u-g*i*r*d,y-v*i*r*d,u+g*i*r*d,y+v*i*r*d,t,!0),n=!n,c+=a*d}},convertPolygonToPath:function(){var t,e=Math.floor(this.pt.v),r=2*Math.PI/e,i=this.or.v,s=this.os.v,a=2*Math.PI*i/(4*e),n=-Math.PI/2,o=3===this.data.d?-1:1;for(n+=this.r.v,t=this.v._length=0;t<e;t+=1){var h=i*Math.cos(n),p=i*Math.sin(n),l=0===h&&0===p?0:p/Math.sqrt(h*h+p*p),m=0===h&&0===p?0:-h/Math.sqrt(h*h+p*p);h+=+this.p.v[0],p+=+this.p.v[1],this.v.setTripleAt(h,p,h-l*a*s*o,p-m*a*s*o,h+l*a*s*o,p+m*a*s*o,t,!0),n+=r*o}this.paths.length=0,this.paths[0]=this.v}},extendPrototype([DynamicPropertyContainer],f),f);function f(t,e){this.v=shape_pool.newElement(),this.v.setPathData(!0,0),this.elem=t,this.comp=t.comp,this.data=e,this.frameId=-1,this.d=e.d,this.initDynamicPropertyContainer(t),1===e.sy?(this.ir=PropertyFactory.getProp(t,e.ir,0,0,this),this.is=PropertyFactory.getProp(t,e.is,0,.01,this),this.convertToPath=this.convertStarToPath):this.convertToPath=this.convertPolygonToPath,this.pt=PropertyFactory.getProp(t,e.pt,0,0,this),this.p=PropertyFactory.getProp(t,e.p,1,0,this),this.r=PropertyFactory.getProp(t,e.r,0,degToRads,this),this.or=PropertyFactory.getProp(t,e.or,0,0,this),this.os=PropertyFactory.getProp(t,e.os,0,.01,this),this.localShapeCollection=shapeCollection_pool.newShapeCollection(),this.localShapeCollection.addShape(this.v),this.paths=this.localShapeCollection,this.dynamicProperties.length?this.k=!0:(this.k=!1,this.convertToPath())}var c=(d.prototype={convertRectToPath:function(){var t=this.p.v[0],e=this.p.v[1],r=this.s.v[0]/2,i=this.s.v[1]/2,s=bm_min(r,i,this.r.v),a=s*(1-roundCorner);this.v._length=0,2===this.d||1===this.d?(this.v.setTripleAt(t+r,e-i+s,t+r,e-i+s,t+r,e-i+a,0,!0),this.v.setTripleAt(t+r,e+i-s,t+r,e+i-a,t+r,e+i-s,1,!0),0!==s?(this.v.setTripleAt(t+r-s,e+i,t+r-s,e+i,t+r-a,e+i,2,!0),this.v.setTripleAt(t-r+s,e+i,t-r+a,e+i,t-r+s,e+i,3,!0),this.v.setTripleAt(t-r,e+i-s,t-r,e+i-s,t-r,e+i-a,4,!0),this.v.setTripleAt(t-r,e-i+s,t-r,e-i+a,t-r,e-i+s,5,!0),this.v.setTripleAt(t-r+s,e-i,t-r+s,e-i,t-r+a,e-i,6,!0),this.v.setTripleAt(t+r-s,e-i,t+r-a,e-i,t+r-s,e-i,7,!0)):(this.v.setTripleAt(t-r,e+i,t-r+a,e+i,t-r,e+i,2),this.v.setTripleAt(t-r,e-i,t-r,e-i+a,t-r,e-i,3))):(this.v.setTripleAt(t+r,e-i+s,t+r,e-i+a,t+r,e-i+s,0,!0),0!==s?(this.v.setTripleAt(t+r-s,e-i,t+r-s,e-i,t+r-a,e-i,1,!0),this.v.setTripleAt(t-r+s,e-i,t-r+a,e-i,t-r+s,e-i,2,!0),this.v.setTripleAt(t-r,e-i+s,t-r,e-i+s,t-r,e-i+a,3,!0),this.v.setTripleAt(t-r,e+i-s,t-r,e+i-a,t-r,e+i-s,4,!0),this.v.setTripleAt(t-r+s,e+i,t-r+s,e+i,t-r+a,e+i,5,!0),this.v.setTripleAt(t+r-s,e+i,t+r-a,e+i,t+r-s,e+i,6,!0),this.v.setTripleAt(t+r,e+i-s,t+r,e+i-s,t+r,e+i-a,7,!0)):(this.v.setTripleAt(t-r,e-i,t-r+a,e-i,t-r,e-i,1,!0),this.v.setTripleAt(t-r,e+i,t-r,e+i-a,t-r,e+i,2,!0),this.v.setTripleAt(t+r,e+i,t+r-a,e+i,t+r,e+i,3,!0)))},getValue:function(t){this.elem.globalData.frameId!==this.frameId&&(this.frameId=this.elem.globalData.frameId,this.iterateDynamicProperties(),this._mdf&&this.convertRectToPath())},reset:a},extendPrototype([DynamicPropertyContainer],d),d);function d(t,e){this.v=shape_pool.newElement(),this.v.c=!0,this.localShapeCollection=shapeCollection_pool.newShapeCollection(),this.localShapeCollection.addShape(this.v),this.paths=this.localShapeCollection,this.elem=t,this.comp=t.comp,this.frameId=-1,this.d=e.d,this.initDynamicPropertyContainer(t),this.p=PropertyFactory.getProp(t,e.p,1,0,this),this.s=PropertyFactory.getProp(t,e.s,1,0,this),this.r=PropertyFactory.getProp(t,e.r,0,0,this),this.dynamicProperties.length?this.k=!0:(this.k=!1,this.convertRectToPath())}var u={getShapeProp:function(t,e,r){var i;return 3===r||4===r?i=(3===r?e.pt:e.ks).k.length?new o(t,e,r):new n(t,e,r):5===r?i=new c(t,e):6===r?i=new p(t,e):7===r&&(i=new m(t,e)),i.k&&t.addDynamicProperty(i),i},getConstructorFunction:function(){return n},getKeyframedConstructorFunction:function(){return o}};return u}(),ShapeModifiers=(Tr={},Ur={},Tr.registerModifier=function(t,e){Ur[t]||(Ur[t]=e)},Tr.getModifier=function(t,e,r){return new Ur[t](e,r)},Tr),Tr,Ur;function ShapeModifier(){}function TrimModifier(){}function RoundCornersModifier(){}function RepeaterModifier(){}function ShapeCollection(){this._length=0,this._maxLength=4,this.shapes=createSizedArray(this._maxLength)}function DashProperty(t,e,r,i){this.elem=t,this.frameId=-1,this.dataProps=createSizedArray(e.length),this.renderer=r,this.k=!1,this.dashStr="",this.dashArray=createTypedArray("float32",e.length?e.length-1:0),this.dashoffset=createTypedArray("float32",1),this.initDynamicPropertyContainer(i);var s,a,n=e.length||0;for(s=0;s<n;s+=1)a=PropertyFactory.getProp(t,e[s].v,0,0,this),this.k=a.k||this.k,this.dataProps[s]={n:e[s].n,p:a};this.k||this.getValue(!0),this._isAnimated=this.k}function GradientProperty(t,e,r){this.data=e,this.c=createTypedArray("uint8c",4*e.p);var i=e.k.k[0].s?e.k.k[0].s.length-4*e.p:e.k.k.length-4*e.p;this.o=createTypedArray("float32",i),this._cmdf=!1,this._omdf=!1,this._collapsable=this.checkCollapsable(),this._hasOpacity=i,this.initDynamicPropertyContainer(r),this.prop=PropertyFactory.getProp(t,e.k,1,null,this),this.k=this.prop.k,this.getValue(!0)}ShapeModifier.prototype.initModifierProperties=function(){},ShapeModifier.prototype.addShapeToModifier=function(){},ShapeModifier.prototype.addShape=function(t){if(!this.closed){var e={shape:t.sh,data:t,localShapeCollection:shapeCollection_pool.newShapeCollection()};this.shapes.push(e),this.addShapeToModifier(e),this._isAnimated&&t.setAsAnimated()}},ShapeModifier.prototype.init=function(t,e){this.shapes=[],this.elem=t,this.initDynamicPropertyContainer(t),this.initModifierProperties(t,e),this.frameId=initialDefaultFrame,this.closed=!1,this.k=!1,this.dynamicProperties.length?this.k=!0:this.getValue(!0)},ShapeModifier.prototype.processKeys=function(){this.elem.globalData.frameId!==this.frameId&&(this.frameId=this.elem.globalData.frameId,this.iterateDynamicProperties())},extendPrototype([DynamicPropertyContainer],ShapeModifier),extendPrototype([ShapeModifier],TrimModifier),TrimModifier.prototype.initModifierProperties=function(t,e){this.s=PropertyFactory.getProp(t,e.s,0,.01,this),this.e=PropertyFactory.getProp(t,e.e,0,.01,this),this.o=PropertyFactory.getProp(t,e.o,0,0,this),this.sValue=0,this.eValue=0,this.getValue=this.processKeys,this.m=e.m,this._isAnimated=!!this.s.effectsSequence.length||!!this.e.effectsSequence.length||!!this.o.effectsSequence.length},TrimModifier.prototype.addShapeToModifier=function(t){t.pathsData=[]},TrimModifier.prototype.calculateShapeEdges=function(t,e,r,i,s){var a=[];e<=1?a.push({s:t,e:e}):1<=t?a.push({s:t-1,e:e-1}):(a.push({s:t,e:1}),a.push({s:0,e:e-1}));var n,o,h=[],p=a.length;for(n=0;n<p;n+=1){var l,m;if((o=a[n]).e*s<i||o.s*s>i+r);else l=o.s*s<=i?0:(o.s*s-i)/r,m=o.e*s>=i+r?1:(o.e*s-i)/r,h.push([l,m])}return h.length||h.push([0,0]),h},TrimModifier.prototype.releasePathsData=function(t){var e,r=t.length;for(e=0;e<r;e+=1)segments_length_pool.release(t[e]);return t.length=0,t},TrimModifier.prototype.processShapes=function(t){var e,r,i;if(this._mdf||t){var s=this.o.v%360/360;if(s<0&&(s+=1),e=(1<this.s.v?1:this.s.v<0?0:this.s.v)+s,(r=(1<this.e.v?1:this.e.v<0?0:this.e.v)+s)<e){var a=e;e=r,r=a}e=1e-4*Math.round(1e4*e),r=1e-4*Math.round(1e4*r),this.sValue=e,this.eValue=r}else e=this.sValue,r=this.eValue;var n,o,h,p,l,m,f=this.shapes.length,c=0;if(r===e)for(n=0;n<f;n+=1)this.shapes[n].localShapeCollection.releaseShapes(),this.shapes[n].shape._mdf=!0,this.shapes[n].shape.paths=this.shapes[n].localShapeCollection;else if(1===r&&0===e||0===r&&1===e){if(this._mdf)for(n=0;n<f;n+=1)this.shapes[n].pathsData.length=0,this.shapes[n].shape._mdf=!0}else{var d,u,y=[];for(n=0;n<f;n+=1)if((d=this.shapes[n]).shape._mdf||this._mdf||t||2===this.m){if(h=(i=d.shape.paths)._length,m=0,!d.shape._mdf&&d.pathsData.length)m=d.totalShapeLength;else{for(p=this.releasePathsData(d.pathsData),o=0;o<h;o+=1)l=bez.getSegmentsLength(i.shapes[o]),p.push(l),m+=l.totalLength;d.totalShapeLength=m,d.pathsData=p}c+=m,d.shape._mdf=!0}else d.shape.paths=d.localShapeCollection;var g,v=e,P=r,b=0;for(n=f-1;0<=n;n-=1)if((d=this.shapes[n]).shape._mdf){for((u=d.localShapeCollection).releaseShapes(),2===this.m&&1<f?(g=this.calculateShapeEdges(e,r,d.totalShapeLength,b,c),b+=d.totalShapeLength):g=[[v,P]],h=g.length,o=0;o<h;o+=1){v=g[o][0],P=g[o][1],y.length=0,P<=1?y.push({s:d.totalShapeLength*v,e:d.totalShapeLength*P}):1<=v?y.push({s:d.totalShapeLength*(v-1),e:d.totalShapeLength*(P-1)}):(y.push({s:d.totalShapeLength*v,e:d.totalShapeLength}),y.push({s:0,e:d.totalShapeLength*(P-1)}));var x=this.addShapes(d,y[0]);if(y[0].s!==y[0].e){if(1<y.length)if(d.shape.paths.shapes[d.shape.paths._length-1].c){var _=x.pop();this.addPaths(x,u),x=this.addShapes(d,y[1],_)}else this.addPaths(x,u),x=this.addShapes(d,y[1]);this.addPaths(x,u)}}d.shape.paths=u}}},TrimModifier.prototype.addPaths=function(t,e){var r,i=t.length;for(r=0;r<i;r+=1)e.addShape(t[r])},TrimModifier.prototype.addSegment=function(t,e,r,i,s,a,n){s.setXYAt(e[0],e[1],"o",a),s.setXYAt(r[0],r[1],"i",a+1),n&&s.setXYAt(t[0],t[1],"v",a),s.setXYAt(i[0],i[1],"v",a+1)},TrimModifier.prototype.addSegmentFromArray=function(t,e,r,i){e.setXYAt(t[1],t[5],"o",r),e.setXYAt(t[2],t[6],"i",r+1),i&&e.setXYAt(t[0],t[4],"v",r),e.setXYAt(t[3],t[7],"v",r+1)},TrimModifier.prototype.addShapes=function(t,e,r){var i,s,a,n,o,h,p,l,m=t.pathsData,f=t.shape.paths.shapes,c=t.shape.paths._length,d=0,u=[],y=!0;for(l=r?(o=r._length,r._length):(r=shape_pool.newElement(),o=0),u.push(r),i=0;i<c;i+=1){for(h=m[i].lengths,r.c=f[i].c,a=f[i].c?h.length:h.length+1,s=1;s<a;s+=1)if(d+(n=h[s-1]).addedLength<e.s)d+=n.addedLength,r.c=!1;else{if(d>e.e){r.c=!1;break}e.s<=d&&e.e>=d+n.addedLength?(this.addSegment(f[i].v[s-1],f[i].o[s-1],f[i].i[s],f[i].v[s],r,o,y),y=!1):(p=bez.getNewSegment(f[i].v[s-1],f[i].v[s],f[i].o[s-1],f[i].i[s],(e.s-d)/n.addedLength,(e.e-d)/n.addedLength,h[s-1]),this.addSegmentFromArray(p,r,o,y),y=!1,r.c=!1),d+=n.addedLength,o+=1}if(f[i].c&&h.length){if(n=h[s-1],d<=e.e){var g=h[s-1].addedLength;e.s<=d&&e.e>=d+g?(this.addSegment(f[i].v[s-1],f[i].o[s-1],f[i].i[0],f[i].v[0],r,o,y),y=!1):(p=bez.getNewSegment(f[i].v[s-1],f[i].v[0],f[i].o[s-1],f[i].i[0],(e.s-d)/g,(e.e-d)/g,h[s-1]),this.addSegmentFromArray(p,r,o,y),y=!1,r.c=!1)}else r.c=!1;d+=n.addedLength,o+=1}if(r._length&&(r.setXYAt(r.v[l][0],r.v[l][1],"i",l),r.setXYAt(r.v[r._length-1][0],r.v[r._length-1][1],"o",r._length-1)),d>e.e)break;i<c-1&&(r=shape_pool.newElement(),y=!0,u.push(r),o=0)}return u},ShapeModifiers.registerModifier("tm",TrimModifier),extendPrototype([ShapeModifier],RoundCornersModifier),RoundCornersModifier.prototype.initModifierProperties=function(t,e){this.getValue=this.processKeys,this.rd=PropertyFactory.getProp(t,e.r,0,null,this),this._isAnimated=!!this.rd.effectsSequence.length},RoundCornersModifier.prototype.processPath=function(t,e){var r=shape_pool.newElement();r.c=t.c;var i,s,a,n,o,h,p,l,m,f,c,d,u,y=t._length,g=0;for(i=0;i<y;i+=1)s=t.v[i],n=t.o[i],a=t.i[i],s[0]===n[0]&&s[1]===n[1]&&s[0]===a[0]&&s[1]===a[1]?0!==i&&i!==y-1||t.c?(o=0===i?t.v[y-1]:t.v[i-1],p=(h=Math.sqrt(Math.pow(s[0]-o[0],2)+Math.pow(s[1]-o[1],2)))?Math.min(h/2,e)/h:0,l=d=s[0]+(o[0]-s[0])*p,m=u=s[1]-(s[1]-o[1])*p,f=l-(l-s[0])*roundCorner,c=m-(m-s[1])*roundCorner,r.setTripleAt(l,m,f,c,d,u,g),g+=1,o=i===y-1?t.v[0]:t.v[i+1],p=(h=Math.sqrt(Math.pow(s[0]-o[0],2)+Math.pow(s[1]-o[1],2)))?Math.min(h/2,e)/h:0,l=f=s[0]+(o[0]-s[0])*p,m=c=s[1]+(o[1]-s[1])*p,d=l-(l-s[0])*roundCorner,u=m-(m-s[1])*roundCorner,r.setTripleAt(l,m,f,c,d,u,g)):r.setTripleAt(s[0],s[1],n[0],n[1],a[0],a[1],g):r.setTripleAt(t.v[i][0],t.v[i][1],t.o[i][0],t.o[i][1],t.i[i][0],t.i[i][1],g),g+=1;return r},RoundCornersModifier.prototype.processShapes=function(t){var e,r,i,s,a,n,o=this.shapes.length,h=this.rd.v;if(0!==h)for(r=0;r<o;r+=1){if((a=this.shapes[r]).shape.paths,n=a.localShapeCollection,a.shape._mdf||this._mdf||t)for(n.releaseShapes(),a.shape._mdf=!0,e=a.shape.paths.shapes,s=a.shape.paths._length,i=0;i<s;i+=1)n.addShape(this.processPath(e[i],h));a.shape.paths=a.localShapeCollection}this.dynamicProperties.length||(this._mdf=!1)},ShapeModifiers.registerModifier("rd",RoundCornersModifier),extendPrototype([ShapeModifier],RepeaterModifier),RepeaterModifier.prototype.initModifierProperties=function(t,e){this.getValue=this.processKeys,this.c=PropertyFactory.getProp(t,e.c,0,null,this),this.o=PropertyFactory.getProp(t,e.o,0,null,this),this.tr=TransformPropertyFactory.getTransformProperty(t,e.tr,this),this.so=PropertyFactory.getProp(t,e.tr.so,0,.01,this),this.eo=PropertyFactory.getProp(t,e.tr.eo,0,.01,this),this.data=e,this.dynamicProperties.length||this.getValue(!0),this._isAnimated=!!this.dynamicProperties.length,this.pMatrix=new Matrix,this.rMatrix=new Matrix,this.sMatrix=new Matrix,this.tMatrix=new Matrix,this.matrix=new Matrix},RepeaterModifier.prototype.applyTransforms=function(t,e,r,i,s,a){var n=a?-1:1,o=i.s.v[0]+(1-i.s.v[0])*(1-s),h=i.s.v[1]+(1-i.s.v[1])*(1-s);t.translate(i.p.v[0]*n*s,i.p.v[1]*n*s,i.p.v[2]),e.translate(-i.a.v[0],-i.a.v[1],i.a.v[2]),e.rotate(-i.r.v*n*s),e.translate(i.a.v[0],i.a.v[1],i.a.v[2]),r.translate(-i.a.v[0],-i.a.v[1],i.a.v[2]),r.scale(a?1/o:o,a?1/h:h),r.translate(i.a.v[0],i.a.v[1],i.a.v[2])},RepeaterModifier.prototype.init=function(t,e,r,i){this.elem=t,this.arr=e,this.pos=r,this.elemsData=i,this._currentCopies=0,this._elements=[],this._groups=[],this.frameId=-1,this.initDynamicPropertyContainer(t),this.initModifierProperties(t,e[r]);for(;0<r;)r-=1,this._elements.unshift(e[r]),1;this.dynamicProperties.length?this.k=!0:this.getValue(!0)},RepeaterModifier.prototype.resetElements=function(t){var e,r=t.length;for(e=0;e<r;e+=1)t[e]._processed=!1,"gr"===t[e].ty&&this.resetElements(t[e].it)},RepeaterModifier.prototype.cloneElements=function(t){t.length;var e=JSON.parse(JSON.stringify(t));return this.resetElements(e),e},RepeaterModifier.prototype.changeGroupRender=function(t,e){var r,i=t.length;for(r=0;r<i;r+=1)t[r]._render=e,"gr"===t[r].ty&&this.changeGroupRender(t[r].it,e)},RepeaterModifier.prototype.processShapes=function(t){var e,r,i,s,a;if(this._mdf||t){var n,o=Math.ceil(this.c.v);if(this._groups.length<o){for(;this._groups.length<o;){var h={it:this.cloneElements(this._elements),ty:"gr"};h.it.push({a:{a:0,ix:1,k:[0,0]},nm:"Transform",o:{a:0,ix:7,k:100},p:{a:0,ix:2,k:[0,0]},r:{a:1,ix:6,k:[{s:0,e:0,t:0},{s:0,e:0,t:1}]},s:{a:0,ix:3,k:[100,100]},sa:{a:0,ix:5,k:0},sk:{a:0,ix:4,k:0},ty:"tr"}),this.arr.splice(0,0,h),this._groups.splice(0,0,h),this._currentCopies+=1}this.elem.reloadShapes()}for(i=a=0;i<=this._groups.length-1;i+=1)n=a<o,this._groups[i]._render=n,this.changeGroupRender(this._groups[i].it,n),a+=1;this._currentCopies=o;var p=this.o.v,l=p%1,m=0<p?Math.floor(p):Math.ceil(p),f=(this.tr.v.props,this.pMatrix.props),c=this.rMatrix.props,d=this.sMatrix.props;this.pMatrix.reset(),this.rMatrix.reset(),this.sMatrix.reset(),this.tMatrix.reset(),this.matrix.reset();var u,y,g=0;if(0<p){for(;g<m;)this.applyTransforms(this.pMatrix,this.rMatrix,this.sMatrix,this.tr,1,!1),g+=1;l&&(this.applyTransforms(this.pMatrix,this.rMatrix,this.sMatrix,this.tr,l,!1),g+=l)}else if(p<0){for(;m<g;)this.applyTransforms(this.pMatrix,this.rMatrix,this.sMatrix,this.tr,1,!0),g-=1;l&&(this.applyTransforms(this.pMatrix,this.rMatrix,this.sMatrix,this.tr,-l,!0),g-=l)}for(i=1===this.data.m?0:this._currentCopies-1,s=1===this.data.m?1:-1,a=this._currentCopies;a;){if(y=(r=(e=this.elemsData[i].it)[e.length-1].transform.mProps.v.props).length,e[e.length-1].transform.mProps._mdf=!0,e[e.length-1].transform.op._mdf=!0,e[e.length-1].transform.op.v=this.so.v+(this.eo.v-this.so.v)*(i/(this._currentCopies-1)),0!==g){for((0!==i&&1===s||i!==this._currentCopies-1&&-1===s)&&this.applyTransforms(this.pMatrix,this.rMatrix,this.sMatrix,this.tr,1,!1),this.matrix.transform(c[0],c[1],c[2],c[3],c[4],c[5],c[6],c[7],c[8],c[9],c[10],c[11],c[12],c[13],c[14],c[15]),this.matrix.transform(d[0],d[1],d[2],d[3],d[4],d[5],d[6],d[7],d[8],d[9],d[10],d[11],d[12],d[13],d[14],d[15]),this.matrix.transform(f[0],f[1],f[2],f[3],f[4],f[5],f[6],f[7],f[8],f[9],f[10],f[11],f[12],f[13],f[14],f[15]),u=0;u<y;u+=1)r[u]=this.matrix.props[u];this.matrix.reset()}else for(this.matrix.reset(),u=0;u<y;u+=1)r[u]=this.matrix.props[u];g+=1,a-=1,i+=s}}else for(a=this._currentCopies,i=0,s=1;a;)r=(e=this.elemsData[i].it)[e.length-1].transform.mProps.v.props,e[e.length-1].transform.mProps._mdf=!1,e[e.length-1].transform.op._mdf=!1,a-=1,i+=s},RepeaterModifier.prototype.addShape=function(){},ShapeModifiers.registerModifier("rp",RepeaterModifier),ShapeCollection.prototype.addShape=function(t){this._length===this._maxLength&&(this.shapes=this.shapes.concat(createSizedArray(this._maxLength)),this._maxLength*=2),this.shapes[this._length]=t,this._length+=1},ShapeCollection.prototype.releaseShapes=function(){var t;for(t=0;t<this._length;t+=1)shape_pool.release(this.shapes[t]);this._length=0},DashProperty.prototype.getValue=function(t){if((this.elem.globalData.frameId!==this.frameId||t)&&(this.frameId=this.elem.globalData.frameId,this.iterateDynamicProperties(),this._mdf=this._mdf||t,this._mdf)){var e=0,r=this.dataProps.length;for("svg"===this.renderer&&(this.dashStr=""),e=0;e<r;e+=1)"o"!=this.dataProps[e].n?"svg"===this.renderer?this.dashStr+=" "+this.dataProps[e].p.v:this.dashArray[e]=this.dataProps[e].p.v:this.dashoffset[0]=this.dataProps[e].p.v}},extendPrototype([DynamicPropertyContainer],DashProperty),GradientProperty.prototype.comparePoints=function(t,e){for(var r=0,i=this.o.length/2;r<i;){if(.01<Math.abs(t[4*r]-t[4*e+2*r]))return!1;r+=1}return!0},GradientProperty.prototype.checkCollapsable=function(){if(this.o.length/2!=this.c.length/4)return!1;if(this.data.k.k[0].s)for(var t=0,e=this.data.k.k.length;t<e;){if(!this.comparePoints(this.data.k.k[t].s,this.data.p))return!1;t+=1}else if(!this.comparePoints(this.data.k.k,this.data.p))return!1;return!0},GradientProperty.prototype.getValue=function(t){if(this.prop.getValue(),this._mdf=!1,this._cmdf=!1,this._omdf=!1,this.prop._mdf||t){var e,r,i,s=4*this.data.p;for(e=0;e<s;e+=1)r=e%4==0?100:255,i=Math.round(this.prop.v[e]*r),this.c[e]!==i&&(this.c[e]=i,this._cmdf=!t);if(this.o.length)for(s=this.prop.v.length,e=4*this.data.p;e<s;e+=1)r=e%2==0?100:1,i=e%2==0?Math.round(100*this.prop.v[e]):this.prop.v[e],this.o[e-4*this.data.p]!==i&&(this.o[e-4*this.data.p]=i,this._omdf=!t);this._mdf=!t}},extendPrototype([DynamicPropertyContainer],GradientProperty);var buildShapeString=function(t,e,r,i){if(0===e)return"";var s,a=t.o,n=t.i,o=t.v,h=" M"+i.applyToPointStringified(o[0][0],o[0][1]);for(s=1;s<e;s+=1)h+=" C"+i.applyToPointStringified(a[s-1][0],a[s-1][1])+" "+i.applyToPointStringified(n[s][0],n[s][1])+" "+i.applyToPointStringified(o[s][0],o[s][1]);return r&&e&&(h+=" C"+i.applyToPointStringified(a[s-1][0],a[s-1][1])+" "+i.applyToPointStringified(n[0][0],n[0][1])+" "+i.applyToPointStringified(o[0][0],o[0][1]),h+="z"),h},ImagePreloader=function(){},featureSupport=(Iv={maskType:!0},(/MSIE 10/i.test(navigator.userAgent)||/MSIE 9/i.test(navigator.userAgent)||/rv:11.0/i.test(navigator.userAgent)||/Edge\/\d./i.test(navigator.userAgent))&&(Iv.maskType=!1),Iv),Iv,filtersFactory=(Jv={},Jv.createFilter=function(t){var e=createNS("filter");return e.setAttribute("id",t),e.setAttribute("filterUnits","objectBoundingBox"),e.setAttribute("x","0%"),e.setAttribute("y","0%"),e.setAttribute("width","100%"),e.setAttribute("height","100%"),e},Jv.createAlphaToLuminanceFilter=function(){var t=createNS("feColorMatrix");return t.setAttribute("type","matrix"),t.setAttribute("color-interpolation-filters","sRGB"),t.setAttribute("values","0 0 0 1 0  0 0 0 1 0  0 0 0 1 0  0 0 0 1 1"),t},Jv),Jv,assetLoader={load:function(t,e,r){var i,s=new XMLHttpRequest;s.open("GET",t,!0);try{s.responseType="json"}catch(t){}s.send(),s.onreadystatechange=function(){if(4==s.readyState)if(200==s.status)i=Pv(s),e(i);else try{i=Pv(s),e(i)}catch(t){r&&r(t)}}}};function Pv(t){return t.response&&"object"==typeof t.response?t.response:t.response&&"string"==typeof t.response?JSON.parse(t.response):t.responseText?JSON.parse(t.responseText):void 0}var assetLoader=null;function TextAnimatorProperty(t,e,r){this._isFirstFrame=!0,this._hasMaskedPath=!1,this._frameId=-1,this._textData=t,this._renderType=e,this._elem=r,this._animatorsData=createSizedArray(this._textData.a.length),this._pathData={},this._moreOptions={alignment:{}},this.renderedLetters=[],this.lettersChangedFlag=!1,this.initDynamicPropertyContainer(r)}function TextAnimatorDataProperty(t,e,r){var i={propType:!1},s=PropertyFactory.getProp,a=e.a;this.a={r:a.r?s(t,a.r,0,degToRads,r):i,rx:a.rx?s(t,a.rx,0,degToRads,r):i,ry:a.ry?s(t,a.ry,0,degToRads,r):i,sk:a.sk?s(t,a.sk,0,degToRads,r):i,sa:a.sa?s(t,a.sa,0,degToRads,r):i,s:a.s?s(t,a.s,1,.01,r):i,a:a.a?s(t,a.a,1,0,r):i,o:a.o?s(t,a.o,0,.01,r):i,p:a.p?s(t,a.p,1,0,r):i,sw:a.sw?s(t,a.sw,0,0,r):i,sc:a.sc?s(t,a.sc,1,0,r):i,fc:a.fc?s(t,a.fc,1,0,r):i,fh:a.fh?s(t,a.fh,0,0,r):i,fs:a.fs?s(t,a.fs,0,.01,r):i,fb:a.fb?s(t,a.fb,0,.01,r):i,t:a.t?s(t,a.t,0,0,r):i},this.s=TextSelectorProp.getTextSelectorProp(t,e.s,r),this.s.t=e.s.t}function LetterProps(t,e,r,i,s,a){this.o=t,this.sw=e,this.sc=r,this.fc=i,this.m=s,this.p=a,this._mdf={o:!0,sw:!!e,sc:!!r,fc:!!i,m:!0,p:!0}}function TextProperty(t,e){this._frameId=initialDefaultFrame,this.pv="",this.v="",this.kf=!1,this._isFirstFrame=!0,this._mdf=!1,this.data=e,this.elem=t,this.comp=this.elem.comp,this.keysIndex=0,this.canResize=!1,this.minimumFontSize=1,this.effectsSequence=[],this.currentData={ascent:0,boxWidth:this.defaultBoxWidth,f:"",fStyle:"",fWeight:"",fc:"",j:"",justifyOffset:"",l:[],lh:0,lineWidths:[],ls:"",of:"",s:"",sc:"",sw:0,t:0,tr:0,sz:0,ps:null,fillColorAnim:!1,strokeColorAnim:!1,strokeWidthAnim:!1,yOffset:0,finalSize:0,finalText:[],finalLineHeight:0,__complete:!1},this.copyData(this.currentData,this.data.d.k[0].s),this.searchProperty()||this.completeTextData(this.currentData)}TextAnimatorProperty.prototype.searchProperties=function(){var t,e,r=this._textData.a.length,i=PropertyFactory.getProp;for(t=0;t<r;t+=1)e=this._textData.a[t],this._animatorsData[t]=new TextAnimatorDataProperty(this._elem,e,this);this._textData.p&&"m"in this._textData.p?(this._pathData={f:i(this._elem,this._textData.p.f,0,0,this),l:i(this._elem,this._textData.p.l,0,0,this),r:this._textData.p.r,m:this._elem.maskManager.getMaskProperty(this._textData.p.m)},this._hasMaskedPath=!0):this._hasMaskedPath=!1,this._moreOptions.alignment=i(this._elem,this._textData.m.a,1,0,this)},TextAnimatorProperty.prototype.getMeasures=function(t,e){if(this.lettersChangedFlag=e,this._mdf||this._isFirstFrame||e||this._hasMaskedPath&&this._pathData.m._mdf){this._isFirstFrame=!1;var r,i,s,a,n,o,h,p,l,m,f,c,d,u,y,g,v,P,b,x=this._moreOptions.alignment.v,_=this._animatorsData,S=this._textData,T=this.mHelper,A=this._renderType,C=this.renderedLetters.length,E=(this.data,t.l);if(this._hasMaskedPath){if(b=this._pathData.m,!this._pathData.n||this._pathData._mdf){var k,D=b.v;for(this._pathData.r&&(D=D.reverse()),n={tLength:0,segments:[]},a=D._length-1,s=g=0;s<a;s+=1)k=bez.buildBezierData(D.v[s],D.v[s+1],[D.o[s][0]-D.v[s][0],D.o[s][1]-D.v[s][1]],[D.i[s+1][0]-D.v[s+1][0],D.i[s+1][1]-D.v[s+1][1]]),n.tLength+=k.segmentLength,n.segments.push(k),g+=k.segmentLength;s=a,b.v.c&&(k=bez.buildBezierData(D.v[s],D.v[0],[D.o[s][0]-D.v[s][0],D.o[s][1]-D.v[s][1]],[D.i[0][0]-D.v[0][0],D.i[0][1]-D.v[0][1]]),n.tLength+=k.segmentLength,n.segments.push(k),g+=k.segmentLength),this._pathData.pi=n}if(n=this._pathData.pi,o=this._pathData.f.v,m=1,l=!(p=f=0),u=n.segments,o<0&&b.v.c)for(n.tLength<Math.abs(o)&&(o=-Math.abs(o)%n.tLength),m=(d=u[f=u.length-1].points).length-1;o<0;)o+=d[m].partialLength,(m-=1)<0&&(m=(d=u[f-=1].points).length-1);c=(d=u[f].points)[m-1],y=(h=d[m]).partialLength}a=E.length,i=r=0;var I,M,w,F,V=1.2*t.finalSize*.714,R=!0;w=_.length;var L,z,O,B,N,G,j,J,K,q,H,W,Y,X=-1,Q=o,$=f,U=m,Z=-1,tt="",et=this.defaultPropsArray;if(2===t.j||1===t.j){var rt=0,it=0,st=2===t.j?-.5:-1,at=0,nt=!0;for(s=0;s<a;s+=1)if(E[s].n){for(rt&&(rt+=it);at<s;)E[at].animatorJustifyOffset=rt,at+=1;nt=!(rt=0)}else{for(M=0;M<w;M+=1)(I=_[M].a).t.propType&&(nt&&2===t.j&&(it+=I.t.v*st),(L=_[M].s.getMult(E[s].anIndexes[M],S.a[M].s.totalChars)).length?rt+=I.t.v*L[0]*st:rt+=I.t.v*L*st);nt=!1}for(rt&&(rt+=it);at<s;)E[at].animatorJustifyOffset=rt,at+=1}for(s=0;s<a;s+=1){if(T.reset(),N=1,E[s].n)r=0,i+=t.yOffset,i+=R?1:0,o=Q,R=!1,0,this._hasMaskedPath&&(m=U,c=(d=u[f=$].points)[m-1],y=(h=d[m]).partialLength,p=0),Y=q=W=tt="",et=this.defaultPropsArray;else{if(this._hasMaskedPath){if(Z!==E[s].line){switch(t.j){case 1:o+=g-t.lineWidths[E[s].line];break;case 2:o+=(g-t.lineWidths[E[s].line])/2}Z=E[s].line}X!==E[s].ind&&(E[X]&&(o+=E[X].extra),o+=E[s].an/2,X=E[s].ind),o+=x[0]*E[s].an/200;var ot=0;for(M=0;M<w;M+=1)(I=_[M].a).p.propType&&((L=_[M].s.getMult(E[s].anIndexes[M],S.a[M].s.totalChars)).length?ot+=I.p.v[0]*L[0]:ot+=I.p.v[0]*L),I.a.propType&&((L=_[M].s.getMult(E[s].anIndexes[M],S.a[M].s.totalChars)).length?ot+=I.a.v[0]*L[0]:ot+=I.a.v[0]*L);for(l=!0;l;)o+ot<=p+y||!d?(v=(o+ot-p)/h.partialLength,O=c.point[0]+(h.point[0]-c.point[0])*v,B=c.point[1]+(h.point[1]-c.point[1])*v,T.translate(-x[0]*E[s].an/200,-x[1]*V/100),l=!1):d&&(p+=h.partialLength,(m+=1)>=d.length&&(m=0,d=u[f+=1]?u[f].points:b.v.c?u[f=m=0].points:(p-=h.partialLength,null)),d&&(c=h,y=(h=d[m]).partialLength));z=E[s].an/2-E[s].add,T.translate(-z,0,0)}else z=E[s].an/2-E[s].add,T.translate(-z,0,0),T.translate(-x[0]*E[s].an/200,-x[1]*V/100,0);for(E[s].l/2,M=0;M<w;M+=1)(I=_[M].a).t.propType&&(L=_[M].s.getMult(E[s].anIndexes[M],S.a[M].s.totalChars),0===r&&0===t.j||(this._hasMaskedPath?L.length?o+=I.t.v*L[0]:o+=I.t.v*L:L.length?r+=I.t.v*L[0]:r+=I.t.v*L));for(E[s].l/2,t.strokeWidthAnim&&(j=t.sw||0),t.strokeColorAnim&&(G=t.sc?[t.sc[0],t.sc[1],t.sc[2]]:[0,0,0]),t.fillColorAnim&&t.fc&&(J=[t.fc[0],t.fc[1],t.fc[2]]),M=0;M<w;M+=1)(I=_[M].a).a.propType&&((L=_[M].s.getMult(E[s].anIndexes[M],S.a[M].s.totalChars)).length?T.translate(-I.a.v[0]*L[0],-I.a.v[1]*L[1],I.a.v[2]*L[2]):T.translate(-I.a.v[0]*L,-I.a.v[1]*L,I.a.v[2]*L));for(M=0;M<w;M+=1)(I=_[M].a).s.propType&&((L=_[M].s.getMult(E[s].anIndexes[M],S.a[M].s.totalChars)).length?T.scale(1+(I.s.v[0]-1)*L[0],1+(I.s.v[1]-1)*L[1],1):T.scale(1+(I.s.v[0]-1)*L,1+(I.s.v[1]-1)*L,1));for(M=0;M<w;M+=1){if(I=_[M].a,L=_[M].s.getMult(E[s].anIndexes[M],S.a[M].s.totalChars),I.sk.propType&&(L.length?T.skewFromAxis(-I.sk.v*L[0],I.sa.v*L[1]):T.skewFromAxis(-I.sk.v*L,I.sa.v*L)),I.r.propType&&(L.length?T.rotateZ(-I.r.v*L[2]):T.rotateZ(-I.r.v*L)),I.ry.propType&&(L.length?T.rotateY(I.ry.v*L[1]):T.rotateY(I.ry.v*L)),I.rx.propType&&(L.length?T.rotateX(I.rx.v*L[0]):T.rotateX(I.rx.v*L)),I.o.propType&&(L.length?N+=(I.o.v*L[0]-N)*L[0]:N+=(I.o.v*L-N)*L),t.strokeWidthAnim&&I.sw.propType&&(L.length?j+=I.sw.v*L[0]:j+=I.sw.v*L),t.strokeColorAnim&&I.sc.propType)for(K=0;K<3;K+=1)L.length?G[K]=G[K]+(I.sc.v[K]-G[K])*L[0]:G[K]=G[K]+(I.sc.v[K]-G[K])*L;if(t.fillColorAnim&&t.fc){if(I.fc.propType)for(K=0;K<3;K+=1)L.length?J[K]=J[K]+(I.fc.v[K]-J[K])*L[0]:J[K]=J[K]+(I.fc.v[K]-J[K])*L;I.fh.propType&&(J=L.length?addHueToRGB(J,I.fh.v*L[0]):addHueToRGB(J,I.fh.v*L)),I.fs.propType&&(J=L.length?addSaturationToRGB(J,I.fs.v*L[0]):addSaturationToRGB(J,I.fs.v*L)),I.fb.propType&&(J=L.length?addBrightnessToRGB(J,I.fb.v*L[0]):addBrightnessToRGB(J,I.fb.v*L))}}for(M=0;M<w;M+=1)(I=_[M].a).p.propType&&(L=_[M].s.getMult(E[s].anIndexes[M],S.a[M].s.totalChars),this._hasMaskedPath?L.length?T.translate(0,I.p.v[1]*L[0],-I.p.v[2]*L[1]):T.translate(0,I.p.v[1]*L,-I.p.v[2]*L):L.length?T.translate(I.p.v[0]*L[0],I.p.v[1]*L[1],-I.p.v[2]*L[2]):T.translate(I.p.v[0]*L,I.p.v[1]*L,-I.p.v[2]*L));if(t.strokeWidthAnim&&(q=j<0?0:j),t.strokeColorAnim&&(H="rgb("+Math.round(255*G[0])+","+Math.round(255*G[1])+","+Math.round(255*G[2])+")"),t.fillColorAnim&&t.fc&&(W="rgb("+Math.round(255*J[0])+","+Math.round(255*J[1])+","+Math.round(255*J[2])+")"),this._hasMaskedPath){if(T.translate(0,-t.ls),T.translate(0,x[1]*V/100+i,0),S.p.p){P=(h.point[1]-c.point[1])/(h.point[0]-c.point[0]);var ht=180*Math.atan(P)/Math.PI;h.point[0]<c.point[0]&&(ht+=180),T.rotate(-ht*Math.PI/180)}T.translate(O,B,0),o-=x[0]*E[s].an/200,E[s+1]&&X!==E[s+1].ind&&(o+=E[s].an/2,o+=t.tr/1e3*t.finalSize)}else{switch(T.translate(r,i,0),t.ps&&T.translate(t.ps[0],t.ps[1]+t.ascent,0),t.j){case 1:T.translate(E[s].animatorJustifyOffset+t.justifyOffset+(t.boxWidth-t.lineWidths[E[s].line]),0,0);break;case 2:T.translate(E[s].animatorJustifyOffset+t.justifyOffset+(t.boxWidth-t.lineWidths[E[s].line])/2,0,0)}T.translate(0,-t.ls),T.translate(z,0,0),T.translate(x[0]*E[s].an/200,x[1]*V/100,0),r+=E[s].l+t.tr/1e3*t.finalSize}"html"===A?tt=T.toCSS():"svg"===A?tt=T.to2dCSS():et=[T.props[0],T.props[1],T.props[2],T.props[3],T.props[4],T.props[5],T.props[6],T.props[7],T.props[8],T.props[9],T.props[10],T.props[11],T.props[12],T.props[13],T.props[14],T.props[15]],Y=N}C<=s?(F=new LetterProps(Y,q,H,W,tt,et),this.renderedLetters.push(F),C+=1,this.lettersChangedFlag=!0):(F=this.renderedLetters[s],this.lettersChangedFlag=F.update(Y,q,H,W,tt,et)||this.lettersChangedFlag)}}},TextAnimatorProperty.prototype.getValue=function(){this._elem.globalData.frameId!==this._frameId&&(this._frameId=this._elem.globalData.frameId,this.iterateDynamicProperties())},TextAnimatorProperty.prototype.mHelper=new Matrix,TextAnimatorProperty.prototype.defaultPropsArray=[],extendPrototype([DynamicPropertyContainer],TextAnimatorProperty),LetterProps.prototype.update=function(t,e,r,i,s,a){this._mdf.o=!1,this._mdf.sw=!1,this._mdf.sc=!1,this._mdf.fc=!1,this._mdf.m=!1;var n=this._mdf.p=!1;return this.o!==t&&(this.o=t,n=this._mdf.o=!0),this.sw!==e&&(this.sw=e,n=this._mdf.sw=!0),this.sc!==r&&(this.sc=r,n=this._mdf.sc=!0),this.fc!==i&&(this.fc=i,n=this._mdf.fc=!0),this.m!==s&&(this.m=s,n=this._mdf.m=!0),!a.length||this.p[0]===a[0]&&this.p[1]===a[1]&&this.p[4]===a[4]&&this.p[5]===a[5]&&this.p[12]===a[12]&&this.p[13]===a[13]||(this.p=a,n=this._mdf.p=!0),n},TextProperty.prototype.defaultBoxWidth=[0,0],TextProperty.prototype.copyData=function(t,e){for(var r in e)e.hasOwnProperty(r)&&(t[r]=e[r]);return t},TextProperty.prototype.setCurrentData=function(t){t.__complete||this.completeTextData(t),this.currentData=t,this.currentData.boxWidth=this.currentData.boxWidth||this.defaultBoxWidth,this._mdf=!0},TextProperty.prototype.searchProperty=function(){return this.searchKeyframes()},TextProperty.prototype.searchKeyframes=function(){return this.kf=1<this.data.d.k.length,this.kf&&this.addEffect(this.getKeyframeValue.bind(this)),this.kf},TextProperty.prototype.addEffect=function(t){this.effectsSequence.push(t),this.elem.addDynamicProperty(this)},TextProperty.prototype.getValue=function(t){if(this.elem.globalData.frameId!==this.frameId&&this.effectsSequence.length||t){this.currentData.t=this.data.d.k[this.keysIndex].s.t;var e=this.currentData,r=this.keysIndex;if(this.lock)this.setCurrentData(this.currentData);else{this.lock=!0,this._mdf=!1;var i,s=this.effectsSequence.length,a=t||this.data.d.k[this.keysIndex].s;for(i=0;i<s;i+=1)a=r!==this.keysIndex?this.effectsSequence[i](a,a.t):this.effectsSequence[i](this.currentData,a.t);e!==a&&this.setCurrentData(a),this.pv=this.v=this.currentData,this.lock=!1,this.frameId=this.elem.globalData.frameId}}},TextProperty.prototype.getKeyframeValue=function(){for(var t=this.data.d.k,e=this.elem.comp.renderedFrame,r=0,i=t.length;r<=i-1&&(t[r].s,!(r===i-1||t[r+1].t>e));)r+=1;return this.keysIndex!==r&&(this.keysIndex=r),this.data.d.k[this.keysIndex].s},TextProperty.prototype.buildFinalText=function(t){for(var e=FontManager.getCombinedCharacterCodes(),r=[],i=0,s=t.length;i<s;)-1!==e.indexOf(t.charCodeAt(i))?r[r.length-1]+=t.charAt(i):r.push(t.charAt(i)),i+=1;return r},TextProperty.prototype.completeTextData=function(t){t.__complete=!0;var e,r,i,s,a,n,o,h=this.elem.globalData.fontManager,p=this.data,l=[],m=0,f=p.m.g,c=0,d=0,u=0,y=[],g=0,v=0,P=h.getFontByName(t.f),b=0,x=P.fStyle?P.fStyle.split(" "):[],_="normal",S="normal";for(r=x.length,e=0;e<r;e+=1)switch(x[e].toLowerCase()){case"italic":S="italic";break;case"bold":_="700";break;case"black":_="900";break;case"medium":_="500";break;case"regular":case"normal":_="400";break;case"light":case"thin":_="200"}t.fWeight=P.fWeight||_,t.fStyle=S,r=t.t.length,t.finalSize=t.s,t.finalText=this.buildFinalText(t.t),t.finalLineHeight=t.lh;var T,A=t.tr/1e3*t.finalSize;if(t.sz)for(var C,E,k=!0,D=t.sz[0],I=t.sz[1];k;){g=C=0,r=(E=this.buildFinalText(t.t)).length,A=t.tr/1e3*t.finalSize;var M=-1;for(e=0;e<r;e+=1)T=E[e].charCodeAt(0),i=!1," "===E[e]?M=e:13!==T&&3!==T||(i=!(g=0),C+=t.finalLineHeight||1.2*t.finalSize),D<g+(b=h.chars?(o=h.getCharData(E[e],P.fStyle,P.fFamily),i?0:o.w*t.finalSize/100):h.measureText(E[e],t.f,t.finalSize))&&" "!==E[e]?(-1===M?r+=1:e=M,C+=t.finalLineHeight||1.2*t.finalSize,E.splice(e,M===e?1:0,"\r"),M=-1,g=0):(g+=b,g+=A);C+=P.ascent*t.finalSize/100,this.canResize&&t.finalSize>this.minimumFontSize&&I<C?(t.finalSize-=1,t.finalLineHeight=t.finalSize*t.lh/t.s):(t.finalText=E,r=t.finalText.length,k=!1)}g=-A;var w,F=b=0;for(e=0;e<r;e+=1)if(i=!1,T=(w=t.finalText[e]).charCodeAt(0)," "===w?s="\xa0":13===T||3===T?(F=0,y.push(g),v=v<g?g:v,g=-2*A,i=!(s=""),u+=1):s=t.finalText[e],b=h.chars?(o=h.getCharData(w,P.fStyle,h.getFontByName(t.f).fFamily),i?0:o.w*t.finalSize/100):h.measureText(s,t.f,t.finalSize)," "===w?F+=b+A:(g+=b+A+F,F=0),l.push({l:b,an:b,add:c,n:i,anIndexes:[],val:s,line:u,animatorJustifyOffset:0}),2==f){if(c+=b,""===s||"\xa0"===s||e===r-1){for(""!==s&&"\xa0"!==s||(c-=b);d<=e;)l[d].an=c,l[d].ind=m,l[d].extra=b,d+=1;m+=1,c=0}}else if(3==f){if(c+=b,""===s||e===r-1){for(""===s&&(c-=b);d<=e;)l[d].an=c,l[d].ind=m,l[d].extra=b,d+=1;c=0,m+=1}}else l[m].ind=m,l[m].extra=0,m+=1;if(t.l=l,v=v<g?g:v,y.push(g),t.sz)t.boxWidth=t.sz[0],t.justifyOffset=0;else switch(t.boxWidth=v,t.j){case 1:t.justifyOffset=-t.boxWidth;break;case 2:t.justifyOffset=-t.boxWidth/2;break;default:t.justifyOffset=0}t.lineWidths=y;var V,R,L=p.a;n=L.length;var z,O,B=[];for(a=0;a<n;a+=1){for((V=L[a]).a.sc&&(t.strokeColorAnim=!0),V.a.sw&&(t.strokeWidthAnim=!0),(V.a.fc||V.a.fh||V.a.fs||V.a.fb)&&(t.fillColorAnim=!0),O=0,z=V.s.b,e=0;e<r;e+=1)(R=l[e]).anIndexes[a]=O,(1==z&&""!==R.val||2==z&&""!==R.val&&"\xa0"!==R.val||3==z&&(R.n||"\xa0"==R.val||e==r-1)||4==z&&(R.n||e==r-1))&&(1===V.s.rn&&B.push(O),O+=1);p.a[a].s.totalChars=O;var N,G=-1;if(1===V.s.rn)for(e=0;e<r;e+=1)G!=(R=l[e]).anIndexes[a]&&(G=R.anIndexes[a],N=B.splice(Math.floor(Math.random()*B.length),1)[0]),R.anIndexes[a]=N}t.yOffset=t.finalLineHeight||1.2*t.finalSize,t.ls=t.ls||0,t.ascent=P.ascent*t.finalSize/100},TextProperty.prototype.updateDocumentData=function(t,e){e=void 0===e?this.keysIndex:e;var r=this.copyData({},this.data.d.k[e].s);r=this.copyData(r,t),this.data.d.k[e].s=r,this.recalculate(e),this.elem.addDynamicProperty(this)},TextProperty.prototype.recalculate=function(t){var e=this.data.d.k[t].s;e.__complete=!1,this.keysIndex=0,this._isFirstFrame=!0,this.getValue(e)},TextProperty.prototype.canResizeFont=function(t){this.canResize=t,this.recalculate(this.keysIndex),this.elem.addDynamicProperty(this)},TextProperty.prototype.setMinimumFontSize=function(t){this.minimumFontSize=Math.floor(t)||1,this.recalculate(this.keysIndex),this.elem.addDynamicProperty(this)};var TextSelectorProp=(cz=Math.max,dz=Math.min,ez=Math.floor,fz.prototype={getMult:function(t){this._currentTextLength!==this.elem.textProperty.currentData.l.length&&this.getValue();var e=BezierFactory.getBezierEasing(this.ne.v/100,0,1-this.xe.v/100,1).get,r=0,i=this.finalS,s=this.finalE,a=this.data.sh;if(2==a)r=e(r=s===i?s<=t?1:0:cz(0,dz(.5/(s-i)+(t-i)/(s-i),1)));else if(3==a)r=e(r=s===i?s<=t?0:1:1-cz(0,dz(.5/(s-i)+(t-i)/(s-i),1)));else if(4==a)s===i?r=0:(r=cz(0,dz(.5/(s-i)+(t-i)/(s-i),1)))<.5?r*=2:r=1-2*(r-.5),r=e(r);else if(5==a){if(s===i)r=0;else{var n=s-i,o=-n/2+(t=dz(cz(0,t+.5-i),s-i)),h=n/2;r=Math.sqrt(1-o*o/(h*h))}r=e(r)}else r=6==a?e(r=s===i?0:(t=dz(cz(0,t+.5-i),s-i),(1+Math.cos(Math.PI+2*Math.PI*t/(s-i)))/2)):(t>=ez(i)&&(r=t-i<0?1-(i-t):cz(0,dz(s-t,1))),e(r));return r*this.a.v},getValue:function(t){this.iterateDynamicProperties(),this._mdf=t||this._mdf,this._currentTextLength=this.elem.textProperty.currentData.l.length||0,t&&2===this.data.r&&(this.e.v=this._currentTextLength);var e=2===this.data.r?1:100/this.data.totalChars,r=this.o.v/e,i=this.s.v/e+r,s=this.e.v/e+r;if(s<i){var a=i;i=s,s=a}this.finalS=i,this.finalE=s}},extendPrototype([DynamicPropertyContainer],fz),{getTextSelectorProp:function(t,e,r){return new fz(t,e,r)}}),cz,dz,ez;function fz(t,e){this._currentTextLength=-1,this.k=!1,this.data=e,this.elem=t,this.comp=t.comp,this.finalS=0,this.finalE=0,this.initDynamicPropertyContainer(t),this.s=PropertyFactory.getProp(t,e.s||{k:0},0,0,this),this.e="e"in e?PropertyFactory.getProp(t,e.e,0,0,this):{v:100},this.o=PropertyFactory.getProp(t,e.o||{k:0},0,0,this),this.xe=PropertyFactory.getProp(t,e.xe||{k:0},0,0,this),this.ne=PropertyFactory.getProp(t,e.ne||{k:0},0,0,this),this.a=PropertyFactory.getProp(t,e.a,0,.01,this),this.dynamicProperties.length||this.getValue()}var pool_factory=function(t,e,r,i){var s=0,a=t,n=createSizedArray(a);function o(){return s?n[s-=1]:e()}return{newElement:o,release:function(t){s===a&&(n=pooling.double(n),a*=2),r&&r(t),n[s]=t,s+=1}}},pooling={double:function(t){return t.concat(createSizedArray(t.length))}},point_pool=pool_factory(8,function(){return createTypedArray("float32",2)}),shape_pool=(Vz=pool_factory(4,function(){return new ShapePath},function(t){var e,r=t._length;for(e=0;e<r;e+=1)point_pool.release(t.v[e]),point_pool.release(t.i[e]),point_pool.release(t.o[e]),t.v[e]=null,t.i[e]=null,t.o[e]=null;t._length=0,t.c=!1}),Vz.clone=function(t){var e,r=Vz.newElement(),i=void 0===t._length?t.v.length:t._length;for(r.setLength(i),r.c=t.c,e=0;e<i;e+=1)r.setTripleAt(t.v[e][0],t.v[e][1],t.o[e][0],t.o[e][1],t.i[e][0],t.i[e][1],e);return r},Vz),Vz,shapeCollection_pool=(cA={newShapeCollection:function(){var t;t=dA?fA[dA-=1]:new ShapeCollection;return t},release:function(t){var e,r=t._length;for(e=0;e<r;e+=1)shape_pool.release(t.shapes[e]);t._length=0,dA===eA&&(fA=pooling.double(fA),eA*=2);fA[dA]=t,dA+=1}},dA=0,eA=4,fA=createSizedArray(eA),cA),cA,dA,eA,fA,segments_length_pool=pool_factory(8,function(){return{lengths:[],totalLength:0}},function(t){var e,r=t.lengths.length;for(e=0;e<r;e+=1)bezier_length_pool.release(t.lengths[e]);t.lengths.length=0}),bezier_length_pool=pool_factory(8,function(){return{addedLength:0,percents:createTypedArray("float32",defaultCurveSegments),lengths:createTypedArray("float32",defaultCurveSegments)}});function BaseRenderer(){}function SVGRenderer(t,e){this.animationItem=t,this.layers=null,this.renderedFrame=-1,this.svgElement=createNS("svg");var r="";if(e&&e.title){var i=createNS("title"),s=createElementID();i.setAttribute("id",s),i.textContent=e.title,this.svgElement.appendChild(i),r+=s}if(e&&e.description){var a=createNS("desc"),n=createElementID();a.setAttribute("id",n),a.textContent=e.description,this.svgElement.appendChild(a),r+=" "+n}r&&this.svgElement.setAttribute("aria-labelledby",r);var o=createNS("defs");this.svgElement.appendChild(o);var h=createNS("g");this.svgElement.appendChild(h),this.layerElement=h,this.renderConfig={preserveAspectRatio:e&&e.preserveAspectRatio||"xMidYMid meet",imagePreserveAspectRatio:e&&e.imagePreserveAspectRatio||"xMidYMid slice",progressiveLoad:e&&e.progressiveLoad||!1,hideOnTransparent:!e||!1!==e.hideOnTransparent,viewBoxOnly:e&&e.viewBoxOnly||!1,viewBoxSize:e&&e.viewBoxSize||!1,className:e&&e.className||""},this.globalData={_mdf:!1,frameNum:-1,defs:o,renderConfig:this.renderConfig},this.elements=[],this.pendingElements=[],this.destroyed=!1,this.rendererType="svg"}function CanvasRenderer(t,e){this.animationItem=t,this.renderConfig={clearCanvas:!e||void 0===e.clearCanvas||e.clearCanvas,context:e&&e.context||null,progressiveLoad:e&&e.progressiveLoad||!1,preserveAspectRatio:e&&e.preserveAspectRatio||"xMidYMid meet",imagePreserveAspectRatio:e&&e.imagePreserveAspectRatio||"xMidYMid slice",className:e&&e.className||""},this.renderConfig.dpr=e&&e.dpr||1,this.animationItem.wrapper&&(this.renderConfig.dpr=e&&e.dpr||window.devicePixelRatio||1),this.renderedFrame=-1,this.globalData={frameNum:-1,_mdf:!1,renderConfig:this.renderConfig,currentGlobalAlpha:-1},this.contextData=new CVContextData,this.elements=[],this.pendingElements=[],this.transformMat=new Matrix,this.completeLayers=!1,this.rendererType="canvas"}function MaskElement(t,e,r){this.data=t,this.element=e,this.globalData=r,this.storedData=[],this.masksProperties=this.data.masksProperties||[],this.maskElement=null;var i,s=this.globalData.defs,a=this.masksProperties?this.masksProperties.length:0;this.viewData=createSizedArray(a),this.solidPath="";var n,o,h,p,l,m,f,c=this.masksProperties,d=0,u=[],y=createElementID(),g="clipPath",v="clip-path";for(i=0;i<a;i++)if(("a"!==c[i].mode&&"n"!==c[i].mode||c[i].inv||100!==c[i].o.k)&&(v=g="mask"),"s"!=c[i].mode&&"i"!=c[i].mode||0!==d?p=null:((p=createNS("rect")).setAttribute("fill","#ffffff"),p.setAttribute("width",this.element.comp.data.w||0),p.setAttribute("height",this.element.comp.data.h||0),u.push(p)),n=createNS("path"),"n"!=c[i].mode){var P;if(d+=1,n.setAttribute("fill","s"===c[i].mode?"#000000":"#ffffff"),n.setAttribute("clip-rule","nonzero"),0!==c[i].x.k?(v=g="mask",f=PropertyFactory.getProp(this.element,c[i].x,0,null,this.element),P=createElementID(),(l=createNS("filter")).setAttribute("id",P),(m=createNS("feMorphology")).setAttribute("operator","erode"),m.setAttribute("in","SourceGraphic"),m.setAttribute("radius","0"),l.appendChild(m),s.appendChild(l),n.setAttribute("stroke","s"===c[i].mode?"#000000":"#ffffff")):f=m=null,this.storedData[i]={elem:n,x:f,expan:m,lastPath:"",lastOperator:"",filterId:P,lastRadius:0},"i"==c[i].mode){h=u.length;var b=createNS("g");for(o=0;o<h;o+=1)b.appendChild(u[o]);var x=createNS("mask");x.setAttribute("mask-type","alpha"),x.setAttribute("id",y+"_"+d),x.appendChild(n),s.appendChild(x),b.setAttribute("mask","url("+locationHref+"#"+y+"_"+d+")"),u.length=0,u.push(b)}else u.push(n);c[i].inv&&!this.solidPath&&(this.solidPath=this.createLayerSolidPath()),this.viewData[i]={elem:n,lastPath:"",op:PropertyFactory.getProp(this.element,c[i].o,0,.01,this.element),prop:ShapePropertyFactory.getShapeProp(this.element,c[i],3),invRect:p},this.viewData[i].prop.k||this.drawPath(c[i],this.viewData[i].prop.v,this.viewData[i])}else this.viewData[i]={op:PropertyFactory.getProp(this.element,c[i].o,0,.01,this.element),prop:ShapePropertyFactory.getShapeProp(this.element,c[i],3),elem:n,lastPath:""},s.appendChild(n);for(this.maskElement=createNS(g),a=u.length,i=0;i<a;i+=1)this.maskElement.appendChild(u[i]);0<d&&(this.maskElement.setAttribute("id",y),this.element.maskedElement.setAttribute(v,"url("+locationHref+"#"+y+")"),s.appendChild(this.maskElement)),this.viewData.length&&this.element.addRenderableComponent(this)}function HierarchyElement(){}function FrameElement(){}function TransformElement(){}function RenderableElement(){}function RenderableDOMElement(){}function ProcessedElement(t,e){this.elem=t,this.pos=e}function SVGShapeData(t,e,r){this.caches=[],this.styles=[],this.transformers=t,this.lStr="",this.sh=r,this.lvl=e,this._isAnimated=!!r.k;for(var i=0,s=t.length;i<s;){if(t[i].mProps.dynamicProperties.length){this._isAnimated=!0;break}i+=1}}function ShapeGroupData(){this.it=[],this.prevViewData=[],this.gr=createNS("g")}function ShapeTransformManager(){this.sequences={},this.sequenceList=[],this.transform_key_count=0}function CVShapeData(t,e,r,i){this.styledShapes=[],this.tr=[0,0,0,0,0,0];var s=4;"rc"==e.ty?s=5:"el"==e.ty?s=6:"sr"==e.ty&&(s=7),this.sh=ShapePropertyFactory.getShapeProp(t,e,s,t);var a,n,o=r.length;for(a=0;a<o;a+=1)r[a].closed||(n={transforms:i.addTransformSequence(r[a].transforms),trNodes:[]},this.styledShapes.push(n),r[a].elements.push(n))}function BaseElement(){}function NullElement(t,e,r){this.initFrame(),this.initBaseData(t,e,r),this.initFrame(),this.initTransform(t,e,r),this.initHierarchy()}function SVGBaseElement(){}function IShapeElement(){}function ITextElement(){}function ICompElement(){}function IImageElement(t,e,r){this.assetData=e.getAssetData(t.refId),this.initElement(t,e,r),this.sourceRect={top:0,left:0,width:this.assetData.w,height:this.assetData.h}}function ISolidElement(t,e,r){this.initElement(t,e,r)}function SVGShapeElement(t,e,r){this.shapes=[],this.shapesData=t.shapes,this.stylesList=[],this.shapeModifiers=[],this.itemsData=[],this.processedElements=[],this.animatedContents=[],this.initElement(t,e,r),this.prevViewData=[]}function CVContextData(){this.saved=[],this.cArrPos=0,this.cTr=new Matrix,this.cO=1;var t;for(this.savedOp=createTypedArray("float32",15),t=0;t<15;t+=1)this.saved[t]=createTypedArray("float32",16);this._length=15}function CVBaseElement(){}function CVCompElement(t,e,r){this.completeLayers=!1,this.layers=t.layers,this.pendingElements=[],this.elements=createSizedArray(this.layers.length),this.initElement(t,e,r),this.tm=t.tm?PropertyFactory.getProp(this,t.tm,0,e.frameRate,this):{_placeholder:!0}}function CVMaskElement(t,e){this.data=t,this.element=e,this.masksProperties=this.data.masksProperties||[],this.viewData=createSizedArray(this.masksProperties.length);var r,i=this.masksProperties.length,s=!1;for(r=0;r<i;r++)"n"!==this.masksProperties[r].mode&&(s=!0),this.viewData[r]=ShapePropertyFactory.getShapeProp(this.element,this.masksProperties[r],3);(this.hasMasks=s)&&this.element.addRenderableComponent(this)}function CVShapeElement(t,e,r){this.shapes=[],this.shapesData=t.shapes,this.stylesList=[],this.itemsData=[],this.prevViewData=[],this.shapeModifiers=[],this.processedElements=[],this.transformsManager=new ShapeTransformManager,this.initElement(t,e,r)}function CVSolidElement(t,e,r){this.initElement(t,e,r)}function CVEffects(){}BaseRenderer.prototype.checkLayers=function(t){var e,r,i=this.layers.length;for(this.completeLayers=!0,e=i-1;0<=e;e--)this.elements[e]||(r=this.layers[e]).ip-r.st<=t-this.layers[e].st&&r.op-r.st>t-this.layers[e].st&&this.buildItem(e),this.completeLayers=!!this.elements[e]&&this.completeLayers;this.checkPendingElements()},BaseRenderer.prototype.createItem=function(t){switch(t.ty){case 2:return this.createImage(t);case 0:return this.createComp(t);case 1:return this.createSolid(t);case 3:return this.createNull(t);case 4:return this.createShape(t);case 5:return this.createText(t);case 13:return this.createCamera(t)}return this.createNull(t)},BaseRenderer.prototype.createCamera=function(){throw new Error("You're using a 3d camera. Try the html renderer.")},BaseRenderer.prototype.buildAllItems=function(){var t,e=this.layers.length;for(t=0;t<e;t+=1)this.buildItem(t);this.checkPendingElements()},BaseRenderer.prototype.includeLayers=function(t){this.completeLayers=!1;var e,r,i=t.length,s=this.layers.length;for(e=0;e<i;e+=1)for(r=0;r<s;){if(this.layers[r].id==t[e].id){this.layers[r]=t[e];break}r+=1}},BaseRenderer.prototype.setProjectInterface=function(t){this.globalData.projectInterface=t},BaseRenderer.prototype.initItems=function(){this.globalData.progressiveLoad||this.buildAllItems()},BaseRenderer.prototype.buildElementParenting=function(t,e,r){for(var i=this.elements,s=this.layers,a=0,n=s.length;a<n;)s[a].ind==e&&(i[a]&&!0!==i[a]?(r.push(i[a]),i[a].setAsParent(),void 0!==s[a].parent?this.buildElementParenting(t,s[a].parent,r):t.setHierarchy(r)):(this.buildItem(a),this.addPendingElement(t))),a+=1},BaseRenderer.prototype.addPendingElement=function(t){this.pendingElements.push(t)},BaseRenderer.prototype.searchExtraCompositions=function(t){var e,r=t.length;for(e=0;e<r;e+=1)if(t[e].xt){var i=this.createComp(t[e]);i.initExpressions(),this.globalData.projectInterface.registerComposition(i)}},BaseRenderer.prototype.setupGlobalData=function(t,e){this.globalData.fontManager=new FontManager,this.globalData.fontManager.addChars(t.chars),this.globalData.fontManager.addFonts(t.fonts,e),this.globalData.getAssetData=this.animationItem.getAssetData.bind(this.animationItem),this.globalData.getAssetsPath=this.animationItem.getAssetsPath.bind(this.animationItem),this.globalData.imageLoader=this.animationItem.imagePreloader,this.globalData.frameId=0,this.globalData.frameRate=t.fr,this.globalData.nm=t.nm,this.globalData.compSize={w:t.w,h:t.h}},extendPrototype([BaseRenderer],SVGRenderer),SVGRenderer.prototype.createNull=function(t){return new NullElement(t,this.globalData,this)},SVGRenderer.prototype.createShape=function(t){return new SVGShapeElement(t,this.globalData,this)},SVGRenderer.prototype.createText=function(t){return new SVGTextElement(t,this.globalData,this)},SVGRenderer.prototype.createImage=function(t){return new IImageElement(t,this.globalData,this)},SVGRenderer.prototype.createComp=function(t){return new SVGCompElement(t,this.globalData,this)},SVGRenderer.prototype.createSolid=function(t){return new ISolidElement(t,this.globalData,this)},SVGRenderer.prototype.configAnimation=function(t){this.svgElement.setAttribute("xmlns","http://www.w3.org/2000/svg"),this.renderConfig.viewBoxSize?this.svgElement.setAttribute("viewBox",this.renderConfig.viewBoxSize):this.svgElement.setAttribute("viewBox","0 0 "+t.w+" "+t.h),this.renderConfig.viewBoxOnly||(this.svgElement.setAttribute("width",t.w),this.svgElement.setAttribute("height",t.h),this.svgElement.style.width="100%",this.svgElement.style.height="100%",this.svgElement.style.transform="translate3d(0,0,0)"),this.renderConfig.className&&this.svgElement.setAttribute("class",this.renderConfig.className),this.svgElement.setAttribute("preserveAspectRatio",this.renderConfig.preserveAspectRatio),this.animationItem.wrapper.appendChild(this.svgElement);var e=this.globalData.defs;this.setupGlobalData(t,e),this.globalData.progressiveLoad=this.renderConfig.progressiveLoad,this.data=t;var r=createNS("clipPath"),i=createNS("rect");i.setAttribute("width",t.w),i.setAttribute("height",t.h),i.setAttribute("x",0),i.setAttribute("y",0);var s=createElementID();r.setAttribute("id",s),r.appendChild(i),this.layerElement.setAttribute("clip-path","url("+locationHref+"#"+s+")"),e.appendChild(r),this.layers=t.layers,this.elements=createSizedArray(t.layers.length)},SVGRenderer.prototype.destroy=function(){this.animationItem.wrapper.innerHTML="",this.layerElement=null,this.globalData.defs=null;var t,e=this.layers?this.layers.length:0;for(t=0;t<e;t++)this.elements[t]&&this.elements[t].destroy();this.elements.length=0,this.destroyed=!0,this.animationItem=null},SVGRenderer.prototype.updateContainerSize=function(){},SVGRenderer.prototype.buildItem=function(t){var e=this.elements;if(!e[t]&&99!=this.layers[t].ty){e[t]=!0;var r=this.createItem(this.layers[t]);e[t]=r,expressionsPlugin&&(0===this.layers[t].ty&&this.globalData.projectInterface.registerComposition(r),r.initExpressions()),this.appendElementInPos(r,t),this.layers[t].tt&&(this.elements[t-1]&&!0!==this.elements[t-1]?r.setMatte(e[t-1].layerId):(this.buildItem(t-1),this.addPendingElement(r)))}},SVGRenderer.prototype.checkPendingElements=function(){for(;this.pendingElements.length;){var t=this.pendingElements.pop();if(t.checkParenting(),t.data.tt)for(var e=0,r=this.elements.length;e<r;){if(this.elements[e]===t){t.setMatte(this.elements[e-1].layerId);break}e+=1}}},SVGRenderer.prototype.renderFrame=function(t){if(this.renderedFrame!==t&&!this.destroyed){null===t?t=this.renderedFrame:this.renderedFrame=t,this.globalData.frameNum=t,this.globalData.frameId+=1,this.globalData.projectInterface.currentFrame=t,this.globalData._mdf=!1;var e,r=this.layers.length;for(this.completeLayers||this.checkLayers(t),e=r-1;0<=e;e--)(this.completeLayers||this.elements[e])&&this.elements[e].prepareFrame(t-this.layers[e].st);if(this.globalData._mdf)for(e=0;e<r;e+=1)(this.completeLayers||this.elements[e])&&this.elements[e].renderFrame()}},SVGRenderer.prototype.appendElementInPos=function(t,e){var r=t.getBaseElement();if(r){for(var i,s=0;s<e;)this.elements[s]&&!0!==this.elements[s]&&this.elements[s].getBaseElement()&&(i=this.elements[s].getBaseElement()),s+=1;i?this.layerElement.insertBefore(r,i):this.layerElement.appendChild(r)}},SVGRenderer.prototype.hide=function(){this.layerElement.style.display="none"},SVGRenderer.prototype.show=function(){this.layerElement.style.display="block"},extendPrototype([BaseRenderer],CanvasRenderer),CanvasRenderer.prototype.createShape=function(t){return new CVShapeElement(t,this.globalData,this)},CanvasRenderer.prototype.createText=function(t){return new CVTextElement(t,this.globalData,this)},CanvasRenderer.prototype.createImage=function(t){return new CVImageElement(t,this.globalData,this)},CanvasRenderer.prototype.createComp=function(t){return new CVCompElement(t,this.globalData,this)},CanvasRenderer.prototype.createSolid=function(t){return new CVSolidElement(t,this.globalData,this)},CanvasRenderer.prototype.createNull=SVGRenderer.prototype.createNull,CanvasRenderer.prototype.ctxTransform=function(t){if(1!==t[0]||0!==t[1]||0!==t[4]||1!==t[5]||0!==t[12]||0!==t[13])if(this.renderConfig.clearCanvas){this.transformMat.cloneFromProps(t);var e=this.contextData.cTr.props;this.transformMat.transform(e[0],e[1],e[2],e[3],e[4],e[5],e[6],e[7],e[8],e[9],e[10],e[11],e[12],e[13],e[14],e[15]),this.contextData.cTr.cloneFromProps(this.transformMat.props);var r=this.contextData.cTr.props;this.canvasContext.setTransform(r[0],r[1],r[4],r[5],r[12],r[13])}else this.canvasContext.transform(t[0],t[1],t[4],t[5],t[12],t[13])},CanvasRenderer.prototype.ctxOpacity=function(t){if(!this.renderConfig.clearCanvas)return this.canvasContext.globalAlpha*=t<0?0:t,void(this.globalData.currentGlobalAlpha=this.contextData.cO);this.contextData.cO*=t<0?0:t,this.globalData.currentGlobalAlpha!==this.contextData.cO&&(this.canvasContext.globalAlpha=this.contextData.cO,this.globalData.currentGlobalAlpha=this.contextData.cO)},CanvasRenderer.prototype.reset=function(){this.renderConfig.clearCanvas?this.contextData.reset():this.canvasContext.restore()},CanvasRenderer.prototype.save=function(t){if(this.renderConfig.clearCanvas){t&&this.canvasContext.save();var e=this.contextData.cTr.props;this.contextData._length<=this.contextData.cArrPos&&this.contextData.duplicate();var r,i=this.contextData.saved[this.contextData.cArrPos];for(r=0;r<16;r+=1)i[r]=e[r];this.contextData.savedOp[this.contextData.cArrPos]=this.contextData.cO,this.contextData.cArrPos+=1}else this.canvasContext.save()},CanvasRenderer.prototype.restore=function(t){if(this.renderConfig.clearCanvas){t&&(this.canvasContext.restore(),this.globalData.blendMode="source-over"),this.contextData.cArrPos-=1;var e,r=this.contextData.saved[this.contextData.cArrPos],i=this.contextData.cTr.props;for(e=0;e<16;e+=1)i[e]=r[e];this.canvasContext.setTransform(r[0],r[1],r[4],r[5],r[12],r[13]),r=this.contextData.savedOp[this.contextData.cArrPos],this.contextData.cO=r,this.globalData.currentGlobalAlpha!==r&&(this.canvasContext.globalAlpha=r,this.globalData.currentGlobalAlpha=r)}else this.canvasContext.restore()},CanvasRenderer.prototype.configAnimation=function(t){this.animationItem.wrapper?(this.animationItem.container=createTag("canvas"),this.animationItem.container.style.width="100%",this.animationItem.container.style.height="100%",this.animationItem.container.style.transformOrigin=this.animationItem.container.style.mozTransformOrigin=this.animationItem.container.style.webkitTransformOrigin=this.animationItem.container.style["-webkit-transform"]="0px 0px 0px",this.animationItem.wrapper.appendChild(this.animationItem.container),this.canvasContext=this.animationItem.container.getContext("2d"),this.renderConfig.className&&this.animationItem.container.setAttribute("class",this.renderConfig.className)):this.canvasContext=this.renderConfig.context,this.data=t,this.layers=t.layers,this.transformCanvas={w:t.w,h:t.h,sx:0,sy:0,tx:0,ty:0},this.setupGlobalData(t,document.body),this.globalData.canvasContext=this.canvasContext,(this.globalData.renderer=this).globalData.isDashed=!1,this.globalData.progressiveLoad=this.renderConfig.progressiveLoad,this.globalData.transformCanvas=this.transformCanvas,this.elements=createSizedArray(t.layers.length),this.updateContainerSize()},CanvasRenderer.prototype.updateContainerSize=function(){var t,e,r,i;if(this.reset(),this.animationItem.wrapper&&this.animationItem.container?(t=this.animationItem.wrapper.offsetWidth,e=this.animationItem.wrapper.offsetHeight,this.animationItem.container.setAttribute("width",t*this.renderConfig.dpr),this.animationItem.container.setAttribute("height",e*this.renderConfig.dpr)):(t=this.canvasContext.canvas.width*this.renderConfig.dpr,e=this.canvasContext.canvas.height*this.renderConfig.dpr),-1!==this.renderConfig.preserveAspectRatio.indexOf("meet")||-1!==this.renderConfig.preserveAspectRatio.indexOf("slice")){var s=this.renderConfig.preserveAspectRatio.split(" "),a=s[1]||"meet",n=s[0]||"xMidYMid",o=n.substr(0,4),h=n.substr(4);(r=t/e)<(i=this.transformCanvas.w/this.transformCanvas.h)&&"meet"===a||i<r&&"slice"===a?(this.transformCanvas.sx=t/(this.transformCanvas.w/this.renderConfig.dpr),this.transformCanvas.sy=t/(this.transformCanvas.w/this.renderConfig.dpr)):(this.transformCanvas.sx=e/(this.transformCanvas.h/this.renderConfig.dpr),this.transformCanvas.sy=e/(this.transformCanvas.h/this.renderConfig.dpr)),this.transformCanvas.tx="xMid"===o&&(i<r&&"meet"===a||r<i&&"slice"===a)?(t-this.transformCanvas.w*(e/this.transformCanvas.h))/2*this.renderConfig.dpr:"xMax"===o&&(i<r&&"meet"===a||r<i&&"slice"===a)?(t-this.transformCanvas.w*(e/this.transformCanvas.h))*this.renderConfig.dpr:0,this.transformCanvas.ty="YMid"===h&&(r<i&&"meet"===a||i<r&&"slice"===a)?(e-this.transformCanvas.h*(t/this.transformCanvas.w))/2*this.renderConfig.dpr:"YMax"===h&&(r<i&&"meet"===a||i<r&&"slice"===a)?(e-this.transformCanvas.h*(t/this.transformCanvas.w))*this.renderConfig.dpr:0}else"none"==this.renderConfig.preserveAspectRatio?(this.transformCanvas.sx=t/(this.transformCanvas.w/this.renderConfig.dpr),this.transformCanvas.sy=e/(this.transformCanvas.h/this.renderConfig.dpr)):(this.transformCanvas.sx=this.renderConfig.dpr,this.transformCanvas.sy=this.renderConfig.dpr),this.transformCanvas.tx=0,this.transformCanvas.ty=0;this.transformCanvas.props=[this.transformCanvas.sx,0,0,0,0,this.transformCanvas.sy,0,0,0,0,1,0,this.transformCanvas.tx,this.transformCanvas.ty,0,1],this.ctxTransform(this.transformCanvas.props),this.canvasContext.beginPath(),this.canvasContext.rect(0,0,this.transformCanvas.w,this.transformCanvas.h),this.canvasContext.closePath(),this.canvasContext.clip(),this.renderFrame(this.renderedFrame,!0)},CanvasRenderer.prototype.destroy=function(){var t;for(this.renderConfig.clearCanvas&&(this.animationItem.wrapper.innerHTML=""),t=(this.layers?this.layers.length:0)-1;0<=t;t-=1)this.elements[t]&&this.elements[t].destroy();this.elements.length=0,this.globalData.canvasContext=null,this.animationItem.container=null,this.destroyed=!0},CanvasRenderer.prototype.renderFrame=function(t,e){if((this.renderedFrame!==t||!0!==this.renderConfig.clearCanvas||e)&&!this.destroyed&&-1!==t){this.renderedFrame=t,this.globalData.frameNum=t-this.animationItem._isFirstFrame,this.globalData.frameId+=1,this.globalData._mdf=!this.renderConfig.clearCanvas||e,this.globalData.projectInterface.currentFrame=t;var r,i=this.layers.length;for(this.completeLayers||this.checkLayers(t),r=0;r<i;r++)(this.completeLayers||this.elements[r])&&this.elements[r].prepareFrame(t-this.layers[r].st);if(this.globalData._mdf){for(!0===this.renderConfig.clearCanvas?this.canvasContext.clearRect(0,0,this.transformCanvas.w,this.transformCanvas.h):this.save(),r=i-1;0<=r;r-=1)(this.completeLayers||this.elements[r])&&this.elements[r].renderFrame();!0!==this.renderConfig.clearCanvas&&this.restore()}}},CanvasRenderer.prototype.buildItem=function(t){var e=this.elements;if(!e[t]&&99!=this.layers[t].ty){var r=this.createItem(this.layers[t],this,this.globalData);(e[t]=r).initExpressions()}},CanvasRenderer.prototype.checkPendingElements=function(){for(;this.pendingElements.length;){this.pendingElements.pop().checkParenting()}},CanvasRenderer.prototype.hide=function(){this.animationItem.container.style.display="none"},CanvasRenderer.prototype.show=function(){this.animationItem.container.style.display="block"},CanvasRenderer.prototype.configAnimation=function(t){this.animationItem.wrapper?(this.animationItem.container=createTag("canvas"),this.animationItem.container.style.width="100%",this.animationItem.container.style.height="100%",this.animationItem.container.style.transformOrigin=this.animationItem.container.style.mozTransformOrigin=this.animationItem.container.style.webkitTransformOrigin=this.animationItem.container.style["-webkit-transform"]="0px 0px 0px",this.animationItem.wrapper.appendChild(this.animationItem.container),this.canvasContext=this.animationItem.container.getContext("2d"),this.renderConfig.className&&this.animationItem.container.setAttribute("class",this.renderConfig.className)):this.canvasContext=this.renderConfig.context,this.data=t,this.layers=t.layers,this.transformCanvas={w:t.w,h:t.h,sx:0,sy:0,tx:0,ty:0},this.globalData.frameId=0,this.globalData.frameRate=t.fr,this.globalData.nm=t.nm,this.globalData.compSize={w:t.w,h:t.h},this.globalData.canvasContext=this.canvasContext,(this.globalData.renderer=this).globalData.isDashed=!1,this.globalData.progressiveLoad=this.renderConfig.progressiveLoad,this.globalData.transformCanvas=this.transformCanvas,this.elements=createSizedArray(t.layers.length),this.updateContainerSize()},MaskElement.prototype.getMaskProperty=function(t){return this.viewData[t].prop},MaskElement.prototype.renderFrame=function(t){var e,r=this.element.finalTransform.mat,i=this.masksProperties.length;for(e=0;e<i;e++)if((this.viewData[e].prop._mdf||t)&&this.drawPath(this.masksProperties[e],this.viewData[e].prop.v,this.viewData[e]),(this.viewData[e].op._mdf||t)&&this.viewData[e].elem.setAttribute("fill-opacity",this.viewData[e].op.v),"n"!==this.masksProperties[e].mode&&(this.viewData[e].invRect&&(this.element.finalTransform.mProp._mdf||t)&&(this.viewData[e].invRect.setAttribute("x",-r.props[12]),this.viewData[e].invRect.setAttribute("y",-r.props[13])),this.storedData[e].x&&(this.storedData[e].x._mdf||t))){var s=this.storedData[e].expan;this.storedData[e].x.v<0?("erode"!==this.storedData[e].lastOperator&&(this.storedData[e].lastOperator="erode",this.storedData[e].elem.setAttribute("filter","url("+locationHref+"#"+this.storedData[e].filterId+")")),s.setAttribute("radius",-this.storedData[e].x.v)):("dilate"!==this.storedData[e].lastOperator&&(this.storedData[e].lastOperator="dilate",this.storedData[e].elem.setAttribute("filter",null)),this.storedData[e].elem.setAttribute("stroke-width",2*this.storedData[e].x.v))}},MaskElement.prototype.getMaskelement=function(){return this.maskElement},MaskElement.prototype.createLayerSolidPath=function(){var t="M0,0 ";return t+=" h"+this.globalData.compSize.w,t+=" v"+this.globalData.compSize.h,t+=" h-"+this.globalData.compSize.w,t+=" v-"+this.globalData.compSize.h+" "},MaskElement.prototype.drawPath=function(t,e,r){var i,s,a=" M"+e.v[0][0]+","+e.v[0][1];for(s=e._length,i=1;i<s;i+=1)a+=" C"+e.o[i-1][0]+","+e.o[i-1][1]+" "+e.i[i][0]+","+e.i[i][1]+" "+e.v[i][0]+","+e.v[i][1];if(e.c&&1<s&&(a+=" C"+e.o[i-1][0]+","+e.o[i-1][1]+" "+e.i[0][0]+","+e.i[0][1]+" "+e.v[0][0]+","+e.v[0][1]),r.lastPath!==a){var n="";r.elem&&(e.c&&(n=t.inv?this.solidPath+a:a),r.elem.setAttribute("d",n)),r.lastPath=a}},MaskElement.prototype.destroy=function(){this.element=null,this.globalData=null,this.maskElement=null,this.data=null,this.masksProperties=null},HierarchyElement.prototype={initHierarchy:function(){this.hierarchy=[],this._isParent=!1,this.checkParenting()},setHierarchy:function(t){this.hierarchy=t},setAsParent:function(){this._isParent=!0},checkParenting:function(){void 0!==this.data.parent&&this.comp.buildElementParenting(this,this.data.parent,[])}},FrameElement.prototype={initFrame:function(){this._isFirstFrame=!1,this.dynamicProperties=[],this._mdf=!1},prepareProperties:function(t,e){var r,i=this.dynamicProperties.length;for(r=0;r<i;r+=1)(e||this._isParent&&"transform"===this.dynamicProperties[r].propType)&&(this.dynamicProperties[r].getValue(),this.dynamicProperties[r]._mdf&&(this.globalData._mdf=!0,this._mdf=!0))},addDynamicProperty:function(t){-1===this.dynamicProperties.indexOf(t)&&this.dynamicProperties.push(t)}},TransformElement.prototype={initTransform:function(){this.finalTransform={mProp:this.data.ks?TransformPropertyFactory.getTransformProperty(this,this.data.ks,this):{o:0},_matMdf:!1,_opMdf:!1,mat:new Matrix},this.data.ao&&(this.finalTransform.mProp.autoOriented=!0),this.data.ty},renderTransform:function(){if(this.finalTransform._opMdf=this.finalTransform.mProp.o._mdf||this._isFirstFrame,this.finalTransform._matMdf=this.finalTransform.mProp._mdf||this._isFirstFrame,this.hierarchy){var t,e=this.finalTransform.mat,r=0,i=this.hierarchy.length;if(!this.finalTransform._matMdf)for(;r<i;){if(this.hierarchy[r].finalTransform.mProp._mdf){this.finalTransform._matMdf=!0;break}r+=1}if(this.finalTransform._matMdf)for(t=this.finalTransform.mProp.v.props,e.cloneFromProps(t),r=0;r<i;r+=1)t=this.hierarchy[r].finalTransform.mProp.v.props,e.transform(t[0],t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15])}},globalToLocal:function(t){var e=[];e.push(this.finalTransform);for(var r=!0,i=this.comp;r;)i.finalTransform?(i.data.hasMask&&e.splice(0,0,i.finalTransform),i=i.comp):r=!1;var s,a,n=e.length;for(s=0;s<n;s+=1)a=e[s].mat.applyToPointArray(0,0,0),t=[t[0]-a[0],t[1]-a[1],0];return t},mHelper:new Matrix},RenderableElement.prototype={initRenderable:function(){this.isInRange=!1,this.hidden=!1,this.isTransparent=!1,this.renderableComponents=[]},addRenderableComponent:function(t){-1===this.renderableComponents.indexOf(t)&&this.renderableComponents.push(t)},removeRenderableComponent:function(t){-1!==this.renderableComponents.indexOf(t)&&this.renderableComponents.splice(this.renderableComponents.indexOf(t),1)},prepareRenderableFrame:function(t){this.checkLayerLimits(t)},checkTransparency:function(){this.finalTransform.mProp.o.v<=0?!this.isTransparent&&this.globalData.renderConfig.hideOnTransparent&&(this.isTransparent=!0,this.hide()):this.isTransparent&&(this.isTransparent=!1,this.show())},checkLayerLimits:function(t){this.data.ip-this.data.st<=t&&this.data.op-this.data.st>t?!0!==this.isInRange&&(this.globalData._mdf=!0,this._mdf=!0,this.isInRange=!0,this.show()):!1!==this.isInRange&&(this.globalData._mdf=!0,this.isInRange=!1,this.hide())},renderRenderable:function(){var t,e=this.renderableComponents.length;for(t=0;t<e;t+=1)this.renderableComponents[t].renderFrame(this._isFirstFrame)},sourceRectAtTime:function(){return{top:0,left:0,width:100,height:100}},getLayerSize:function(){return 5===this.data.ty?{w:this.data.textData.width,h:this.data.textData.height}:{w:this.data.width,h:this.data.height}}},extendPrototype([RenderableElement,createProxyFunction({initElement:function(t,e,r){this.initFrame(),this.initBaseData(t,e,r),this.initTransform(t,e,r),this.initHierarchy(),this.initRenderable(),this.initRendererElement(),this.createContainerElements(),this.createRenderableComponents(),this.createContent(),this.hide()},hide:function(){this.hidden||this.isInRange&&!this.isTransparent||((this.baseElement||this.layerElement).style.display="none",this.hidden=!0)},show:function(){this.isInRange&&!this.isTransparent&&(this.data.hd||((this.baseElement||this.layerElement).style.display="block"),this.hidden=!1,this._isFirstFrame=!0)},renderFrame:function(){this.data.hd||this.hidden||(this.renderTransform(),this.renderRenderable(),this.renderElement(),this.renderInnerContent(),this._isFirstFrame&&(this._isFirstFrame=!1))},renderInnerContent:function(){},prepareFrame:function(t){this._mdf=!1,this.prepareRenderableFrame(t),this.prepareProperties(t,this.isInRange),this.checkTransparency()},destroy:function(){this.innerElem=null,this.destroyBaseElement()}})],RenderableDOMElement),SVGShapeData.prototype.setAsAnimated=function(){this._isAnimated=!0},ShapeTransformManager.prototype={addTransformSequence:function(t){var e,r=t.length,i="_";for(e=0;e<r;e+=1)i+=t[e].transform.key+"_";var s=this.sequences[i];return s||(s={transforms:[].concat(t),finalTransform:new Matrix,_mdf:!1},this.sequences[i]=s,this.sequenceList.push(s)),s},processSequence:function(t,e){for(var r,i=0,s=t.transforms.length,a=e;i<s&&!e;){if(t.transforms[i].transform.mProps._mdf){a=!0;break}i+=1}if(a)for(t.finalTransform.reset(),i=s-1;0<=i;i-=1)r=t.transforms[i].transform.mProps.v.props,t.finalTransform.transform(r[0],r[1],r[2],r[3],r[4],r[5],r[6],r[7],r[8],r[9],r[10],r[11],r[12],r[13],r[14],r[15]);t._mdf=a},processSequences:function(t){var e,r=this.sequenceList.length;for(e=0;e<r;e+=1)this.processSequence(this.sequenceList[e],t)},getNewKey:function(){return"_"+this.transform_key_count++}},CVShapeData.prototype.setAsAnimated=SVGShapeData.prototype.setAsAnimated,BaseElement.prototype={checkMasks:function(){if(!this.data.hasMask)return!1;for(var t=0,e=this.data.masksProperties.length;t<e;){if("n"!==this.data.masksProperties[t].mode&&!1!==this.data.masksProperties[t].cl)return!0;t+=1}return!1},initExpressions:function(){this.layerInterface=LayerExpressionInterface(this),this.data.hasMask&&this.maskManager&&this.layerInterface.registerMaskInterface(this.maskManager);var t=EffectsExpressionInterface.createEffectsInterface(this,this.layerInterface);this.layerInterface.registerEffectsInterface(t),0===this.data.ty||this.data.xt?this.compInterface=CompExpressionInterface(this):4===this.data.ty?(this.layerInterface.shapeInterface=ShapeExpressionInterface(this.shapesData,this.itemsData,this.layerInterface),this.layerInterface.content=this.layerInterface.shapeInterface):5===this.data.ty&&(this.layerInterface.textInterface=TextExpressionInterface(this),this.layerInterface.text=this.layerInterface.textInterface)},setBlendMode:function(){var t=getBlendMode(this.data.bm);(this.baseElement||this.layerElement).style["mix-blend-mode"]=t},initBaseData:function(t,e,r){this.globalData=e,this.comp=r,this.data=t,this.layerId=createElementID(),this.data.sr||(this.data.sr=1),this.effectsManager=new EffectsManager(this.data,this,this.dynamicProperties)},getType:function(){return this.type},sourceRectAtTime:function(){}},NullElement.prototype.prepareFrame=function(t){this.prepareProperties(t,!0)},NullElement.prototype.renderFrame=function(){},NullElement.prototype.getBaseElement=function(){return null},NullElement.prototype.destroy=function(){},NullElement.prototype.sourceRectAtTime=function(){},NullElement.prototype.hide=function(){},extendPrototype([BaseElement,TransformElement,HierarchyElement,FrameElement],NullElement),SVGBaseElement.prototype={initRendererElement:function(){this.layerElement=createNS("g")},createContainerElements:function(){this.matteElement=createNS("g"),this.transformedElement=this.layerElement,this.maskedElement=this.layerElement,this._sizeChanged=!1;var t,e,r,i=null;if(this.data.td){if(3==this.data.td||1==this.data.td){var s=createNS("mask");s.setAttribute("id",this.layerId),s.setAttribute("mask-type",3==this.data.td?"luminance":"alpha"),s.appendChild(this.layerElement),i=s,this.globalData.defs.appendChild(s),featureSupport.maskType||1!=this.data.td||(s.setAttribute("mask-type","luminance"),t=createElementID(),e=filtersFactory.createFilter(t),this.globalData.defs.appendChild(e),e.appendChild(filtersFactory.createAlphaToLuminanceFilter()),(r=createNS("g")).appendChild(this.layerElement),i=r,s.appendChild(r),r.setAttribute("filter","url("+locationHref+"#"+t+")"))}else if(2==this.data.td){var a=createNS("mask");a.setAttribute("id",this.layerId),a.setAttribute("mask-type","alpha");var n=createNS("g");a.appendChild(n),t=createElementID(),e=filtersFactory.createFilter(t);var o=createNS("feComponentTransfer");o.setAttribute("in","SourceGraphic"),e.appendChild(o);var h=createNS("feFuncA");h.setAttribute("type","table"),h.setAttribute("tableValues","1.0 0.0"),o.appendChild(h),this.globalData.defs.appendChild(e);var p=createNS("rect");p.setAttribute("width",this.comp.data.w),p.setAttribute("height",this.comp.data.h),p.setAttribute("x","0"),p.setAttribute("y","0"),p.setAttribute("fill","#ffffff"),p.setAttribute("opacity","0"),n.setAttribute("filter","url("+locationHref+"#"+t+")"),n.appendChild(p),n.appendChild(this.layerElement),i=n,featureSupport.maskType||(a.setAttribute("mask-type","luminance"),e.appendChild(filtersFactory.createAlphaToLuminanceFilter()),r=createNS("g"),n.appendChild(p),r.appendChild(this.layerElement),i=r,n.appendChild(r)),this.globalData.defs.appendChild(a)}}else this.data.tt?(this.matteElement.appendChild(this.layerElement),i=this.matteElement,this.baseElement=this.matteElement):this.baseElement=this.layerElement;if(this.data.ln&&this.layerElement.setAttribute("id",this.data.ln),this.data.cl&&this.layerElement.setAttribute("class",this.data.cl),0===this.data.ty&&!this.data.hd){var l=createNS("clipPath"),m=createNS("path");m.setAttribute("d","M0,0 L"+this.data.w+",0 L"+this.data.w+","+this.data.h+" L0,"+this.data.h+"z");var f=createElementID();if(l.setAttribute("id",f),l.appendChild(m),this.globalData.defs.appendChild(l),this.checkMasks()){var c=createNS("g");c.setAttribute("clip-path","url("+locationHref+"#"+f+")"),c.appendChild(this.layerElement),this.transformedElement=c,i?i.appendChild(this.transformedElement):this.baseElement=this.transformedElement}else this.layerElement.setAttribute("clip-path","url("+locationHref+"#"+f+")")}0!==this.data.bm&&this.setBlendMode()},renderElement:function(){this.finalTransform._matMdf&&this.transformedElement.setAttribute("transform",this.finalTransform.mat.to2dCSS()),this.finalTransform._opMdf&&this.transformedElement.setAttribute("opacity",this.finalTransform.mProp.o.v)},destroyBaseElement:function(){this.layerElement=null,this.matteElement=null,this.maskManager.destroy()},getBaseElement:function(){return this.data.hd?null:this.baseElement},createRenderableComponents:function(){this.maskManager=new MaskElement(this.data,this,this.globalData),this.renderableEffectsManager=new SVGEffects(this)},setMatte:function(t){this.matteElement&&this.matteElement.setAttribute("mask","url("+locationHref+"#"+t+")")}},IShapeElement.prototype={addShapeToModifiers:function(t){var e,r=this.shapeModifiers.length;for(e=0;e<r;e+=1)this.shapeModifiers[e].addShape(t)},isShapeInAnimatedModifiers:function(t){for(var e=this.shapeModifiers.length;0<e;)if(this.shapeModifiers[0].isAnimatedWithShape(t))return!0;return!1},renderModifiers:function(){if(this.shapeModifiers.length){var t,e=this.shapes.length;for(t=0;t<e;t+=1)this.shapes[t].sh.reset();for(t=(e=this.shapeModifiers.length)-1;0<=t;t-=1)this.shapeModifiers[t].processShapes(this._isFirstFrame)}},lcEnum:{1:"butt",2:"round",3:"square"},ljEnum:{1:"miter",2:"round",3:"bevel"},searchProcessedElement:function(t){for(var e=this.processedElements,r=0,i=e.length;r<i;){if(e[r].elem===t)return e[r].pos;r+=1}return 0},addProcessedElement:function(t,e){for(var r=this.processedElements,i=r.length;i;)if(r[i-=1].elem===t)return void(r[i].pos=e);r.push(new ProcessedElement(t,e))},prepareFrame:function(t){this.prepareRenderableFrame(t),this.prepareProperties(t,this.isInRange)}},ITextElement.prototype.initElement=function(t,e,r){this.lettersChangedFlag=!0,this.initFrame(),this.initBaseData(t,e,r),this.textProperty=new TextProperty(this,t.t,this.dynamicProperties),this.textAnimator=new TextAnimatorProperty(t.t,this.renderType,this),this.initTransform(t,e,r),this.initHierarchy(),this.initRenderable(),this.initRendererElement(),this.createContainerElements(),this.createRenderableComponents(),this.createContent(),this.hide(),this.textAnimator.searchProperties(this.dynamicProperties)},ITextElement.prototype.prepareFrame=function(t){this._mdf=!1,this.prepareRenderableFrame(t),this.prepareProperties(t,this.isInRange),(this.textProperty._mdf||this.textProperty._isFirstFrame)&&(this.buildNewText(),this.textProperty._isFirstFrame=!1,this.textProperty._mdf=!1)},ITextElement.prototype.createPathShape=function(t,e){var r,i,s=e.length,a="";for(r=0;r<s;r+=1)i=e[r].ks.k,a+=buildShapeString(i,i.i.length,!0,t);return a},ITextElement.prototype.updateDocumentData=function(t,e){this.textProperty.updateDocumentData(t,e)},ITextElement.prototype.canResizeFont=function(t){this.textProperty.canResizeFont(t)},ITextElement.prototype.setMinimumFontSize=function(t){this.textProperty.setMinimumFontSize(t)},ITextElement.prototype.applyTextPropertiesToMatrix=function(t,e,r,i,s){switch(t.ps&&e.translate(t.ps[0],t.ps[1]+t.ascent,0),e.translate(0,-t.ls,0),t.j){case 1:e.translate(t.justifyOffset+(t.boxWidth-t.lineWidths[r]),0,0);break;case 2:e.translate(t.justifyOffset+(t.boxWidth-t.lineWidths[r])/2,0,0)}e.translate(i,s,0)},ITextElement.prototype.buildColor=function(t){return"rgb("+Math.round(255*t[0])+","+Math.round(255*t[1])+","+Math.round(255*t[2])+")"},ITextElement.prototype.emptyProp=new LetterProps,ITextElement.prototype.destroy=function(){},extendPrototype([BaseElement,TransformElement,HierarchyElement,FrameElement,RenderableDOMElement],ICompElement),ICompElement.prototype.initElement=function(t,e,r){this.initFrame(),this.initBaseData(t,e,r),this.initTransform(t,e,r),this.initRenderable(),this.initHierarchy(),this.initRendererElement(),this.createContainerElements(),this.createRenderableComponents(),!this.data.xt&&e.progressiveLoad||this.buildAllItems(),this.hide()},ICompElement.prototype.prepareFrame=function(t){if(this._mdf=!1,this.prepareRenderableFrame(t),this.prepareProperties(t,this.isInRange),this.isInRange||this.data.xt){if(this.tm._placeholder)this.renderedFrame=t/this.data.sr;else{var e=this.tm.v;e===this.data.op&&(e=this.data.op-1),this.renderedFrame=e}var r,i=this.elements.length;for(this.completeLayers||this.checkLayers(this.renderedFrame),r=i-1;0<=r;r-=1)(this.completeLayers||this.elements[r])&&(this.elements[r].prepareFrame(this.renderedFrame-this.layers[r].st),this.elements[r]._mdf&&(this._mdf=!0))}},ICompElement.prototype.renderInnerContent=function(){var t,e=this.layers.length;for(t=0;t<e;t+=1)(this.completeLayers||this.elements[t])&&this.elements[t].renderFrame()},ICompElement.prototype.setElements=function(t){this.elements=t},ICompElement.prototype.getElements=function(){return this.elements},ICompElement.prototype.destroyElements=function(){var t,e=this.layers.length;for(t=0;t<e;t+=1)this.elements[t]&&this.elements[t].destroy()},ICompElement.prototype.destroy=function(){this.destroyElements(),this.destroyBaseElement()},extendPrototype([BaseElement,TransformElement,SVGBaseElement,HierarchyElement,FrameElement,RenderableDOMElement],IImageElement),IImageElement.prototype.createContent=function(){var t=this.globalData.getAssetsPath(this.assetData);this.innerElem=createNS("image"),this.innerElem.setAttribute("width",this.assetData.w+"px"),this.innerElem.setAttribute("height",this.assetData.h+"px"),this.innerElem.setAttribute("preserveAspectRatio",this.assetData.pr||this.globalData.renderConfig.imagePreserveAspectRatio),this.innerElem.setAttributeNS("http://www.w3.org/1999/xlink","href",t),this.layerElement.appendChild(this.innerElem)},IImageElement.prototype.sourceRectAtTime=function(){return this.sourceRect},extendPrototype([IImageElement],ISolidElement),ISolidElement.prototype.createContent=function(){var t=createNS("rect");t.setAttribute("width",this.data.sw),t.setAttribute("height",this.data.sh),t.setAttribute("fill",this.data.sc),this.layerElement.appendChild(t)},extendPrototype([BaseElement,TransformElement,SVGBaseElement,IShapeElement,HierarchyElement,FrameElement,RenderableDOMElement],SVGShapeElement),SVGShapeElement.prototype.initSecondaryElement=function(){},SVGShapeElement.prototype.identityMatrix=new Matrix,SVGShapeElement.prototype.buildExpressionInterface=function(){},SVGShapeElement.prototype.createContent=function(){this.searchShapes(this.shapesData,this.itemsData,this.prevViewData,this.layerElement,0,[],!0),this.filterUniqueShapes()},SVGShapeElement.prototype.filterUniqueShapes=function(){var t,e,r,i,s=this.shapes.length,a=this.stylesList.length,n=[],o=!1;for(r=0;r<a;r+=1){for(i=this.stylesList[r],o=!1,t=n.length=0;t<s;t+=1)-1!==(e=this.shapes[t]).styles.indexOf(i)&&(n.push(e),o=e._isAnimated||o);1<n.length&&o&&this.setShapesAsAnimated(n)}},SVGShapeElement.prototype.setShapesAsAnimated=function(t){var e,r=t.length;for(e=0;e<r;e+=1)t[e].setAsAnimated()},SVGShapeElement.prototype.createStyleElement=function(t,e){var r,i=new SVGStyleData(t,e),s=i.pElem;if("st"===t.ty)r=new SVGStrokeStyleData(this,t,i);else if("fl"===t.ty)r=new SVGFillStyleData(this,t,i);else if("gf"===t.ty||"gs"===t.ty){r=new("gf"===t.ty?SVGGradientFillStyleData:SVGGradientStrokeStyleData)(this,t,i),this.globalData.defs.appendChild(r.gf),r.maskId&&(this.globalData.defs.appendChild(r.ms),this.globalData.defs.appendChild(r.of),s.setAttribute("mask","url("+locationHref+"#"+r.maskId+")"))}return"st"!==t.ty&&"gs"!==t.ty||(s.setAttribute("stroke-linecap",this.lcEnum[t.lc]||"round"),s.setAttribute("stroke-linejoin",this.ljEnum[t.lj]||"round"),s.setAttribute("fill-opacity","0"),1===t.lj&&s.setAttribute("stroke-miterlimit",t.ml)),2===t.r&&s.setAttribute("fill-rule","evenodd"),t.ln&&s.setAttribute("id",t.ln),t.cl&&s.setAttribute("class",t.cl),t.bm&&(s.style["mix-blend-mode"]=getBlendMode(t.bm)),this.stylesList.push(i),this.addToAnimatedContents(t,r),r},SVGShapeElement.prototype.createGroupElement=function(t){var e=new ShapeGroupData;return t.ln&&e.gr.setAttribute("id",t.ln),t.cl&&e.gr.setAttribute("class",t.cl),t.bm&&(e.gr.style["mix-blend-mode"]=getBlendMode(t.bm)),e},SVGShapeElement.prototype.createTransformElement=function(t,e){var r=TransformPropertyFactory.getTransformProperty(this,t,this),i=new SVGTransformData(r,r.o,e);return this.addToAnimatedContents(t,i),i},SVGShapeElement.prototype.createShapeElement=function(t,e,r){var i=4;"rc"===t.ty?i=5:"el"===t.ty?i=6:"sr"===t.ty&&(i=7);var s=new SVGShapeData(e,r,ShapePropertyFactory.getShapeProp(this,t,i,this));return this.shapes.push(s),this.addShapeToModifiers(s),this.addToAnimatedContents(t,s),s},SVGShapeElement.prototype.addToAnimatedContents=function(t,e){for(var r=0,i=this.animatedContents.length;r<i;){if(this.animatedContents[r].element===e)return;r+=1}this.animatedContents.push({fn:SVGElementsRenderer.createRenderFunction(t),element:e,data:t})},SVGShapeElement.prototype.setElementStyles=function(t){var e,r=t.styles,i=this.stylesList.length;for(e=0;e<i;e+=1)this.stylesList[e].closed||r.push(this.stylesList[e])},SVGShapeElement.prototype.reloadShapes=function(){this._isFirstFrame=!0;var t,e=this.itemsData.length;for(t=0;t<e;t+=1)this.prevViewData[t]=this.itemsData[t];for(this.searchShapes(this.shapesData,this.itemsData,this.prevViewData,this.layerElement,0,[],!0),this.filterUniqueShapes(),e=this.dynamicProperties.length,t=0;t<e;t+=1)this.dynamicProperties[t].getValue();this.renderModifiers()},SVGShapeElement.prototype.searchShapes=function(t,e,r,i,s,a,n){var o,h,p,l,m,f,c=[].concat(a),d=t.length-1,u=[],y=[];for(o=d;0<=o;o-=1){if((f=this.searchProcessedElement(t[o]))?e[o]=r[f-1]:t[o]._render=n,"fl"==t[o].ty||"st"==t[o].ty||"gf"==t[o].ty||"gs"==t[o].ty)f?e[o].style.closed=!1:e[o]=this.createStyleElement(t[o],s),t[o]._render&&i.appendChild(e[o].style.pElem),u.push(e[o].style);else if("gr"==t[o].ty){if(f)for(p=e[o].it.length,h=0;h<p;h+=1)e[o].prevViewData[h]=e[o].it[h];else e[o]=this.createGroupElement(t[o]);this.searchShapes(t[o].it,e[o].it,e[o].prevViewData,e[o].gr,s+1,c,n),t[o]._render&&i.appendChild(e[o].gr)}else"tr"==t[o].ty?(f||(e[o]=this.createTransformElement(t[o],i)),l=e[o].transform,c.push(l)):"sh"==t[o].ty||"rc"==t[o].ty||"el"==t[o].ty||"sr"==t[o].ty?(f||(e[o]=this.createShapeElement(t[o],c,s)),this.setElementStyles(e[o])):"tm"==t[o].ty||"rd"==t[o].ty||"ms"==t[o].ty?(f?(m=e[o]).closed=!1:((m=ShapeModifiers.getModifier(t[o].ty)).init(this,t[o]),e[o]=m,this.shapeModifiers.push(m)),y.push(m)):"rp"==t[o].ty&&(f?(m=e[o]).closed=!0:(m=ShapeModifiers.getModifier(t[o].ty),(e[o]=m).init(this,t,o,e),this.shapeModifiers.push(m),n=!1),y.push(m));this.addProcessedElement(t[o],o+1)}for(d=u.length,o=0;o<d;o+=1)u[o].closed=!0;for(d=y.length,o=0;o<d;o+=1)y[o].closed=!0},SVGShapeElement.prototype.renderInnerContent=function(){this.renderModifiers();var t,e=this.stylesList.length;for(t=0;t<e;t+=1)this.stylesList[t].reset();for(this.renderShape(),t=0;t<e;t+=1)(this.stylesList[t]._mdf||this._isFirstFrame)&&(this.stylesList[t].msElem&&(this.stylesList[t].msElem.setAttribute("d",this.stylesList[t].d),this.stylesList[t].d="M0 0"+this.stylesList[t].d),this.stylesList[t].pElem.setAttribute("d",this.stylesList[t].d||"M0 0"))},SVGShapeElement.prototype.renderShape=function(){var t,e,r=this.animatedContents.length;for(t=0;t<r;t+=1)e=this.animatedContents[t],(this._isFirstFrame||e.element._isAnimated)&&!0!==e.data&&e.fn(e.data,e.element,this._isFirstFrame)},SVGShapeElement.prototype.destroy=function(){this.destroyBaseElement(),this.shapesData=null,this.itemsData=null},CVContextData.prototype.duplicate=function(){var t=2*this._length,e=this.savedOp;this.savedOp=createTypedArray("float32",t),this.savedOp.set(e);var r=0;for(r=this._length;r<t;r+=1)this.saved[r]=createTypedArray("float32",16);this._length=t},CVContextData.prototype.reset=function(){this.cArrPos=0,this.cTr.reset(),this.cO=1},CVBaseElement.prototype={createElements:function(){},initRendererElement:function(){},createContainerElements:function(){this.canvasContext=this.globalData.canvasContext,this.renderableEffectsManager=new CVEffects(this)},createContent:function(){},setBlendMode:function(){var t=this.globalData;if(t.blendMode!==this.data.bm){t.blendMode=this.data.bm;var e=getBlendMode(this.data.bm);t.canvasContext.globalCompositeOperation=e}},createRenderableComponents:function(){this.maskManager=new CVMaskElement(this.data,this)},hideElement:function(){this.hidden||this.isInRange&&!this.isTransparent||(this.hidden=!0)},showElement:function(){this.isInRange&&!this.isTransparent&&(this.hidden=!1,this._isFirstFrame=!0,this.maskManager._isFirstFrame=!0)},renderFrame:function(){this.hidden||this.data.hd||(this.renderTransform(),this.renderRenderable(),this.setBlendMode(),this.globalData.renderer.save(),this.globalData.renderer.ctxTransform(this.finalTransform.mat.props),this.globalData.renderer.ctxOpacity(this.finalTransform.mProp.o.v),this.renderInnerContent(),this.globalData.renderer.restore(),this.maskManager.hasMasks&&this.globalData.renderer.restore(!0),this._isFirstFrame&&(this._isFirstFrame=!1))},destroy:function(){this.canvasContext=null,this.data=null,this.globalData=null,this.maskManager.destroy()},mHelper:new Matrix},CVBaseElement.prototype.hide=CVBaseElement.prototype.hideElement,CVBaseElement.prototype.show=CVBaseElement.prototype.showElement,extendPrototype([CanvasRenderer,ICompElement,CVBaseElement],CVCompElement),CVCompElement.prototype.renderInnerContent=function(){var t;for(t=this.layers.length-1;0<=t;t-=1)(this.completeLayers||this.elements[t])&&this.elements[t].renderFrame()},CVCompElement.prototype.destroy=function(){var t;for(t=this.layers.length-1;0<=t;t-=1)this.elements[t]&&this.elements[t].destroy();this.layers=null,this.elements=null},CVMaskElement.prototype.renderFrame=function(){if(this.hasMasks){var t,e,r,i,s=this.element.finalTransform.mat,a=this.element.canvasContext,n=this.masksProperties.length;for(a.beginPath(),t=0;t<n;t++)if("n"!==this.masksProperties[t].mode){this.masksProperties[t].inv&&(a.moveTo(0,0),a.lineTo(this.element.globalData.compSize.w,0),a.lineTo(this.element.globalData.compSize.w,this.element.globalData.compSize.h),a.lineTo(0,this.element.globalData.compSize.h),a.lineTo(0,0)),i=this.viewData[t].v,e=s.applyToPointArray(i.v[0][0],i.v[0][1],0),a.moveTo(e[0],e[1]);var o,h=i._length;for(o=1;o<h;o++)r=s.applyToTriplePoints(i.o[o-1],i.i[o],i.v[o]),a.bezierCurveTo(r[0],r[1],r[2],r[3],r[4],r[5]);r=s.applyToTriplePoints(i.o[o-1],i.i[0],i.v[0]),a.bezierCurveTo(r[0],r[1],r[2],r[3],r[4],r[5])}this.element.globalData.renderer.save(!0),a.clip()}},CVMaskElement.prototype.getMaskProperty=MaskElement.prototype.getMaskProperty,CVMaskElement.prototype.destroy=function(){this.element=null},extendPrototype([BaseElement,TransformElement,CVBaseElement,IShapeElement,HierarchyElement,FrameElement,RenderableElement],CVShapeElement),CVShapeElement.prototype.initElement=RenderableDOMElement.prototype.initElement,CVShapeElement.prototype.transformHelper={opacity:1,_opMdf:!1},CVShapeElement.prototype.dashResetter=[],CVShapeElement.prototype.createContent=function(){this.searchShapes(this.shapesData,this.itemsData,this.prevViewData,!0,[])},CVShapeElement.prototype.createStyleElement=function(t,e){var r={data:t,type:t.ty,preTransforms:this.transformsManager.addTransformSequence(e),transforms:[],elements:[],closed:!0===t.hd},i={};if("fl"==t.ty||"st"==t.ty?(i.c=PropertyFactory.getProp(this,t.c,1,255,this),i.c.k||(r.co="rgb("+bm_floor(i.c.v[0])+","+bm_floor(i.c.v[1])+","+bm_floor(i.c.v[2])+")")):"gf"!==t.ty&&"gs"!==t.ty||(i.s=PropertyFactory.getProp(this,t.s,1,null,this),i.e=PropertyFactory.getProp(this,t.e,1,null,this),i.h=PropertyFactory.getProp(this,t.h||{k:0},0,.01,this),i.a=PropertyFactory.getProp(this,t.a||{k:0},0,degToRads,this),i.g=new GradientProperty(this,t.g,this)),i.o=PropertyFactory.getProp(this,t.o,0,.01,this),"st"==t.ty||"gs"==t.ty){if(r.lc=this.lcEnum[t.lc]||"round",r.lj=this.ljEnum[t.lj]||"round",1==t.lj&&(r.ml=t.ml),i.w=PropertyFactory.getProp(this,t.w,0,null,this),i.w.k||(r.wi=i.w.v),t.d){var s=new DashProperty(this,t.d,"canvas",this);i.d=s,i.d.k||(r.da=i.d.dashArray,r.do=i.d.dashoffset[0])}}else r.r=2===t.r?"evenodd":"nonzero";return this.stylesList.push(r),i.style=r,i},CVShapeElement.prototype.createGroupElement=function(t){return{it:[],prevViewData:[]}},CVShapeElement.prototype.createTransformElement=function(t){return{transform:{opacity:1,_opMdf:!1,key:this.transformsManager.getNewKey(),op:PropertyFactory.getProp(this,t.o,0,.01,this),mProps:TransformPropertyFactory.getTransformProperty(this,t,this)}}},CVShapeElement.prototype.createShapeElement=function(t){var e=new CVShapeData(this,t,this.stylesList,this.transformsManager);return this.shapes.push(e),this.addShapeToModifiers(e),e},CVShapeElement.prototype.reloadShapes=function(){this._isFirstFrame=!0;var t,e=this.itemsData.length;for(t=0;t<e;t+=1)this.prevViewData[t]=this.itemsData[t];for(this.searchShapes(this.shapesData,this.itemsData,this.prevViewData,!0,[]),e=this.dynamicProperties.length,t=0;t<e;t+=1)this.dynamicProperties[t].getValue();this.renderModifiers(),this.transformsManager.processSequences(this._isFirstFrame)},CVShapeElement.prototype.addTransformToStyleList=function(t){var e,r=this.stylesList.length;for(e=0;e<r;e+=1)this.stylesList[e].closed||this.stylesList[e].transforms.push(t)},CVShapeElement.prototype.removeTransformFromStyleList=function(){var t,e=this.stylesList.length;for(t=0;t<e;t+=1)this.stylesList[t].closed||this.stylesList[t].transforms.pop()},CVShapeElement.prototype.closeStyles=function(t){var e,r=t.length;for(e=0;e<r;e+=1)t[e].closed=!0},CVShapeElement.prototype.searchShapes=function(t,e,r,i,s){var a,n,o,h,p,l,m=t.length-1,f=[],c=[],d=[].concat(s);for(a=m;0<=a;a-=1){if((h=this.searchProcessedElement(t[a]))?e[a]=r[h-1]:t[a]._shouldRender=i,"fl"==t[a].ty||"st"==t[a].ty||"gf"==t[a].ty||"gs"==t[a].ty)h?e[a].style.closed=!1:e[a]=this.createStyleElement(t[a],d),f.push(e[a].style);else if("gr"==t[a].ty){if(h)for(o=e[a].it.length,n=0;n<o;n+=1)e[a].prevViewData[n]=e[a].it[n];else e[a]=this.createGroupElement(t[a]);this.searchShapes(t[a].it,e[a].it,e[a].prevViewData,i,d)}else"tr"==t[a].ty?(h||(l=this.createTransformElement(t[a]),e[a]=l),d.push(e[a]),this.addTransformToStyleList(e[a])):"sh"==t[a].ty||"rc"==t[a].ty||"el"==t[a].ty||"sr"==t[a].ty?h||(e[a]=this.createShapeElement(t[a])):"tm"==t[a].ty||"rd"==t[a].ty?(h?(p=e[a]).closed=!1:((p=ShapeModifiers.getModifier(t[a].ty)).init(this,t[a]),e[a]=p,this.shapeModifiers.push(p)),c.push(p)):"rp"==t[a].ty&&(h?(p=e[a]).closed=!0:(p=ShapeModifiers.getModifier(t[a].ty),(e[a]=p).init(this,t,a,e),this.shapeModifiers.push(p),i=!1),c.push(p));this.addProcessedElement(t[a],a+1)}for(this.removeTransformFromStyleList(),this.closeStyles(f),m=c.length,a=0;a<m;a+=1)c[a].closed=!0},CVShapeElement.prototype.renderInnerContent=function(){this.transformHelper.opacity=1,this.transformHelper._opMdf=!1,this.renderModifiers(),this.transformsManager.processSequences(this._isFirstFrame),this.renderShape(this.transformHelper,this.shapesData,this.itemsData,!0)},CVShapeElement.prototype.renderShapeTransform=function(t,e){(t._opMdf||e.op._mdf||this._isFirstFrame)&&(e.opacity=t.opacity,e.opacity*=e.op.v,e._opMdf=!0)},CVShapeElement.prototype.drawLayer=function(){var t,e,r,i,s,a,n,o,h,p=this.stylesList.length,l=this.globalData.renderer,m=this.globalData.canvasContext;for(t=0;t<p;t+=1)if(("st"!==(o=(h=this.stylesList[t]).type)&&"gs"!==o||0!==h.wi)&&h.data._shouldRender&&0!==h.coOp&&0!==this.globalData.currentGlobalAlpha){for(l.save(),a=h.elements,"st"===o||"gs"===o?(m.strokeStyle="st"===o?h.co:h.grd,m.lineWidth=h.wi,m.lineCap=h.lc,m.lineJoin=h.lj,m.miterLimit=h.ml||0):m.fillStyle="fl"===o?h.co:h.grd,l.ctxOpacity(h.coOp),"st"!==o&&"gs"!==o&&m.beginPath(),l.ctxTransform(h.preTransforms.finalTransform.props),r=a.length,e=0;e<r;e+=1){for("st"!==o&&"gs"!==o||(m.beginPath(),h.da&&(m.setLineDash(h.da),m.lineDashOffset=h.do)),s=(n=a[e].trNodes).length,i=0;i<s;i+=1)"m"==n[i].t?m.moveTo(n[i].p[0],n[i].p[1]):"c"==n[i].t?m.bezierCurveTo(n[i].pts[0],n[i].pts[1],n[i].pts[2],n[i].pts[3],n[i].pts[4],n[i].pts[5]):m.closePath();"st"!==o&&"gs"!==o||(m.stroke(),h.da&&m.setLineDash(this.dashResetter))}"st"!==o&&"gs"!==o&&m.fill(h.r),l.restore()}},CVShapeElement.prototype.renderShape=function(t,e,r,i){var s,a;for(a=t,s=e.length-1;0<=s;s-=1)"tr"==e[s].ty?(a=r[s].transform,this.renderShapeTransform(t,a)):"sh"==e[s].ty||"el"==e[s].ty||"rc"==e[s].ty||"sr"==e[s].ty?this.renderPath(e[s],r[s]):"fl"==e[s].ty?this.renderFill(e[s],r[s],a):"st"==e[s].ty?this.renderStroke(e[s],r[s],a):"gf"==e[s].ty||"gs"==e[s].ty?this.renderGradientFill(e[s],r[s],a):"gr"==e[s].ty?this.renderShape(a,e[s].it,r[s].it):e[s].ty;i&&this.drawLayer()},CVShapeElement.prototype.renderStyledShape=function(t,e){if(this._isFirstFrame||e._mdf||t.transforms._mdf){var r,i,s,a=t.trNodes,n=e.paths,o=n._length;a.length=0;var h=t.transforms.finalTransform;for(s=0;s<o;s+=1){var p=n.shapes[s];if(p&&p.v){for(i=p._length,r=1;r<i;r+=1)1===r&&a.push({t:"m",p:h.applyToPointArray(p.v[0][0],p.v[0][1],0)}),a.push({t:"c",pts:h.applyToTriplePoints(p.o[r-1],p.i[r],p.v[r])});1===i&&a.push({t:"m",p:h.applyToPointArray(p.v[0][0],p.v[0][1],0)}),p.c&&i&&(a.push({t:"c",pts:h.applyToTriplePoints(p.o[r-1],p.i[0],p.v[0])}),a.push({t:"z"}))}}t.trNodes=a}},CVShapeElement.prototype.renderPath=function(t,e){if(!0!==t.hd&&t._shouldRender){var r,i=e.styledShapes.length;for(r=0;r<i;r+=1)this.renderStyledShape(e.styledShapes[r],e.sh)}},CVShapeElement.prototype.renderFill=function(t,e,r){var i=e.style;(e.c._mdf||this._isFirstFrame)&&(i.co="rgb("+bm_floor(e.c.v[0])+","+bm_floor(e.c.v[1])+","+bm_floor(e.c.v[2])+")"),(e.o._mdf||r._opMdf||this._isFirstFrame)&&(i.coOp=e.o.v*r.opacity)},CVShapeElement.prototype.renderGradientFill=function(t,e,r){var i=e.style;if(!i.grd||e.g._mdf||e.s._mdf||e.e._mdf||1!==t.t&&(e.h._mdf||e.a._mdf)){var s=this.globalData.canvasContext,a=e.s.v,n=e.e.v;if(1===t.t)f=s.createLinearGradient(a[0],a[1],n[0],n[1]);else var o=Math.sqrt(Math.pow(a[0]-n[0],2)+Math.pow(a[1]-n[1],2)),h=Math.atan2(n[1]-a[1],n[0]-a[0]),p=o*(1<=e.h.v?.99:e.h.v<=-1?-.99:e.h.v),l=Math.cos(h+e.a.v)*p+a[0],m=Math.sin(h+e.a.v)*p+a[1],f=s.createRadialGradient(l,m,0,a[0],a[1],o);var c,d=t.g.p,u=e.g.c,y=1;for(c=0;c<d;c+=1)e.g._hasOpacity&&e.g._collapsable&&(y=e.g.o[2*c+1]),f.addColorStop(u[4*c]/100,"rgba("+u[4*c+1]+","+u[4*c+2]+","+u[4*c+3]+","+y+")");i.grd=f}i.coOp=e.o.v*r.opacity},CVShapeElement.prototype.renderStroke=function(t,e,r){var i=e.style,s=e.d;s&&(s._mdf||this._isFirstFrame)&&(i.da=s.dashArray,i.do=s.dashoffset[0]),(e.c._mdf||this._isFirstFrame)&&(i.co="rgb("+bm_floor(e.c.v[0])+","+bm_floor(e.c.v[1])+","+bm_floor(e.c.v[2])+")"),(e.o._mdf||r._opMdf||this._isFirstFrame)&&(i.coOp=e.o.v*r.opacity),(e.w._mdf||this._isFirstFrame)&&(i.wi=e.w.v)},CVShapeElement.prototype.destroy=function(){this.shapesData=null,this.globalData=null,this.canvasContext=null,this.stylesList.length=0,this.itemsData.length=0},extendPrototype([BaseElement,TransformElement,CVBaseElement,HierarchyElement,FrameElement,RenderableElement],CVSolidElement),CVSolidElement.prototype.initElement=SVGShapeElement.prototype.initElement,CVSolidElement.prototype.prepareFrame=IImageElement.prototype.prepareFrame,CVSolidElement.prototype.renderInnerContent=function(){var t=this.canvasContext;t.fillStyle=this.data.sc,t.fillRect(0,0,this.data.sw,this.data.sh)},CVEffects.prototype.renderFrame=function(){};var animationManager=(tJ={},uJ=[],vJ=0,wJ=0,xJ=0,yJ=!0,zJ=!1,tJ.registerAnimation=BJ,tJ.loadAnimation=function(t){var e=new AnimationItem;return FJ(e,null),e.setParams(t),e},tJ.setSpeed=function(t,e){var r;for(r=0;r<wJ;r+=1)uJ[r].animation.setSpeed(t,e)},tJ.setDirection=function(t,e){var r;for(r=0;r<wJ;r+=1)uJ[r].animation.setDirection(t,e)},tJ.play=function(t){var e;for(e=0;e<wJ;e+=1)uJ[e].animation.play(t)},tJ.pause=function(t){var e;for(e=0;e<wJ;e+=1)uJ[e].animation.pause(t)},tJ.stop=function(t){var e;for(e=0;e<wJ;e+=1)uJ[e].animation.stop(t)},tJ.togglePause=function(t){var e;for(e=0;e<wJ;e+=1)uJ[e].animation.togglePause(t)},tJ.searchAnimations=function(t,e,r){var i,s=[].concat([].slice.call(document.getElementsByClassName("lottie")),[].slice.call(document.getElementsByClassName("bodymovin"))),a=s.length;for(i=0;i<a;i+=1)r&&s[i].setAttribute("data-bm-type",r),BJ(s[i],t);if(e&&0===a){r||(r="svg");var n=document.getElementsByTagName("body")[0];n.innerHTML="";var o=createTag("div");o.style.width="100%",o.style.height="100%",o.setAttribute("data-bm-type",r),n.appendChild(o),BJ(o,t)}},tJ.resize=function(){var t;for(t=0;t<wJ;t+=1)uJ[t].animation.resize()},tJ.goToAndStop=function(t,e,r){var i;for(i=0;i<wJ;i+=1)uJ[i].animation.goToAndStop(t,e,r)},tJ.destroy=function(t){var e;for(e=wJ-1;0<=e;e-=1)uJ[e].animation.destroy(t)},tJ.freeze=function(){zJ=!0},tJ.unfreeze=function(){zJ=!1,TJ()},tJ.getRegisteredAnimations=function(){var t,e=uJ.length,r=[];for(t=0;t<e;t+=1)r.push(uJ[t].animation);return r},tJ),tJ,uJ,vJ,wJ,xJ,yJ,zJ,PK,QK,RK,SK,TK,UK,VK;function AJ(t){for(var e=0,r=t.target;e<wJ;)uJ[e].animation===r&&(uJ.splice(e,1),e-=1,wJ-=1,r.isPaused||EJ()),e+=1}function BJ(t,e){if(!t)return null;for(var r=0;r<wJ;){if(uJ[r].elem==t&&null!==uJ[r].elem)return uJ[r].animation;r+=1}var i=new AnimationItem;return FJ(i,t),i.setData(t,e),i}function DJ(){xJ+=1,TJ()}function EJ(){xJ-=1}function FJ(t,e){t.addEventListener("destroy",AJ),t.addEventListener("_active",DJ),t.addEventListener("_idle",EJ),uJ.push({elem:e,animation:t}),wJ+=1}function KJ(t){var e,r=t-vJ;for(e=0;e<wJ;e+=1)uJ[e].animation.advanceTime(r);vJ=t,xJ&&!zJ?window.requestAnimationFrame(KJ):yJ=!0}function LJ(t){vJ=t,window.requestAnimationFrame(KJ)}function TJ(){!zJ&&xJ&&yJ&&(window.requestAnimationFrame(LJ),yJ=!1)}function WK(t){for(var e=0,r=t.target;e<SK;)QK[e].animation===r&&(QK.splice(e,1),e-=1,SK-=1,r.isPaused||$K()),e+=1}function ZK(){TK+=1,nL()}function $K(){TK-=1}function _K(t,e){t.addEventListener("destroy",WK),t.addEventListener("_active",ZK),t.addEventListener("_idle",$K),QK.push({elem:e,animation:t}),SK+=1}function eL(t){var e,r=t-RK;for(e=0;e<SK;e+=1)QK[e].animation.advanceTime(r);RK=t,TK&&!VK?requestAnimationFrame(eL):UK=!0}function fL(t){RK=t,requestAnimationFrame(eL)}function nL(){!VK&&TK&&UK&&(requestAnimationFrame(fL),UK=!1)}PK={},QK=[],RK=0,SK=0,TK=0,UK=!0,VK=!1,PK.registerAnimation=function(t,e){if(!t)return null;for(var r=0;r<SK;){if(QK[r].elem==t&&null!==QK[r].elem)return QK[r].animation;r+=1}var i=new AnimationItem;return _K(i,t),i.setData(t,e),i},PK.loadAnimation=function(t){var e=new AnimationItem;return _K(e,null),e.setParams(t),e},PK.setSpeed=function(t,e){var r;for(r=0;r<SK;r+=1)QK[r].animation.setSpeed(t,e)},PK.setDirection=function(t,e){var r;for(r=0;r<SK;r+=1)QK[r].animation.setDirection(t,e)},PK.play=function(t){var e;for(e=0;e<SK;e+=1)QK[e].animation.play(t)},PK.pause=function(t){var e;for(e=0;e<SK;e+=1)QK[e].animation.pause(t)},PK.stop=function(t){var e;for(e=0;e<SK;e+=1)QK[e].animation.stop(t)},PK.togglePause=function(t){var e;for(e=0;e<SK;e+=1)QK[e].animation.togglePause(t)},PK.searchAnimations=function(t,e,r){throw new Error("Cannot access DOM from worker thread")},PK.resize=function(){var t;for(t=0;t<SK;t+=1)QK[t].animation.resize()},PK.goToAndStop=function(t,e,r){var i;for(i=0;i<SK;i+=1)QK[i].animation.goToAndStop(t,e,r)},PK.destroy=function(t){var e;for(e=SK-1;0<=e;e-=1)QK[e].animation.destroy(t)},PK.freeze=function(){VK=!0},PK.unfreeze=function(){VK=!1,nL()},PK.getRegisteredAnimations=function(){var t,e=QK.length,r=[];for(t=0;t<e;t+=1)r.push(QK[t].animation);return r},animationManager=PK;var AnimationItem=function(){this._cbs=[],this.name="",this.path="",this.isLoaded=!1,this.currentFrame=0,this.currentRawFrame=0,this.totalFrames=0,this.frameRate=0,this.frameMult=0,this.playSpeed=1,this.playDirection=1,this.playCount=0,this.animationData={},this.assets=[],this.isPaused=!0,this.autoplay=!1,this.loop=!0,this.renderer=null,this.animationID=createElementID(),this.assetsPath="",this.timeCompleted=0,this.segmentPos=0,this.subframeEnabled=subframeEnabled,this.segments=[],this._idle=!0,this._completedLoop=!1,this.projectInterface=ProjectInterface(),this.imagePreloader=new ImagePreloader};extendPrototype([BaseEvent],AnimationItem),AnimationItem.prototype.setParams=function(t){t.context&&(this.context=t.context),(t.wrapper||t.container)&&(this.wrapper=t.wrapper||t.container);var e=t.animType?t.animType:t.renderer?t.renderer:"svg";switch(e){case"canvas":this.renderer=new CanvasRenderer(this,t.rendererSettings);break;case"svg":this.renderer=new SVGRenderer(this,t.rendererSettings);break;default:this.renderer=new HybridRenderer(this,t.rendererSettings)}this.renderer.setProjectInterface(this.projectInterface),this.animType=e,""===t.loop||null===t.loop||(!1===t.loop?this.loop=!1:!0===t.loop?this.loop=!0:this.loop=parseInt(t.loop)),this.autoplay=!("autoplay"in t)||t.autoplay,this.name=t.name?t.name:"",this.autoloadSegments=!t.hasOwnProperty("autoloadSegments")||t.autoloadSegments,this.assetsPath=t.assetsPath,t.animationData?this.configAnimation(t.animationData):t.path&&("json"!=t.path.substr(-4)&&("/"!=t.path.substr(-1,1)&&(t.path+="/"),t.path+="data.json"),-1!=t.path.lastIndexOf("\\")?this.path=t.path.substr(0,t.path.lastIndexOf("\\")+1):this.path=t.path.substr(0,t.path.lastIndexOf("/")+1),this.fileName=t.path.substr(t.path.lastIndexOf("/")+1),this.fileName=this.fileName.substr(0,this.fileName.lastIndexOf(".json")),assetLoader.load(t.path,this.configAnimation.bind(this),function(){this.trigger("data_failed")}.bind(this)))},AnimationItem.prototype.setData=function(t,e){var r={wrapper:t,animationData:e?"object"==typeof e?e:JSON.parse(e):null},i=t.attributes;r.path=i.getNamedItem("data-animation-path")?i.getNamedItem("data-animation-path").value:i.getNamedItem("data-bm-path")?i.getNamedItem("data-bm-path").value:i.getNamedItem("bm-path")?i.getNamedItem("bm-path").value:"",r.animType=i.getNamedItem("data-anim-type")?i.getNamedItem("data-anim-type").value:i.getNamedItem("data-bm-type")?i.getNamedItem("data-bm-type").value:i.getNamedItem("bm-type")?i.getNamedItem("bm-type").value:i.getNamedItem("data-bm-renderer")?i.getNamedItem("data-bm-renderer").value:i.getNamedItem("bm-renderer")?i.getNamedItem("bm-renderer").value:"canvas";var s=i.getNamedItem("data-anim-loop")?i.getNamedItem("data-anim-loop").value:i.getNamedItem("data-bm-loop")?i.getNamedItem("data-bm-loop").value:i.getNamedItem("bm-loop")?i.getNamedItem("bm-loop").value:"";""===s||(r.loop="false"!==s&&("true"===s||parseInt(s)));var a=i.getNamedItem("data-anim-autoplay")?i.getNamedItem("data-anim-autoplay").value:i.getNamedItem("data-bm-autoplay")?i.getNamedItem("data-bm-autoplay").value:!i.getNamedItem("bm-autoplay")||i.getNamedItem("bm-autoplay").value;r.autoplay="false"!==a,r.name=i.getNamedItem("data-name")?i.getNamedItem("data-name").value:i.getNamedItem("data-bm-name")?i.getNamedItem("data-bm-name").value:i.getNamedItem("bm-name")?i.getNamedItem("bm-name").value:"","false"===(i.getNamedItem("data-anim-prerender")?i.getNamedItem("data-anim-prerender").value:i.getNamedItem("data-bm-prerender")?i.getNamedItem("data-bm-prerender").value:i.getNamedItem("bm-prerender")?i.getNamedItem("bm-prerender").value:"")&&(r.prerender=!1),this.setParams(r)},AnimationItem.prototype.includeLayers=function(t){t.op>this.animationData.op&&(this.animationData.op=t.op,this.totalFrames=Math.floor(t.op-this.animationData.ip));var e,r,i=this.animationData.layers,s=i.length,a=t.layers,n=a.length;for(r=0;r<n;r+=1)for(e=0;e<s;){if(i[e].id==a[r].id){i[e]=a[r];break}e+=1}if((t.chars||t.fonts)&&(this.renderer.globalData.fontManager.addChars(t.chars),this.renderer.globalData.fontManager.addFonts(t.fonts,this.renderer.globalData.defs)),t.assets)for(s=t.assets.length,e=0;e<s;e+=1)this.animationData.assets.push(t.assets[e]);this.animationData.__complete=!1,dataManager.completeData(this.animationData,this.renderer.globalData.fontManager),this.renderer.includeLayers(t.layers),expressionsPlugin&&expressionsPlugin.initExpressions(this),this.loadNextSegment()},AnimationItem.prototype.loadNextSegment=function(){var t=this.animationData.segments;if(!t||0===t.length||!this.autoloadSegments)return this.trigger("data_ready"),void(this.timeCompleted=this.totalFrames);var e=t.shift();this.timeCompleted=e.time*this.frameRate;var r=this.path+this.fileName+"_"+this.segmentPos+".json";this.segmentPos+=1,assetLoader.load(r,this.includeLayers.bind(this),function(){this.trigger("data_failed")}.bind(this))},AnimationItem.prototype.loadSegments=function(){this.animationData.segments||(this.timeCompleted=this.totalFrames),this.loadNextSegment()},AnimationItem.prototype.imagesLoaded=function(){this.trigger("loaded_images"),this.checkLoaded()},AnimationItem.prototype.preloadImages=function(){this.imagePreloader.setAssetsPath(this.assetsPath),this.imagePreloader.setPath(this.path),this.imagePreloader.loadAssets(this.animationData.assets,this.imagesLoaded.bind(this))},AnimationItem.prototype.configAnimation=function(t){this.renderer&&(this.animationData=t,this.totalFrames=Math.floor(this.animationData.op-this.animationData.ip),this.renderer.configAnimation(t),t.assets||(t.assets=[]),this.renderer.searchExtraCompositions(t.assets),this.assets=this.animationData.assets,this.frameRate=this.animationData.fr,this.firstFrame=Math.round(this.animationData.ip),this.frameMult=this.animationData.fr/1e3,this.trigger("config_ready"),this.preloadImages(),this.loadSegments(),this.updaFrameModifier(),this.waitForFontsLoaded())},AnimationItem.prototype.waitForFontsLoaded=function(){this.renderer&&(this.renderer.globalData.fontManager.loaded()?this.checkLoaded():setTimeout(this.waitForFontsLoaded.bind(this),20))},AnimationItem.prototype.checkLoaded=function(){this.isLoaded||!this.renderer.globalData.fontManager.loaded()||!this.imagePreloader.loaded()&&"canvas"===this.renderer.rendererType||(this.isLoaded=!0,dataManager.completeData(this.animationData,this.renderer.globalData.fontManager),expressionsPlugin&&expressionsPlugin.initExpressions(this),this.renderer.initItems(),setTimeout(function(){this.trigger("DOMLoaded")}.bind(this),0),this.gotoFrame(),this.autoplay&&this.play())},AnimationItem.prototype.resize=function(){this.renderer.updateContainerSize()},AnimationItem.prototype.setSubframe=function(t){this.subframeEnabled=!!t},AnimationItem.prototype.gotoFrame=function(){this.currentFrame=this.subframeEnabled?this.currentRawFrame:~~this.currentRawFrame,this.timeCompleted!==this.totalFrames&&this.currentFrame>this.timeCompleted&&(this.currentFrame=this.timeCompleted),this.trigger("enterFrame"),this.renderFrame()},AnimationItem.prototype.renderFrame=function(){!1!==this.isLoaded&&this.renderer.renderFrame(this.currentFrame+this.firstFrame)},AnimationItem.prototype.play=function(t){t&&this.name!=t||!0===this.isPaused&&(this.isPaused=!1,this._idle&&(this._idle=!1,this.trigger("_active")))},AnimationItem.prototype.pause=function(t){t&&this.name!=t||!1===this.isPaused&&(this.isPaused=!0,this._idle=!0,this.trigger("_idle"))},AnimationItem.prototype.togglePause=function(t){t&&this.name!=t||(!0===this.isPaused?this.play():this.pause())},AnimationItem.prototype.stop=function(t){t&&this.name!=t||(this.pause(),this.playCount=0,this._completedLoop=!1,this.setCurrentRawFrameValue(0))},AnimationItem.prototype.goToAndStop=function(t,e,r){r&&this.name!=r||(e?this.setCurrentRawFrameValue(t):this.setCurrentRawFrameValue(t*this.frameModifier),this.pause())},AnimationItem.prototype.goToAndPlay=function(t,e,r){this.goToAndStop(t,e,r),this.play()},AnimationItem.prototype.advanceTime=function(t){if(!0!==this.isPaused&&!1!==this.isLoaded){var e=this.currentRawFrame+t*this.frameModifier,r=!1;e>=this.totalFrames-1&&0<this.frameModifier?this.loop&&this.playCount!==this.loop?e>=this.totalFrames?(this.playCount+=1,this.checkSegments(e%this.totalFrames)||(this.setCurrentRawFrameValue(e%this.totalFrames),this._completedLoop=!0,this.trigger("loopComplete"))):this.setCurrentRawFrameValue(e):this.checkSegments(e>this.totalFrames?e%this.totalFrames:0)||(r=!0,e=this.totalFrames-1):e<0?this.checkSegments(e%this.totalFrames)||(!this.loop||this.playCount--<=0&&!0!==this.loop?(r=!0,e=0):(this.setCurrentRawFrameValue(this.totalFrames+e%this.totalFrames),this._completedLoop?this.trigger("loopComplete"):this._completedLoop=!0)):this.setCurrentRawFrameValue(e),r&&(this.setCurrentRawFrameValue(e),this.pause(),this.trigger("complete"))}},AnimationItem.prototype.adjustSegment=function(t,e){this.playCount=0,t[1]<t[0]?(0<this.frameModifier&&(this.playSpeed<0?this.setSpeed(-this.playSpeed):this.setDirection(-1)),this.timeCompleted=this.totalFrames=t[0]-t[1],this.firstFrame=t[1],this.setCurrentRawFrameValue(this.totalFrames-.001-e)):t[1]>t[0]&&(this.frameModifier<0&&(this.playSpeed<0?this.setSpeed(-this.playSpeed):this.setDirection(1)),this.timeCompleted=this.totalFrames=t[1]-t[0],this.firstFrame=t[0],this.setCurrentRawFrameValue(.001+e)),this.trigger("segmentStart")},AnimationItem.prototype.setSegment=function(t,e){var r=-1;this.isPaused&&(this.currentRawFrame+this.firstFrame<t?r=t:this.currentRawFrame+this.firstFrame>e&&(r=e-t)),this.firstFrame=t,this.timeCompleted=this.totalFrames=e-t,-1!==r&&this.goToAndStop(r,!0)},AnimationItem.prototype.playSegments=function(t,e){if(e&&(this.segments.length=0),"object"==typeof t[0]){var r,i=t.length;for(r=0;r<i;r+=1)this.segments.push(t[r])}else this.segments.push(t);this.segments.length&&e&&this.adjustSegment(this.segments.shift(),0),this.isPaused&&this.play()},AnimationItem.prototype.resetSegments=function(t){this.segments.length=0,this.segments.push([this.animationData.ip,this.animationData.op]),t&&this.checkSegments(0)},AnimationItem.prototype.checkSegments=function(t){return!!this.segments.length&&(this.adjustSegment(this.segments.shift(),t),!0)},AnimationItem.prototype.destroy=function(t){t&&this.name!=t||!this.renderer||(this.renderer.destroy(),this.imagePreloader.destroy(),this.trigger("destroy"),this._cbs=null,this.onEnterFrame=this.onLoopComplete=this.onComplete=this.onSegmentStart=this.onDestroy=null,this.renderer=null)},AnimationItem.prototype.setCurrentRawFrameValue=function(t){this.currentRawFrame=t,this.gotoFrame()},AnimationItem.prototype.setSpeed=function(t){this.playSpeed=t,this.updaFrameModifier()},AnimationItem.prototype.setDirection=function(t){this.playDirection=t<0?-1:1,this.updaFrameModifier()},AnimationItem.prototype.updaFrameModifier=function(){this.frameModifier=this.frameMult*this.playSpeed*this.playDirection},AnimationItem.prototype.getPath=function(){return this.path},AnimationItem.prototype.getAssetsPath=function(t){var e="";if(t.e)e=t.p;else if(this.assetsPath){var r=t.p;-1!==r.indexOf("images/")&&(r=r.split("/")[1]),e=this.assetsPath+r}else e=this.path,e+=t.u?t.u:"",e+=t.p;return e},AnimationItem.prototype.getAssetData=function(t){for(var e=0,r=this.assets.length;e<r;){if(t==this.assets[e].id)return this.assets[e];e+=1}},AnimationItem.prototype.hide=function(){this.renderer.hide()},AnimationItem.prototype.show=function(){this.renderer.show()},AnimationItem.prototype.getDuration=function(t){return t?this.totalFrames:this.totalFrames/this.frameRate},AnimationItem.prototype.trigger=function(t){if(this._cbs&&this._cbs[t])switch(t){case"enterFrame":this.triggerEvent(t,new BMEnterFrameEvent(t,this.currentFrame,this.totalFrames,this.frameModifier));break;case"loopComplete":this.triggerEvent(t,new BMCompleteLoopEvent(t,this.loop,this.playCount,this.frameMult));break;case"complete":this.triggerEvent(t,new BMCompleteEvent(t,this.frameMult));break;case"segmentStart":this.triggerEvent(t,new BMSegmentStartEvent(t,this.firstFrame,this.totalFrames));break;case"destroy":this.triggerEvent(t,new BMDestroyEvent(t,this));break;default:this.triggerEvent(t)}"enterFrame"===t&&this.onEnterFrame&&this.onEnterFrame.call(this,new BMEnterFrameEvent(t,this.currentFrame,this.totalFrames,this.frameMult)),"loopComplete"===t&&this.onLoopComplete&&this.onLoopComplete.call(this,new BMCompleteLoopEvent(t,this.loop,this.playCount,this.frameMult)),"complete"===t&&this.onComplete&&this.onComplete.call(this,new BMCompleteEvent(t,this.frameMult)),"segmentStart"===t&&this.onSegmentStart&&this.onSegmentStart.call(this,new BMSegmentStartEvent(t,this.firstFrame,this.totalFrames)),"destroy"===t&&this.onDestroy&&this.onDestroy.call(this,new BMDestroyEvent(t,this))},AnimationItem.prototype.setParams=function(t){t.context&&(this.context=t.context);var e=t.animType?t.animType:t.renderer?t.renderer:"svg";switch(e){case"canvas":this.renderer=new CanvasRenderer(this,t.rendererSettings);break;default:throw new Error("Only canvas renderer is supported when using worker.")}if(this.renderer.setProjectInterface(this.projectInterface),this.animType=e,""===t.loop||null===t.loop||(!1===t.loop?this.loop=!1:!0===t.loop?this.loop=!0:this.loop=parseInt(t.loop)),this.autoplay=!("autoplay"in t)||t.autoplay,this.name=t.name?t.name:"",this.autoloadSegments=!t.hasOwnProperty("autoloadSegments")||t.autoloadSegments,this.assetsPath=null,t.animationData)this.configAnimation(t.animationData);else if(t.path)throw new Error("Canvas worker renderer cannot load animation from url")},AnimationItem.prototype.setData=function(t,e){throw new Error("Cannot set data on wrapper for canvas worker renderer")},AnimationItem.prototype.includeLayers=function(t){t.op>this.animationData.op&&(this.animationData.op=t.op,this.totalFrames=Math.floor(t.op-this.animationData.ip));var e,r,i=this.animationData.layers,s=i.length,a=t.layers,n=a.length;for(r=0;r<n;r+=1)for(e=0;e<s;){if(i[e].id==a[r].id){i[e]=a[r];break}e+=1}this.animationData.__complete=!1,dataManager.completeData(this.animationData,this.renderer.globalData.fontManager),this.renderer.includeLayers(t.layers),expressionsPlugin&&expressionsPlugin.initExpressions(this),this.loadNextSegment()},AnimationItem.prototype.loadNextSegment=function(){var t=this.animationData.segments;if(t&&0!==t.length&&this.autoloadSegments)throw new Error("Cannot load multiple segments in worker.");this.timeCompleted=this.totalFrames},AnimationItem.prototype.loadSegments=function(){this.animationData.segments||(this.timeCompleted=this.totalFrames),this.loadNextSegment()},AnimationItem.prototype.imagesLoaded=null,AnimationItem.prototype.preloadImages=null,AnimationItem.prototype.configAnimation=function(t){this.renderer&&(this.animationData=t,this.totalFrames=Math.floor(this.animationData.op-this.animationData.ip),this.renderer.configAnimation(t),t.assets||(t.assets=[]),this.renderer.searchExtraCompositions(t.assets),this.assets=this.animationData.assets,this.frameRate=this.animationData.fr,this.firstFrame=Math.round(this.animationData.ip),this.frameMult=this.animationData.fr/1e3,this.loadSegments(),this.updaFrameModifier(),this.checkLoaded())},AnimationItem.prototype.waitForFontsLoaded=null,AnimationItem.prototype.checkLoaded=function(){this.isLoaded||(this.isLoaded=!0,dataManager.completeData(this.animationData,null),expressionsPlugin&&expressionsPlugin.initExpressions(this),this.renderer.initItems(),this.gotoFrame())},AnimationItem.prototype.destroy=function(t){t&&this.name!=t||!this.renderer||(this.renderer.destroy(),this._cbs=null,this.onEnterFrame=this.onLoopComplete=this.onComplete=this.onSegmentStart=this.onDestroy=null,this.renderer=null)},AnimationItem.prototype.getPath=null;var Expressions=(xN={},xN.initExpressions=function(t){var e=0,r=[];t.renderer.compInterface=CompExpressionInterface(t.renderer),t.renderer.globalData.projectInterface.registerComposition(t.renderer),t.renderer.globalData.pushExpression=function(){e+=1},t.renderer.globalData.popExpression=function(){0==(e-=1)&&function(){var t,e=r.length;for(t=0;t<e;t+=1)r[t].release();r.length=0}()},t.renderer.globalData.registerExpressionProperty=function(t){-1===r.indexOf(t)&&r.push(t)}},xN),xN;expressionsPlugin=Expressions;var ExpressionManager=function(){var ob={},Math=BMMath,window=null,document=null;function $bm_isInstanceOfArray(t){return t.constructor===Array||t.constructor===Float32Array}function isNumerable(t,e){return"number"===t||"boolean"===t||"string"===t||e instanceof Number}function $bm_neg(t){var e=typeof t;if("number"==e||"boolean"==e||t instanceof Number)return-t;if($bm_isInstanceOfArray(t)){var r,i=t.length,s=[];for(r=0;r<i;r+=1)s[r]=-t[r];return s}return t.propType?t.v:void 0}var easeInBez=BezierFactory.getBezierEasing(.333,0,.833,.833,"easeIn").get,easeOutBez=BezierFactory.getBezierEasing(.167,.167,.667,1,"easeOut").get,easeInOutBez=BezierFactory.getBezierEasing(.33,0,.667,1,"easeInOut").get;function sum(t,e){var r=typeof t,i=typeof e;if("string"==r||"string"==i)return t+e;if(isNumerable(r,t)&&isNumerable(i,e))return t+e;if($bm_isInstanceOfArray(t)&&isNumerable(i,e))return(t=t.slice(0))[0]=t[0]+e,t;if(isNumerable(r,t)&&$bm_isInstanceOfArray(e))return(e=e.slice(0))[0]=t+e[0],e;if($bm_isInstanceOfArray(t)&&$bm_isInstanceOfArray(e)){for(var s=0,a=t.length,n=e.length,o=[];s<a||s<n;)("number"==typeof t[s]||t[s]instanceof Number)&&("number"==typeof e[s]||e[s]instanceof Number)?o[s]=t[s]+e[s]:o[s]=void 0===e[s]?t[s]:t[s]||e[s],s+=1;return o}return 0}var add=sum;function sub(t,e){var r=typeof t,i=typeof e;if(isNumerable(r,t)&&isNumerable(i,e))return"string"==r&&(t=parseInt(t)),"string"==i&&(e=parseInt(e)),t-e;if($bm_isInstanceOfArray(t)&&isNumerable(i,e))return(t=t.slice(0))[0]=t[0]-e,t;if(isNumerable(r,t)&&$bm_isInstanceOfArray(e))return(e=e.slice(0))[0]=t-e[0],e;if($bm_isInstanceOfArray(t)&&$bm_isInstanceOfArray(e)){for(var s=0,a=t.length,n=e.length,o=[];s<a||s<n;)("number"==typeof t[s]||t[s]instanceof Number)&&("number"==typeof e[s]||e[s]instanceof Number)?o[s]=t[s]-e[s]:o[s]=void 0===e[s]?t[s]:t[s]||e[s],s+=1;return o}return 0}function mul(t,e){var r,i,s,a=typeof t,n=typeof e;if(isNumerable(a,t)&&isNumerable(n,e))return t*e;if($bm_isInstanceOfArray(t)&&isNumerable(n,e)){for(s=t.length,r=createTypedArray("float32",s),i=0;i<s;i+=1)r[i]=t[i]*e;return r}if(isNumerable(a,t)&&$bm_isInstanceOfArray(e)){for(s=e.length,r=createTypedArray("float32",s),i=0;i<s;i+=1)r[i]=t*e[i];return r}return 0}function div(t,e){var r,i,s,a=typeof t,n=typeof e;if(isNumerable(a,t)&&isNumerable(n,e))return t/e;if($bm_isInstanceOfArray(t)&&isNumerable(n,e)){for(s=t.length,r=createTypedArray("float32",s),i=0;i<s;i+=1)r[i]=t[i]/e;return r}if(isNumerable(a,t)&&$bm_isInstanceOfArray(e)){for(s=e.length,r=createTypedArray("float32",s),i=0;i<s;i+=1)r[i]=t/e[i];return r}return 0}function mod(t,e){return"string"==typeof t&&(t=parseInt(t)),"string"==typeof e&&(e=parseInt(e)),t%e}var $bm_sum=sum,$bm_sub=sub,$bm_mul=mul,$bm_div=div,$bm_mod=mod;function clamp(t,e,r){if(r<e){var i=r;r=e,e=i}return Math.min(Math.max(t,e),r)}function radiansToDegrees(t){return t/degToRads}var radians_to_degrees=radiansToDegrees;function degreesToRadians(t){return t*degToRads}var degrees_to_radians=radiansToDegrees,helperLengthArray=[0,0,0,0,0,0];function length(t,e){if("number"==typeof t||t instanceof Number)return e=e||0,Math.abs(t-e);e||(e=helperLengthArray);var r,i=Math.min(t.length,e.length),s=0;for(r=0;r<i;r+=1)s+=Math.pow(e[r]-t[r],2);return Math.sqrt(s)}function normalize(t){return div(t,length(t))}function rgbToHsl(t){var e,r,i=t[0],s=t[1],a=t[2],n=Math.max(i,s,a),o=Math.min(i,s,a),h=(n+o)/2;if(n==o)e=r=0;else{var p=n-o;switch(r=.5<h?p/(2-n-o):p/(n+o),n){case i:e=(s-a)/p+(s<a?6:0);break;case s:e=(a-i)/p+2;break;case a:e=(i-s)/p+4}e/=6}return[e,r,h,t[3]]}function hue2rgb(t,e,r){return r<0&&(r+=1),1<r&&(r-=1),r<1/6?t+6*(e-t)*r:r<.5?e:r<2/3?t+(e-t)*(2/3-r)*6:t}function hslToRgb(t){var e,r,i,s=t[0],a=t[1],n=t[2];if(0===a)e=r=i=n;else{var o=n<.5?n*(1+a):n+a-n*a,h=2*n-o;e=hue2rgb(h,o,s+1/3),r=hue2rgb(h,o,s),i=hue2rgb(h,o,s-1/3)}return[e,r,i,t[3]]}function linear(t,e,r,i,s){if(void 0!==i&&void 0!==s||(i=e,s=r,e=0,r=1),r<e){var a=r;r=e,e=a}if(t<=e)return i;if(r<=t)return s;var n=r===e?0:(t-e)/(r-e);if(!i.length)return i+(s-i)*n;var o,h=i.length,p=createTypedArray("float32",h);for(o=0;o<h;o+=1)p[o]=i[o]+(s[o]-i[o])*n;return p}function random(t,e){if(void 0===e&&(void 0===t?(t=0,e=1):(e=t,t=void 0)),e.length){var r,i=e.length;t||(t=createTypedArray("float32",i));var s=createTypedArray("float32",i),a=BMMath.random();for(r=0;r<i;r+=1)s[r]=t[r]+a*(e[r]-t[r]);return s}return void 0===t&&(t=0),t+BMMath.random()*(e-t)}function createPath(t,e,r,i){var s,a=t.length,n=shape_pool.newElement();n.setPathData(!!i,a);var o,h,p=[0,0];for(s=0;s<a;s+=1)o=e&&e[s]?e[s]:p,h=r&&r[s]?r[s]:p,n.setTripleAt(t[s][0],t[s][1],h[0]+t[s][0],h[1]+t[s][1],o[0]+t[s][0],o[1]+t[s][1],s,!0);return n}function initiateExpression(elem,data,property){var val=data.x,needsVelocity=/velocity(?![\w\d])/.test(val),_needsRandom=-1!==val.indexOf("random"),elemType=elem.data.ty,transform,$bm_transform,content,effect,thisProperty=property;thisProperty.valueAtTime=thisProperty.getValueAtTime,Object.defineProperty(thisProperty,"value",{get:function(){return thisProperty.v}}),elem.comp.frameDuration=1/elem.comp.globalData.frameRate,elem.comp.displayStartTime=0;var inPoint=elem.data.ip/elem.comp.globalData.frameRate,outPoint=elem.data.op/elem.comp.globalData.frameRate,width=elem.data.sw?elem.data.sw:0,height=elem.data.sh?elem.data.sh:0,name=elem.data.nm,loopIn,loop_in,loopOut,loop_out,smooth,toWorld,fromWorld,fromComp,toComp,fromCompToSurface,position,rotation,anchorPoint,scale,thisLayer,thisComp,mask,valueAtTime,velocityAtTime,__expression_functions=[],scoped_bm_rt;if(data.xf){var i,len=data.xf.length;for(i=0;i<len;i+=1)__expression_functions[i]=eval("(function(){ return "+data.xf[i]+"}())")}var expression_function=eval("[function _expression_function(){"+val+";scoped_bm_rt=$bm_rt}]")[0],numKeys=property.kf?data.k.length:0,active=!this.data||!0!==this.data.hd,wiggle=function(t,e){var r,i,s=this.pv.length?this.pv.length:1,a=createTypedArray("float32",s);var n=Math.floor(5*time);for(i=r=0;r<n;){for(i=0;i<s;i+=1)a[i]+=-e+2*e*BMMath.random();r+=1}var o=5*time,h=o-Math.floor(o),p=createTypedArray("float32",s);if(1<s){for(i=0;i<s;i+=1)p[i]=this.pv[i]+a[i]+(-e+2*e*BMMath.random())*h;return p}return this.pv+a[0]+(-e+2*e*BMMath.random())*h}.bind(this);function loopInDuration(t,e){return loopIn(t,e,!0)}function loopOutDuration(t,e){return loopOut(t,e,!0)}thisProperty.loopIn&&(loopIn=thisProperty.loopIn.bind(thisProperty),loop_in=loopIn),thisProperty.loopOut&&(loopOut=thisProperty.loopOut.bind(thisProperty),loop_out=loopOut),thisProperty.smooth&&(smooth=thisProperty.smooth.bind(thisProperty)),this.getValueAtTime&&(valueAtTime=this.getValueAtTime.bind(this)),this.getVelocityAtTime&&(velocityAtTime=this.getVelocityAtTime.bind(this));var comp=elem.comp.globalData.projectInterface.bind(elem.comp.globalData.projectInterface),time,velocity,value,text,textIndex,textTotal,selectorValue;function lookAt(t,e){var r=[e[0]-t[0],e[1]-t[1],e[2]-t[2]],i=Math.atan2(r[0],Math.sqrt(r[1]*r[1]+r[2]*r[2]))/degToRads;return[-Math.atan2(r[1],r[2])/degToRads,i,0]}function easeOut(t,e,r,i,s){return applyEase(easeOutBez,t,e,r,i,s)}function easeIn(t,e,r,i,s){return applyEase(easeInBez,t,e,r,i,s)}function ease(t,e,r,i,s){return applyEase(easeInOutBez,t,e,r,i,s)}function applyEase(t,e,r,i,s,a){void 0===s?(s=r,a=i):e=(e-r)/(i-r);var n=t(e=1<e?1:e<0?0:e);if($bm_isInstanceOfArray(s)){var o,h=s.length,p=createTypedArray("float32",h);for(o=0;o<h;o+=1)p[o]=(a[o]-s[o])*n+s[o];return p}return(a-s)*n+s}function nearestKey(t){var e,r,i,s=data.k.length;if(data.k.length&&"number"!=typeof data.k[0])if(r=-1,(t*=elem.comp.globalData.frameRate)<data.k[0].t)r=1,i=data.k[0].t;else{for(e=0;e<s-1;e+=1){if(t===data.k[e].t){r=e+1,i=data.k[e].t;break}if(t>data.k[e].t&&t<data.k[e+1].t){i=t-data.k[e].t>data.k[e+1].t-t?(r=e+2,data.k[e+1].t):(r=e+1,data.k[e].t);break}}-1===r&&(r=e+1,i=data.k[e].t)}else i=r=0;var a={};return a.index=r,a.time=i/elem.comp.globalData.frameRate,a}function key(t){var e,r,i,s;if(!data.k.length||"number"==typeof data.k[0])throw new Error("The property has no keyframe at index "+t);for(t-=1,e={time:data.k[t].t/elem.comp.globalData.frameRate,value:[]},i=(s=t!==data.k.length-1||data.k[t].h?data.k[t].s:data.k[t].s||0===data.k[t].s?data.k[t-1].s:data.k[t].e).length,r=0;r<i;r+=1)e[r]=s[r],e.value[r]=s[r];return e}function framesToTime(t,e){return e||(e=elem.comp.globalData.frameRate),t/e}function timeToFrames(t,e){return t||0===t||(t=time),e||(e=elem.comp.globalData.frameRate),t*e}function seedRandom(t){BMMath.seedrandom(randSeed+t)}function sourceRectAtTime(){return elem.sourceRectAtTime()}function substring(t,e){return"string"==typeof value?void 0===e?value.substring(t):value.substring(t,e):""}function substr(t,e){return"string"==typeof value?void 0===e?value.substr(t):value.substr(t,e):""}var index=elem.data.ind,hasParent=!(!elem.hierarchy||!elem.hierarchy.length),parent,randSeed=Math.floor(1e6*Math.random()),globalData=elem.globalData;function executeExpression(t){return value=t,_needsRandom&&seedRandom(randSeed),this.frameExpressionId===elem.globalData.frameId&&"textSelector"!==this.propType?value:("textSelector"===this.propType&&(textIndex=this.textIndex,textTotal=this.textTotal,selectorValue=this.selectorValue),thisLayer||(text=elem.layerInterface.text,thisLayer=elem.layerInterface,thisComp=elem.comp.compInterface,toWorld=thisLayer.toWorld.bind(thisLayer),fromWorld=thisLayer.fromWorld.bind(thisLayer),fromComp=thisLayer.fromComp.bind(thisLayer),toComp=thisLayer.toComp.bind(thisLayer),mask=thisLayer.mask?thisLayer.mask.bind(thisLayer):null,fromCompToSurface=fromComp),transform||(transform=elem.layerInterface("ADBE Transform Group"),($bm_transform=transform)&&(anchorPoint=transform.anchorPoint)),4!==elemType||content||(content=thisLayer("ADBE Root Vectors Group")),effect||(effect=thisLayer(4)),(hasParent=!(!elem.hierarchy||!elem.hierarchy.length))&&!parent&&(parent=elem.hierarchy[0].layerInterface),time=this.comp.renderedFrame/this.comp.globalData.frameRate,needsVelocity&&(velocity=velocityAtTime(time)),expression_function(),this.frameExpressionId=elem.globalData.frameId,"shape"===scoped_bm_rt.propType&&(scoped_bm_rt=scoped_bm_rt.v),scoped_bm_rt)}return executeExpression}return ob.initiateExpression=initiateExpression,ob}(),expressionHelpers={searchExpressions:function(t,e,r){e.x&&(r.k=!0,r.x=!0,r.initiateExpression=ExpressionManager.initiateExpression,r.effectsSequence.push(r.initiateExpression(t,e,r).bind(r)))},getSpeedAtTime:function(t){var e=this.getValueAtTime(t),r=this.getValueAtTime(t+-.01),i=0;if(e.length){var s;for(s=0;s<e.length;s+=1)i+=Math.pow(r[s]-e[s],2);i=100*Math.sqrt(i)}else i=0;return i},getVelocityAtTime:function(t){if(void 0!==this.vel)return this.vel;var e,r,i=this.getValueAtTime(t),s=this.getValueAtTime(t+-.001);if(i.length)for(e=createTypedArray("float32",i.length),r=0;r<i.length;r+=1)e[r]=(s[r]-i[r])/-.001;else e=(s-i)/-.001;return e},getValueAtTime:function(t){return t*=this.elem.globalData.frameRate,(t-=this.offsetTime)!==this._cachingAtTime.lastFrame&&(this._cachingAtTime.lastIndex=this._cachingAtTime.lastFrame<t?this._cachingAtTime.lastIndex:0,this._cachingAtTime.value=this.interpolateValue(t,this._cachingAtTime),this._cachingAtTime.lastFrame=t),this._cachingAtTime.value},getStaticValueAtTime:function(){return this.pv},setGroupProperty:function(t){this.propertyGroup=t}};!function(){function o(t,e,r){if(!this.k||!this.keyframes)return this.pv;t=t?t.toLowerCase():"";var i,s,a,n,o,h=this.comp.renderedFrame,p=this.keyframes,l=p[p.length-1].t;if(h<=l)return this.pv;if(r?s=l-(i=e?Math.abs(l-elem.comp.globalData.frameRate*e):Math.max(0,l-this.elem.data.ip)):((!e||e>p.length-1)&&(e=p.length-1),i=l-(s=p[p.length-1-e].t)),"pingpong"===t){if(Math.floor((h-s)/i)%2!=0)return this.getValueAtTime((i-(h-s)%i+s)/this.comp.globalData.frameRate,0)}else{if("offset"===t){var m=this.getValueAtTime(s/this.comp.globalData.frameRate,0),f=this.getValueAtTime(l/this.comp.globalData.frameRate,0),c=this.getValueAtTime(((h-s)%i+s)/this.comp.globalData.frameRate,0),d=Math.floor((h-s)/i);if(this.pv.length){for(n=(o=new Array(m.length)).length,a=0;a<n;a+=1)o[a]=(f[a]-m[a])*d+c[a];return o}return(f-m)*d+c}if("continue"===t){var u=this.getValueAtTime(l/this.comp.globalData.frameRate,0),y=this.getValueAtTime((l-.001)/this.comp.globalData.frameRate,0);if(this.pv.length){for(n=(o=new Array(u.length)).length,a=0;a<n;a+=1)o[a]=u[a]+(u[a]-y[a])*((h-l)/this.comp.globalData.frameRate)/5e-4;return o}return u+(h-l)/.001*(u-y)}}return this.getValueAtTime(((h-s)%i+s)/this.comp.globalData.frameRate,0)}function h(t,e,r){if(!this.k)return this.pv;t=t?t.toLowerCase():"";var i,s,a,n,o,h=this.comp.renderedFrame,p=this.keyframes,l=p[0].t;if(l<=h)return this.pv;if(r?s=l+(i=e?Math.abs(elem.comp.globalData.frameRate*e):Math.max(0,this.elem.data.op-l)):((!e||e>p.length-1)&&(e=p.length-1),i=(s=p[e].t)-l),"pingpong"===t){if(Math.floor((l-h)/i)%2==0)return this.getValueAtTime(((l-h)%i+l)/this.comp.globalData.frameRate,0)}else{if("offset"===t){var m=this.getValueAtTime(l/this.comp.globalData.frameRate,0),f=this.getValueAtTime(s/this.comp.globalData.frameRate,0),c=this.getValueAtTime((i-(l-h)%i+l)/this.comp.globalData.frameRate,0),d=Math.floor((l-h)/i)+1;if(this.pv.length){for(n=(o=new Array(m.length)).length,a=0;a<n;a+=1)o[a]=c[a]-(f[a]-m[a])*d;return o}return c-(f-m)*d}if("continue"===t){var u=this.getValueAtTime(l/this.comp.globalData.frameRate,0),y=this.getValueAtTime((l+.001)/this.comp.globalData.frameRate,0);if(this.pv.length){for(n=(o=new Array(u.length)).length,a=0;a<n;a+=1)o[a]=u[a]+(u[a]-y[a])*(l-h)/.001;return o}return u+(u-y)*(l-h)/.001}}return this.getValueAtTime((i-(l-h)%i+l)/this.comp.globalData.frameRate,0)}function p(t,e){if(!this.k)return this.pv;if(t=.5*(t||.4),(e=Math.floor(e||5))<=1)return this.pv;var r,i,s=this.comp.renderedFrame/this.comp.globalData.frameRate,a=s-t,n=1<e?(s+t-a)/(e-1):1,o=0,h=0;for(r=this.pv.length?createTypedArray("float32",this.pv.length):0;o<e;){if(i=this.getValueAtTime(a+o*n),this.pv.length)for(h=0;h<this.pv.length;h+=1)r[h]+=i[h];else r+=i;o+=1}if(this.pv.length)for(h=0;h<this.pv.length;h+=1)r[h]/=e;else r/=e;return r}var s=TransformPropertyFactory.getTransformProperty;TransformPropertyFactory.getTransformProperty=function(t,e,r){var i=s(t,e,r);return i.dynamicProperties.length?i.getValueAtTime=function(t){console.warn("Transform at time not supported")}.bind(i):i.getValueAtTime=function(t){}.bind(i),i.setGroupProperty=expressionHelpers.setGroupProperty,i};var l=PropertyFactory.getProp;PropertyFactory.getProp=function(t,e,r,i,s){var a=l(t,e,r,i,s);a.kf?a.getValueAtTime=expressionHelpers.getValueAtTime.bind(a):a.getValueAtTime=expressionHelpers.getStaticValueAtTime.bind(a),a.setGroupProperty=expressionHelpers.setGroupProperty,a.loopOut=o,a.loopIn=h,a.smooth=p,a.getVelocityAtTime=expressionHelpers.getVelocityAtTime.bind(a),a.getSpeedAtTime=expressionHelpers.getSpeedAtTime.bind(a),a.numKeys=1===e.a?e.k.length:0,a.propertyIndex=e.ix;var n=0;return 0!==r&&(n=createTypedArray("float32",1===e.a?e.k[0].s.length:e.k.length)),a._cachingAtTime={lastFrame:initialDefaultFrame,lastIndex:0,value:n},expressionHelpers.searchExpressions(t,e,a),a.k&&s.addDynamicProperty(a),a};var t=ShapePropertyFactory.getConstructorFunction(),e=ShapePropertyFactory.getKeyframedConstructorFunction();function r(){}r.prototype={vertices:function(t,e){this.k&&this.getValue();var r=this.v;void 0!==e&&(r=this.getValueAtTime(e,0));var i,s=r._length,a=r[t],n=r.v,o=createSizedArray(s);for(i=0;i<s;i+=1)o[i]="i"===t||"o"===t?[a[i][0]-n[i][0],a[i][1]-n[i][1]]:[a[i][0],a[i][1]];return o},points:function(t){return this.vertices("v",t)},inTangents:function(t){return this.vertices("i",t)},outTangents:function(t){return this.vertices("o",t)},isClosed:function(){return this.v.c},pointOnPath:function(t,e){var r=this.v;void 0!==e&&(r=this.getValueAtTime(e,0)),this._segmentsLength||(this._segmentsLength=bez.getSegmentsLength(r));for(var i,s=this._segmentsLength,a=s.lengths,n=s.totalLength*t,o=0,h=a.length,p=0;o<h;){if(p+a[o].addedLength>n){var l=o,m=r.c&&o===h-1?0:o+1,f=(n-p)/a[o].addedLength;i=bez.getPointInSegment(r.v[l],r.v[m],r.o[l],r.i[m],f,a[o]);break}p+=a[o].addedLength,o+=1}return i||(i=r.c?[r.v[0][0],r.v[0][1]]:[r.v[r._length-1][0],r.v[r._length-1][1]]),i},vectorOnPath:function(t,e,r){t=1==t?this.v.c?0:.999:t;var i=this.pointOnPath(t,e),s=this.pointOnPath(t+.001,e),a=s[0]-i[0],n=s[1]-i[1],o=Math.sqrt(Math.pow(a,2)+Math.pow(n,2));return"tangent"===r?[a/o,n/o]:[-n/o,a/o]},tangentOnPath:function(t,e){return this.vectorOnPath(t,e,"tangent")},normalOnPath:function(t,e){return this.vectorOnPath(t,e,"normal")},setGroupProperty:expressionHelpers.setGroupProperty,getValueAtTime:expressionHelpers.getStaticValueAtTime},extendPrototype([r],t),extendPrototype([r],e),e.prototype.getValueAtTime=function(t){return this._cachingAtTime||(this._cachingAtTime={shapeValue:shape_pool.clone(this.pv),lastIndex:0,lastTime:initialDefaultFrame}),t*=this.elem.globalData.frameRate,(t-=this.offsetTime)!==this._cachingAtTime.lastTime&&(this._cachingAtTime.lastIndex=this._cachingAtTime.lastTime<t?this._caching.lastIndex:0,this._cachingAtTime.lastTime=t,this.interpolateShape(t,this._cachingAtTime.shapeValue,this._cachingAtTime)),this._cachingAtTime.shapeValue},e.prototype.initiateExpression=ExpressionManager.initiateExpression;var n=ShapePropertyFactory.getShapeProp;ShapePropertyFactory.getShapeProp=function(t,e,r,i,s){var a=n(t,e,r,i,s);return a.propertyIndex=e.ix,a.lock=!1,3===r?expressionHelpers.searchExpressions(t,e.pt,a):4===r&&expressionHelpers.searchExpressions(t,e.ks,a),a.k&&t.addDynamicProperty(a),a}}(),TextProperty.prototype.getExpressionValue=function(t,e){var r=this.calculateExpression(e);if(t.t===r)return t;var i={};return this.copyData(i,t),i.t=r.toString(),i.__complete=!1,i},TextProperty.prototype.searchProperty=function(){var t=this.searchKeyframes(),e=this.searchExpressions();return this.kf=t||e,this.kf},TextProperty.prototype.searchExpressions=function(){if(this.data.d.x)return this.calculateExpression=ExpressionManager.initiateExpression.bind(this)(this.elem,this.data.d,this),this.addEffect(this.getExpressionValue.bind(this)),!0};var ShapeExpressionInterface=function(t,e,r){var i;function s(t){if("number"==typeof t)return i[t-1];for(var e=0,r=i.length;e<r;){if(i[e]._name===t)return i[e];e+=1}}return s.propertyGroup=r,i=DT(t,e,s),s.numProperties=i.length,s};function DT(t,e,r){var i,s=[],a=t?t.length:0;for(i=0;i<a;i+=1)"gr"==t[i].ty?s.push(FT(t[i],e[i],r)):"fl"==t[i].ty?s.push(GT(t[i],e[i],r)):"st"==t[i].ty?s.push(HT(t[i],e[i],r)):"tm"==t[i].ty?s.push(IT(t[i],e[i],r)):"tr"==t[i].ty||("el"==t[i].ty?s.push(KT(t[i],e[i],r)):"sr"==t[i].ty?s.push(LT(t[i],e[i],r)):"sh"==t[i].ty?s.push(PT(t[i],e[i],r)):"rc"==t[i].ty?s.push(MT(t[i],e[i],r)):"rd"==t[i].ty?s.push(NT(t[i],e[i],r)):"rp"==t[i].ty&&s.push(OT(t[i],e[i],r)));return s}function FT(t,e,r){var i=function(t){switch(t){case"ADBE Vectors Group":case"Contents":case 2:return i.content;default:return i.transform}};i.propertyGroup=function(t){return 1===t?i:r(t-1)};var s=function(t,e,r){function i(t){for(var e=0,r=s.length;e<r;){if(s[e]._name===t||s[e].mn===t||s[e].propertyIndex===t||s[e].ix===t||s[e].ind===t)return s[e];e+=1}if("number"==typeof t)return s[t-1]}var s;return i.propertyGroup=function(t){return 1===t?i:r(t-1)},s=DT(t.it,e.it,i.propertyGroup),i.numProperties=s.length,i.propertyIndex=t.cix,i._name=t.nm,i}(t,e,i.propertyGroup),a=function(e,t,r){function i(t){return 1==t?s:r(--t)}t.transform.mProps.o.setGroupProperty(i),t.transform.mProps.p.setGroupProperty(i),t.transform.mProps.a.setGroupProperty(i),t.transform.mProps.s.setGroupProperty(i),t.transform.mProps.r.setGroupProperty(i),t.transform.mProps.sk&&(t.transform.mProps.sk.setGroupProperty(i),t.transform.mProps.sa.setGroupProperty(i));function s(t){return e.a.ix===t||"Anchor Point"===t?s.anchorPoint:e.o.ix===t||"Opacity"===t?s.opacity:e.p.ix===t||"Position"===t?s.position:e.r.ix===t||"Rotation"===t||"ADBE Vector Rotation"===t?s.rotation:e.s.ix===t||"Scale"===t?s.scale:e.sk&&e.sk.ix===t||"Skew"===t?s.skew:e.sa&&e.sa.ix===t||"Skew Axis"===t?s.skewAxis:void 0}return t.transform.op.setGroupProperty(i),Object.defineProperties(s,{opacity:{get:ExpressionPropertyInterface(t.transform.mProps.o)},position:{get:ExpressionPropertyInterface(t.transform.mProps.p)},anchorPoint:{get:ExpressionPropertyInterface(t.transform.mProps.a)},scale:{get:ExpressionPropertyInterface(t.transform.mProps.s)},rotation:{get:ExpressionPropertyInterface(t.transform.mProps.r)},skew:{get:ExpressionPropertyInterface(t.transform.mProps.sk)},skewAxis:{get:ExpressionPropertyInterface(t.transform.mProps.sa)},_name:{value:e.nm}}),s.ty="tr",s.mn=e.mn,s.propertyGroup=r,s}(t.it[t.it.length-1],e.it[e.it.length-1],i.propertyGroup);return i.content=s,i.transform=a,Object.defineProperty(i,"_name",{get:function(){return t.nm}}),i.numProperties=t.np,i.propertyIndex=t.ix,i.nm=t.nm,i.mn=t.mn,i}function GT(t,e,r){function i(t){return"Color"===t||"color"===t?i.color:"Opacity"===t||"opacity"===t?i.opacity:void 0}return Object.defineProperties(i,{color:{get:ExpressionPropertyInterface(e.c)},opacity:{get:ExpressionPropertyInterface(e.o)},_name:{value:t.nm},mn:{value:t.mn}}),e.c.setGroupProperty(r),e.o.setGroupProperty(r),i}function HT(t,e,r){function i(t){return 1===t?ob:r(t-1)}function s(t){return 1===t?h:i(t-1)}var a,n,o=t.d?t.d.length:0,h={};for(a=0;a<o;a+=1)n=a,Object.defineProperty(h,t.d[n].nm,{get:ExpressionPropertyInterface(e.d.dataProps[n].p)}),e.d.dataProps[a].p.setGroupProperty(s);function p(t){return"Color"===t||"color"===t?p.color:"Opacity"===t||"opacity"===t?p.opacity:"Stroke Width"===t||"stroke width"===t?p.strokeWidth:void 0}return Object.defineProperties(p,{color:{get:ExpressionPropertyInterface(e.c)},opacity:{get:ExpressionPropertyInterface(e.o)},strokeWidth:{get:ExpressionPropertyInterface(e.w)},dash:{get:function(){return h}},_name:{value:t.nm},mn:{value:t.mn}}),e.c.setGroupProperty(i),e.o.setGroupProperty(i),e.w.setGroupProperty(i),p}function IT(e,t,r){function i(t){return 1==t?s:r(--t)}function s(t){return t===e.e.ix||"End"===t||"end"===t?s.end:t===e.s.ix?s.start:t===e.o.ix?s.offset:void 0}return s.propertyIndex=e.ix,t.s.setGroupProperty(i),t.e.setGroupProperty(i),t.o.setGroupProperty(i),s.propertyIndex=e.ix,s.propertyGroup=r,Object.defineProperties(s,{start:{get:ExpressionPropertyInterface(t.s)},end:{get:ExpressionPropertyInterface(t.e)},offset:{get:ExpressionPropertyInterface(t.o)},_name:{value:e.nm}}),s.mn=e.mn,s}function KT(e,t,r){function i(t){return 1==t?a:r(--t)}a.propertyIndex=e.ix;var s="tm"===t.sh.ty?t.sh.prop:t.sh;function a(t){return e.p.ix===t?a.position:e.s.ix===t?a.size:void 0}return s.s.setGroupProperty(i),s.p.setGroupProperty(i),Object.defineProperties(a,{size:{get:ExpressionPropertyInterface(s.s)},position:{get:ExpressionPropertyInterface(s.p)},_name:{value:e.nm}}),a.mn=e.mn,a}function LT(e,t,r){function i(t){return 1==t?a:r(--t)}var s="tm"===t.sh.ty?t.sh.prop:t.sh;function a(t){return e.p.ix===t?a.position:e.r.ix===t?a.rotation:e.pt.ix===t?a.points:e.or.ix===t||"ADBE Vector Star Outer Radius"===t?a.outerRadius:e.os.ix===t?a.outerRoundness:!e.ir||e.ir.ix!==t&&"ADBE Vector Star Inner Radius"!==t?e.is&&e.is.ix===t?a.innerRoundness:void 0:a.innerRadius}return a.propertyIndex=e.ix,s.or.setGroupProperty(i),s.os.setGroupProperty(i),s.pt.setGroupProperty(i),s.p.setGroupProperty(i),s.r.setGroupProperty(i),e.ir&&(s.ir.setGroupProperty(i),s.is.setGroupProperty(i)),Object.defineProperties(a,{position:{get:ExpressionPropertyInterface(s.p)},rotation:{get:ExpressionPropertyInterface(s.r)},points:{get:ExpressionPropertyInterface(s.pt)},outerRadius:{get:ExpressionPropertyInterface(s.or)},outerRoundness:{get:ExpressionPropertyInterface(s.os)},innerRadius:{get:ExpressionPropertyInterface(s.ir)},innerRoundness:{get:ExpressionPropertyInterface(s.is)},_name:{value:e.nm}}),a.mn=e.mn,a}function MT(e,t,r){function i(t){return 1==t?a:r(--t)}var s="tm"===t.sh.ty?t.sh.prop:t.sh;function a(t){return e.p.ix===t?a.position:e.r.ix===t?a.roundness:e.s.ix===t||"Size"===t||"ADBE Vector Rect Size"===t?a.size:void 0}return a.propertyIndex=e.ix,s.p.setGroupProperty(i),s.s.setGroupProperty(i),s.r.setGroupProperty(i),Object.defineProperties(a,{position:{get:ExpressionPropertyInterface(s.p)},roundness:{get:ExpressionPropertyInterface(s.r)},size:{get:ExpressionPropertyInterface(s.s)},_name:{value:e.nm}}),a.mn=e.mn,a}function NT(e,t,r){var i=t;function s(t){if(e.r.ix===t||"Round Corners 1"===t)return s.radius}return s.propertyIndex=e.ix,i.rd.setGroupProperty(function(t){return 1==t?s:r(--t)}),Object.defineProperties(s,{radius:{get:ExpressionPropertyInterface(i.rd)},_name:{value:e.nm}}),s.mn=e.mn,s}function OT(e,t,r){function i(t){return 1==t?a:r(--t)}var s=t;function a(t){return e.c.ix===t||"Copies"===t?a.copies:e.o.ix===t||"Offset"===t?a.offset:void 0}return a.propertyIndex=e.ix,s.c.setGroupProperty(i),s.o.setGroupProperty(i),Object.defineProperties(a,{copies:{get:ExpressionPropertyInterface(s.c)},offset:{get:ExpressionPropertyInterface(s.o)},_name:{value:e.nm}}),a.mn=e.mn,a}function PT(t,e,r){var i=e.sh;function s(t){if("Shape"===t||"shape"===t||"Path"===t||"path"===t||"ADBE Vector Shape"===t||2===t)return s.path}return i.setGroupProperty(function(t){return 1==t?s:r(--t)}),Object.defineProperties(s,{path:{get:function(){return i.k&&i.getValue(),i}},shape:{get:function(){return i.k&&i.getValue(),i}},_name:{value:t.nm},ix:{value:t.ix},mn:{value:t.mn}}),s}var TextExpressionInterface=function(e){var r;function t(){}return Object.defineProperty(t,"sourceText",{get:function(){e.textProperty.getValue();var t=e.textProperty.currentData.t;return void 0!==t&&(e.textProperty.currentData.t=void 0,(r=new String(t)).value=t||new String(t)),r}}),t},LayerExpressionInterface=function(e){var r;function i(t){switch(t){case"ADBE Root Vectors Group":case"Contents":case 2:return i.shapeInterface;case 1:case 6:case"Transform":case"transform":case"ADBE Transform Group":return r;case 4:case"ADBE Effect Parade":case"effects":case"Effects":return i.effect}}i.toWorld=_V,i.fromWorld=aW,i.toComp=_V,i.fromComp=bW,i.sampleImage=cW,i.sourceRectAtTime=e.sourceRectAtTime.bind(e);var t=getDescriptor(r=TransformExpressionInterface((i._elem=e).finalTransform.mProp),"anchorPoint");return Object.defineProperties(i,{hasParent:{get:function(){return e.hierarchy.length}},parent:{get:function(){return e.hierarchy[0].layerInterface}},rotation:getDescriptor(r,"rotation"),scale:getDescriptor(r,"scale"),position:getDescriptor(r,"position"),opacity:getDescriptor(r,"opacity"),anchorPoint:t,anchor_point:t,transform:{get:function(){return r}},active:{get:function(){return e.isInRange}}}),i.startTime=e.data.st,i.index=e.data.ind,i.source=e.data.refId,i.height=0===e.data.ty?e.data.h:100,i.width=0===e.data.ty?e.data.w:100,i.inPoint=e.data.ip/e.comp.globalData.frameRate,i.outPoint=e.data.op/e.comp.globalData.frameRate,i._name=e.data.nm,i.registerMaskInterface=function(t){i.mask=new MaskManagerInterface(t,e)},i.registerEffectsInterface=function(t){i.effect=t},i};function _V(t,e){var r=new Matrix;if(r.reset(),this._elem.finalTransform.mProp.applyToMatrix(r),this._elem.hierarchy&&this._elem.hierarchy.length){var i,s=this._elem.hierarchy.length;for(i=0;i<s;i+=1)this._elem.hierarchy[i].finalTransform.mProp.applyToMatrix(r);return r.applyToPointArray(t[0],t[1],t[2]||0)}return r.applyToPointArray(t[0],t[1],t[2]||0)}function aW(t,e){var r=new Matrix;if(r.reset(),this._elem.finalTransform.mProp.applyToMatrix(r),this._elem.hierarchy&&this._elem.hierarchy.length){var i,s=this._elem.hierarchy.length;for(i=0;i<s;i+=1)this._elem.hierarchy[i].finalTransform.mProp.applyToMatrix(r);return r.inversePoint(t)}return r.inversePoint(t)}function bW(t){var e=new Matrix;if(e.reset(),this._elem.finalTransform.mProp.applyToMatrix(e),this._elem.hierarchy&&this._elem.hierarchy.length){var r,i=this._elem.hierarchy.length;for(r=0;r<i;r+=1)this._elem.hierarchy[r].finalTransform.mProp.applyToMatrix(e);return e.inversePoint(t)}return e.inversePoint(t)}function cW(){return[1,1,1,1]}var CompExpressionInterface=function(i){function t(t){for(var e=0,r=i.layers.length;e<r;){if(i.layers[e].nm===t||i.layers[e].ind===t)return i.elements[e].layerInterface;e+=1}return null}return Object.defineProperty(t,"_name",{value:i.data.nm}),(t.layer=t).pixelAspect=1,t.height=i.data.h||i.globalData.compSize.h,t.width=i.data.w||i.globalData.compSize.w,t.pixelAspect=1,t.frameDuration=1/i.globalData.frameRate,t.displayStartTime=0,t.numLayers=i.layers.length,t},TransformExpressionInterface=function(t){function e(t){switch(t){case"scale":case"Scale":case"ADBE Scale":case 6:return e.scale;case"rotation":case"Rotation":case"ADBE Rotation":case"ADBE Rotate Z":case 10:return e.rotation;case"ADBE Rotate X":return e.xRotation;case"ADBE Rotate Y":return e.yRotation;case"position":case"Position":case"ADBE Position":case 2:return e.position;case"ADBE Position_0":return e.xPosition;case"ADBE Position_1":return e.yPosition;case"ADBE Position_2":return e.zPosition;case"anchorPoint":case"AnchorPoint":case"Anchor Point":case"ADBE AnchorPoint":case 1:return e.anchorPoint;case"opacity":case"Opacity":case 11:return e.opacity}}if(Object.defineProperty(e,"rotation",{get:ExpressionPropertyInterface(t.r||t.rz)}),Object.defineProperty(e,"zRotation",{get:ExpressionPropertyInterface(t.rz||t.r)}),Object.defineProperty(e,"xRotation",{get:ExpressionPropertyInterface(t.rx)}),Object.defineProperty(e,"yRotation",{get:ExpressionPropertyInterface(t.ry)}),Object.defineProperty(e,"scale",{get:ExpressionPropertyInterface(t.s)}),t.p)var r=ExpressionPropertyInterface(t.p);return Object.defineProperty(e,"position",{get:function(){return t.p?r():[t.px.v,t.py.v,t.pz?t.pz.v:0]}}),Object.defineProperty(e,"xPosition",{get:ExpressionPropertyInterface(t.px)}),Object.defineProperty(e,"yPosition",{get:ExpressionPropertyInterface(t.py)}),Object.defineProperty(e,"zPosition",{get:ExpressionPropertyInterface(t.pz)}),Object.defineProperty(e,"anchorPoint",{get:ExpressionPropertyInterface(t.a)}),Object.defineProperty(e,"opacity",{get:ExpressionPropertyInterface(t.o)}),Object.defineProperty(e,"skew",{get:ExpressionPropertyInterface(t.sk)}),Object.defineProperty(e,"skewAxis",{get:ExpressionPropertyInterface(t.sa)}),Object.defineProperty(e,"orientation",{get:ExpressionPropertyInterface(t.or)}),e},ProjectInterface=function(){function t(t){for(var e=0,r=this.compositions.length;e<r;){if(this.compositions[e].data&&this.compositions[e].data.nm===t)return this.compositions[e].prepareFrame&&this.compositions[e].data.xt&&this.compositions[e].prepareFrame(this.currentFrame),this.compositions[e].compInterface;e+=1}}return t.compositions=[],t.currentFrame=0,t.registerComposition=LW,t};function LW(t){this.compositions.push(t)}var EffectsExpressionInterface={createEffectsInterface:function(s,t){if(s.effectsManager){var e,a=[],r=s.data.ef,i=s.effectsManager.effectElements.length;for(e=0;e<i;e+=1)a.push(TW(r[e],s.effectsManager.effectElements[e],t,s));return function(t){for(var e=s.data.ef||[],r=0,i=e.length;r<i;){if(t===e[r].nm||t===e[r].mn||t===e[r].ix)return a[r];r+=1}}}}};function TW(s,t,e,r){var i,a=[],n=s.ef.length;for(i=0;i<n;i+=1)5===s.ef[i].ty?a.push(TW(s.ef[i],t.effectElements[i],t.effectElements[i].propertyGroup,r)):a.push(UW(t.effectElements[i],s.ef[i].ty,r,o));function o(t){return 1===t?h:e(t-1)}var h=function(t){for(var e=s.ef,r=0,i=e.length;r<i;){if(t===e[r].nm||t===e[r].mn||t===e[r].ix)return 5===e[r].ty?a[r]:a[r]();r+=1}return a[0]()};return h.propertyGroup=o,"ADBE Color Control"===s.mn&&Object.defineProperty(h,"color",{get:function(){return a[0]()}}),Object.defineProperty(h,"numProperties",{get:function(){return s.np}}),h.active=h.enabled=0!==s.en,h}function UW(t,e,r,i){var s=ExpressionPropertyInterface(t.p);return t.p.setGroupProperty&&t.p.setGroupProperty(i),function(){return 10===e?r.comp.compInterface(t.p.v):s()}}var MaskManagerInterface=function(){function a(t,e){this._mask=t,this._data=e}Object.defineProperty(a.prototype,"maskPath",{get:function(){return this._mask.prop.k&&this._mask.prop.getValue(),this._mask.prop}});return function(e,t){var r,i=createSizedArray(e.viewData.length),s=e.viewData.length;for(r=0;r<s;r+=1)i[r]=new a(e.viewData[r],e.masksProperties[r]);return function(t){for(r=0;r<s;){if(e.masksProperties[r].nm===t)return i[r];r+=1}}}}(),ExpressionPropertyInterface=(KX={pv:0,v:0,mult:1},LX={pv:[0,0,0],v:[0,0,0],mult:1},function(t){return t?"unidimensional"===t.propType?function(t){t&&"pv"in t||(t=KX);var e=1/t.mult,r=t.pv*e,i=new Number(r);return i.value=r,MX(i,t,"unidimensional"),function(){return t.k&&t.getValue(),r=t.v*e,i.value!==r&&((i=new Number(r)).value=r,MX(i,t,"unidimensional")),i}}(t):function(e){e&&"pv"in e||(e=LX);var r=1/e.mult,i=e.pv.length,s=createTypedArray("float32",i),a=createTypedArray("float32",i);return s.value=a,MX(s,e,"multidimensional"),function(){e.k&&e.getValue();for(var t=0;t<i;t+=1)s[t]=a[t]=e.v[t]*r;return s}}(t):PX}),KX,LX,fY,gY;function MX(i,s,a){Object.defineProperty(i,"velocity",{get:function(){return s.getVelocityAtTime(s.comp.currentFrame)}}),i.numKeys=s.keyframes?s.keyframes.length:0,i.key=function(t){if(i.numKeys){var e="";e="s"in s.keyframes[t-1]?s.keyframes[t-1].s:"e"in s.keyframes[t-2]?s.keyframes[t-2].e:s.keyframes[t-2].s;var r="unidimensional"===a?new Number(e):Object.assign({},e);return r.time=s.keyframes[t-1].t/s.elem.comp.globalData.frameRate,r}return 0},i.valueAtTime=s.getValueAtTime,i.speedAtTime=s.getSpeedAtTime,i.velocityAtTime=s.getVelocityAtTime,i.propertyGroup=s.propertyGroup}function PX(){return KX}function hY(t,e){return this.textIndex=t+1,this.textTotal=e,this.v=this.getValue()*this.mult,this.v}function SliderEffect(t,e,r){this.p=PropertyFactory.getProp(e,t.v,0,0,r)}function AngleEffect(t,e,r){this.p=PropertyFactory.getProp(e,t.v,0,0,r)}function ColorEffect(t,e,r){this.p=PropertyFactory.getProp(e,t.v,1,0,r)}function PointEffect(t,e,r){this.p=PropertyFactory.getProp(e,t.v,1,0,r)}function LayerIndexEffect(t,e,r){this.p=PropertyFactory.getProp(e,t.v,0,0,r)}function MaskIndexEffect(t,e,r){this.p=PropertyFactory.getProp(e,t.v,0,0,r)}function CheckboxEffect(t,e,r){this.p=PropertyFactory.getProp(e,t.v,0,0,r)}function NoValueEffect(){this.p={}}function EffectsManager(t,e){var r=t.ef||[];this.effectElements=[];var i,s,a=r.length;for(i=0;i<a;i++)s=new GroupEffect(r[i],e),this.effectElements.push(s)}function GroupEffect(t,e){this.init(t,e)}fY=function(t,e){this.pv=1,this.comp=t.comp,this.elem=t,this.mult=.01,this.propType="textSelector",this.textTotal=e.totalChars,this.selectorValue=100,this.lastValue=[1,1,1],this.k=!0,this.x=!0,this.getValue=ExpressionManager.initiateExpression.bind(this)(t,e,this),this.getMult=hY,this.getVelocityAtTime=expressionHelpers.getVelocityAtTime,this.kf?this.getValueAtTime=expressionHelpers.getValueAtTime.bind(this):this.getValueAtTime=expressionHelpers.getStaticValueAtTime.bind(this),this.setGroupProperty=expressionHelpers.setGroupProperty},gY=TextSelectorProp.getTextSelectorProp,TextSelectorProp.getTextSelectorProp=function(t,e,r){return 1===e.t?new fY(t,e,r):gY(t,e,r)},extendPrototype([DynamicPropertyContainer],GroupEffect),GroupEffect.prototype.getValue=GroupEffect.prototype.iterateDynamicProperties,GroupEffect.prototype.init=function(t,e){this.data=t,this.effectElements=[],this.initDynamicPropertyContainer(e);var r,i,s=this.data.ef.length,a=this.data.ef;for(r=0;r<s;r+=1){switch(i=null,a[r].ty){case 0:i=new SliderEffect(a[r],e,this);break;case 1:i=new AngleEffect(a[r],e,this);break;case 2:i=new ColorEffect(a[r],e,this);break;case 3:i=new PointEffect(a[r],e,this);break;case 4:case 7:i=new CheckboxEffect(a[r],e,this);break;case 10:i=new LayerIndexEffect(a[r],e,this);break;case 11:i=new MaskIndexEffect(a[r],e,this);break;case 5:i=new EffectsManager(a[r],e,this);break;default:i=new NoValueEffect(a[r],e,this)}i&&this.effectElements.push(i)}};var lottiejs={},_isFrozen=!1;function loadAnimation(t){return animationManager.loadAnimation(t)}function setQuality(t){if("string"==typeof t)switch(t){case"high":defaultCurveSegments=200;break;case"medium":defaultCurveSegments=50;break;case"low":defaultCurveSegments=10}else!isNaN(t)&&1<t&&(defaultCurveSegments=t);roundValues(!(50<=defaultCurveSegments))}lottiejs.play=animationManager.play,lottiejs.pause=animationManager.pause,lottiejs.togglePause=animationManager.togglePause,lottiejs.setSpeed=animationManager.setSpeed,lottiejs.setDirection=animationManager.setDirection,lottiejs.stop=animationManager.stop,lottiejs.registerAnimation=animationManager.registerAnimation,lottiejs.loadAnimation=loadAnimation,lottiejs.resize=animationManager.resize,lottiejs.goToAndStop=animationManager.goToAndStop,lottiejs.destroy=animationManager.destroy,lottiejs.setQuality=setQuality,lottiejs.freeze=animationManager.freeze,lottiejs.unfreeze=animationManager.unfreeze,lottiejs.getRegisteredAnimations=animationManager.getRegisteredAnimations,lottiejs.version="5.5.2";var renderer="";return lottiejs}({}),currentAnimation=null,events={INITIALIZED:"initialized",RESIZED:"resized",PLAYING:"playing"};getCurrentCanvasSize=function(){var t=currentAnimation.renderer.canvasContext.canvas;return{height:t.height,width:t.width}},sendResizeEvent=function(){currentAnimation.renderer.canvasContext.canvas;postMessage({name:events.RESIZED,size:getCurrentCanvasSize()})},sendPlayEvent=function(){postMessage({name:events.PLAYING})},sendInitializedEvent=function(){currentAnimation.renderer.canvasContext.canvas;postMessage({name:events.INITIALIZED,success:currentAnimation.isLoaded})},onmessage=function(t){if(t&&t.data){var e=null;if(currentAnimation)e=currentAnimation.renderer.canvasContext.canvas;else{if(!t.data.canvas)return;e=t.data.canvas}if(t.data.drawSize&&0<t.data.drawSize.height&&0<t.data.drawSize.width&&(e.height=t.data.drawSize.height,e.width=t.data.drawSize.width,currentAnimation&&(currentAnimation.resize(),sendResizeEvent())),!currentAnimation){if(!t.data.animationData||!t.data.params)return;var r=t.data.params,i=e.getContext("2d");currentAnimation=lottiejs.loadAnimation({renderer:"canvas",loop:r.loop,autoplay:r.autoplay,animationData:t.data.animationData,rendererSettings:{context:i,scaleMode:"noScale",clearCanvas:!0}}),sendInitializedEvent(),r.autoplay&&currentAnimation.play(),currentAnimation.isLoaded&&!currentAnimation.isPaused&&sendPlayEvent()}}};
\ No newline at end of file
diff --git a/third_party/pylint/README.chromium b/third_party/pylint/README.chromium
index 88e1f1a..86495e6c 100644
--- a/third_party/pylint/README.chromium
+++ b/third_party/pylint/README.chromium
@@ -8,6 +8,14 @@
 Description:
 This directory contains the pylint module.
 
+This code is not included in the final build.  It is only used to run linting
+checks on code (usually at presubmit time).
+
+This is only used by code inside the src tree that needs to import the pylint
+module directly.  If you're using `pylint` to check your code (e.g. via the
+PRESUBMIT.cfg file), then this copy is *not* used.  That pylint comes from the
+depot_tools repo instead.
+
 Local Modifications:
 - applied upstream fix https://bitbucket.org/logilab/pylint/commits/5df347467ee0
 - applied fix to work around bad interaction between sys.path manipulation in
diff --git a/tools/grit/grit/clique.py b/tools/grit/grit/clique.py
index cd5b44c..bb19f1b 100644
--- a/tools/grit/grit/clique.py
+++ b/tools/grit/grit/clique.py
@@ -9,7 +9,8 @@
 from __future__ import print_function
 
 import re
-import types
+
+import six
 
 from grit import constants
 from grit import exception
@@ -271,7 +272,7 @@
     '''
     contents = translation.GetContent()
     for ix in range(len(contents)):
-      if (isinstance(contents[ix], types.StringTypes)):
+      if (isinstance(contents[ix], six.string_types)):
         contents[ix] = self.ModifyTextPart(lang, contents[ix])
 
 
diff --git a/tools/grit/grit/format/c_format.py b/tools/grit/grit/format/c_format.py
index e944b7f..2a6ee12 100644
--- a/tools/grit/grit/format/c_format.py
+++ b/tools/grit/grit/format/c_format.py
@@ -9,7 +9,8 @@
 
 import os
 import re
-import types
+
+import six
 
 from grit import util
 
@@ -35,7 +36,7 @@
 def Format(root, lang='en', output_dir='.'):
   """Outputs a C switch statement representing the string table."""
   from grit.node import message
-  assert isinstance(lang, types.StringTypes)
+  assert isinstance(lang, six.string_types)
 
   yield _FormatHeader(root, output_dir)
 
diff --git a/tools/grit/grit/format/rc.py b/tools/grit/grit/format/rc.py
index ac65f34..ed32bb8 100644
--- a/tools/grit/grit/format/rc.py
+++ b/tools/grit/grit/format/rc.py
@@ -8,10 +8,11 @@
 from __future__ import print_function
 
 import os
-import types
 import re
 from functools import partial
 
+import six
+
 from grit import util
 from grit.node import misc
 
@@ -315,7 +316,7 @@
 
 def _FormatHeader(root, lang, output_dir):
   '''Returns the required preamble for RC files.'''
-  assert isinstance(lang, types.StringTypes)
+  assert isinstance(lang, six.string_types)
   assert isinstance(root, misc.GritNode)
   # Find the location of the resource header file, so that we can include
   # it.
@@ -373,7 +374,7 @@
 
 def _FormatSection(item, lang, output_dir):
   '''Writes out an .rc file section.'''
-  assert isinstance(lang, types.StringTypes)
+  assert isinstance(lang, six.string_types)
   from grit.node import structure
   assert isinstance(item, structure.StructureNode)
 
@@ -402,7 +403,7 @@
           StructureNode)
     process_html: False/True (ignored unless item is a StructureNode)
   '''
-  assert isinstance(lang, types.StringTypes)
+  assert isinstance(lang, six.string_types)
   from grit.node import structure
   from grit.node import include
   assert isinstance(item, (structure.StructureNode, include.IncludeNode))
diff --git a/tools/grit/grit/gather/interface.py b/tools/grit/grit/gather/interface.py
index 6149167..15d64f932 100644
--- a/tools/grit/grit/gather/interface.py
+++ b/tools/grit/grit/gather/interface.py
@@ -8,7 +8,8 @@
 from __future__ import print_function
 
 import os.path
-import types
+
+import six
 
 from grit import clique
 from grit import util
@@ -161,7 +162,7 @@
     '''A convenience function for subclasses that loads the contents of the
     input file.
     '''
-    if isinstance(self.rc_file, types.StringTypes):
+    if isinstance(self.rc_file, six.string_types):
       path = self.GetInputPath()
       # Hack: some unit tests supply an absolute path and no root node.
       if not os.path.isabs(path):
diff --git a/tools/grit/grit/gather/skeleton_gatherer.py b/tools/grit/grit/gather/skeleton_gatherer.py
index e0f3074..b11862b 100644
--- a/tools/grit/grit/gather/skeleton_gatherer.py
+++ b/tools/grit/grit/gather/skeleton_gatherer.py
@@ -8,7 +8,7 @@
 
 from __future__ import print_function
 
-import types
+import six
 
 from grit.gather import interface
 from grit import clique
@@ -78,17 +78,17 @@
 
     out = []
     for ix in range(len(self.skeleton_)):
-      if isinstance(self.skeleton_[ix], types.StringTypes):
+      if isinstance(self.skeleton_[ix], six.string_types):
         if skeleton_gatherer:
           # Make sure the skeleton is like the original
-          assert(isinstance(skeleton_gatherer.skeleton_[ix], types.StringTypes))
+          assert(isinstance(skeleton_gatherer.skeleton_[ix], six.string_types))
           out.append(skeleton_gatherer.skeleton_[ix])
         else:
           out.append(self.skeleton_[ix])
       else:
         if skeleton_gatherer:  # Make sure the skeleton is like the original
           assert(not isinstance(skeleton_gatherer.skeleton_[ix],
-                                types.StringTypes))
+                                six.string_types))
         msg = self.skeleton_[ix].MessageForLanguage(lang,
                                                     pseudo_if_not_available,
                                                     fallback_to_english)
diff --git a/tools/grit/grit/gather/tr_html.py b/tools/grit/grit/gather/tr_html.py
index ba59ff65..5a60696 100644
--- a/tools/grit/grit/gather/tr_html.py
+++ b/tools/grit/grit/gather/tr_html.py
@@ -52,7 +52,8 @@
 from __future__ import print_function
 
 import re
-import types
+
+import six
 
 from grit import clique
 from grit import exception
@@ -573,7 +574,7 @@
       current += m.end()
       continue
 
-    if len(parts) and isinstance(parts[-1], types.StringTypes):
+    if len(parts) and isinstance(parts[-1], six.string_types):
       parts[-1] += html[current]
     else:
       parts.append(html[current])
@@ -582,7 +583,7 @@
   msg_text = ''
   placeholders = []
   for part in parts:
-    if isinstance(part, types.TupleType):
+    if isinstance(part, tuple):
       final_name = part[0]()
       original = part[1]
       msg_text += final_name
@@ -594,7 +595,7 @@
                       description=description)
   content = msg.GetContent()
   for ix in range(len(content)):
-    if isinstance(content[ix], types.StringTypes):
+    if isinstance(content[ix], six.string_types):
       content[ix] = util.UnescapeHtml(content[ix], replace_nbsp=False)
 
   return msg
@@ -658,7 +659,7 @@
 
     out = []
     for item in self.skeleton_:
-      if isinstance(item, types.StringTypes):
+      if isinstance(item, six.string_types):
         out.append(item)
       else:
         msg = item.MessageForLanguage(lang,
@@ -718,8 +719,8 @@
       if isinstance(self.skeleton_[ix], clique.MessageClique):
         msg = self.skeleton_[ix].GetMessage()
         for item in msg.GetContent():
-          if (isinstance(item, types.StringTypes) and _NON_WHITESPACE.search(item)
-              and item != '&nbsp;'):
+          if (isinstance(item, six.string_types)
+              and _NON_WHITESPACE.search(item) and item != '&nbsp;'):
             got_text = True
             break
         if not got_text:
diff --git a/tools/grit/grit/gather/tr_html_unittest.py b/tools/grit/grit/gather/tr_html_unittest.py
index 5d82276..1194853 100755
--- a/tools/grit/grit/gather/tr_html_unittest.py
+++ b/tools/grit/grit/gather/tr_html_unittest.py
@@ -12,9 +12,9 @@
 if __name__ == '__main__':
   sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
 
-import types
 import unittest
 
+import six
 from six import StringIO
 
 from grit.gather import tr_html
@@ -369,7 +369,7 @@
     # For manual results inspection only...
     list = []
     for item in html.skeleton_:
-      if isinstance(item, types.StringTypes):
+      if isinstance(item, six.string_types):
         list.append(item)
       else:
         list.append(item.GetMessage().GetPresentableContent())
diff --git a/tools/grit/grit/grd_reader.py b/tools/grit/grit/grd_reader.py
index 2535ce94..514008a3 100755
--- a/tools/grit/grit/grd_reader.py
+++ b/tools/grit/grit/grd_reader.py
@@ -10,10 +10,11 @@
 
 import os.path
 import sys
-import types
 import xml.sax
 import xml.sax.handler
 
+import six
+
 from grit import exception
 from grit import util
 from grit.node import mapping
@@ -187,7 +188,7 @@
     grit.exception.Parsing
   '''
 
-  if isinstance(filename_or_stream, types.StringType):
+  if isinstance(filename_or_stream, six.string_types):
     source = filename_or_stream
     if dir is None:
       dir = util.dirname(filename_or_stream)
diff --git a/tools/grit/grit/node/base.py b/tools/grit/grit/node/base.py
index 0519b59..5159c5e 100644
--- a/tools/grit/grit/node/base.py
+++ b/tools/grit/grit/node/base.py
@@ -11,9 +11,10 @@
 import os
 import struct
 import sys
-import types
 from xml.sax import saxutils
 
+import six
+
 from grit import constants
 from grit import clique
 from grit import exception
@@ -112,7 +113,7 @@
       name: u'elementname'
       parent: grit.node.base.Node or subclass or None
     '''
-    assert isinstance(name, types.StringTypes)
+    assert isinstance(name, six.string_types)
     assert not parent or isinstance(parent, Node)
     self.name = name
     self.parent = parent
@@ -155,7 +156,7 @@
     Return:
       None
     '''
-    assert isinstance(content, types.StringTypes)
+    assert isinstance(content, six.string_types)
     if self._ContentType() != self._CONTENT_TYPE_NONE:
       self.mixed_content.append(content)
     elif content.strip() != '':
@@ -172,8 +173,8 @@
     Return:
       None
     '''
-    assert isinstance(attrib, types.StringTypes)
-    assert isinstance(value, types.StringTypes)
+    assert isinstance(attrib, six.string_types)
+    assert isinstance(value, six.string_types)
     if self._IsValidAttribute(attrib, value):
       self.attrs[attrib] = value
     else:
@@ -184,34 +185,34 @@
 
     # TODO(joi) Rewrite this, it's extremely ugly!
     if len(self.mixed_content):
-      if isinstance(self.mixed_content[0], types.StringTypes):
+      if isinstance(self.mixed_content[0], six.string_types):
         # Remove leading and trailing chunks of pure whitespace.
         while (len(self.mixed_content) and
-               isinstance(self.mixed_content[0], types.StringTypes) and
+               isinstance(self.mixed_content[0], six.string_types) and
                self.mixed_content[0].strip() == ''):
           self.mixed_content = self.mixed_content[1:]
         # Strip leading and trailing whitespace from mixed content chunks
         # at front and back.
         if (len(self.mixed_content) and
-            isinstance(self.mixed_content[0], types.StringTypes)):
+            isinstance(self.mixed_content[0], six.string_types)):
           self.mixed_content[0] = self.mixed_content[0].lstrip()
         # Remove leading and trailing ''' (used to demarcate whitespace)
         if (len(self.mixed_content) and
-            isinstance(self.mixed_content[0], types.StringTypes)):
+            isinstance(self.mixed_content[0], six.string_types)):
           if self.mixed_content[0].startswith("'''"):
             self.mixed_content[0] = self.mixed_content[0][3:]
     if len(self.mixed_content):
-      if isinstance(self.mixed_content[-1], types.StringTypes):
+      if isinstance(self.mixed_content[-1], six.string_types):
         # Same stuff all over again for the tail end.
         while (len(self.mixed_content) and
-               isinstance(self.mixed_content[-1], types.StringTypes) and
+               isinstance(self.mixed_content[-1], six.string_types) and
                self.mixed_content[-1].strip() == ''):
           self.mixed_content = self.mixed_content[:-1]
         if (len(self.mixed_content) and
-            isinstance(self.mixed_content[-1], types.StringTypes)):
+            isinstance(self.mixed_content[-1], six.string_types)):
           self.mixed_content[-1] = self.mixed_content[-1].rstrip()
         if (len(self.mixed_content) and
-            isinstance(self.mixed_content[-1], types.StringTypes)):
+            isinstance(self.mixed_content[-1], six.string_types)):
           if self.mixed_content[-1].endswith("'''"):
             self.mixed_content[-1] = self.mixed_content[-1][:-3]
 
@@ -244,7 +245,7 @@
     '''Returns all CDATA of this element, concatenated into a single
     string.  Note that this ignores any elements embedded in CDATA.'''
     return ''.join([c for c in self.mixed_content
-                    if isinstance(c, types.StringTypes)])
+                    if isinstance(c, six.string_types)])
 
   def __unicode__(self):
     '''Returns this node and all nodes below it as an XML document in a Unicode
@@ -259,7 +260,7 @@
     children and CDATA are layed out in a way that preserves internal
     whitespace.
     '''
-    assert isinstance(indent, types.StringTypes)
+    assert isinstance(indent, six.string_types)
 
     content_one_line = (one_line or
                         self._ContentType() == self._CONTENT_TYPE_MIXED)
@@ -293,7 +294,7 @@
   def ContentsAsXml(self, indent, one_line):
     '''Returns the contents of this node (CDATA and child elements) in XML
     format.  If 'one_line' is true, the content will be laid out on one line.'''
-    assert isinstance(indent, types.StringTypes)
+    assert isinstance(indent, six.string_types)
 
     # Build the contents of the element.
     inside_parts = []
@@ -319,7 +320,7 @@
 
     # If the last item is a string (not a node) and ends with whitespace,
     # we need to add the ''' delimiter.
-    if (isinstance(last_item, types.StringTypes) and
+    if (isinstance(last_item, six.string_types) and
         last_item.rstrip() != last_item):
       inside_parts[-1] = inside_parts[-1] + u"'''"
 
diff --git a/tools/grit/grit/node/message.py b/tools/grit/grit/node/message.py
index a21c38c..cc8d217 100644
--- a/tools/grit/grit/node/message.py
+++ b/tools/grit/grit/node/message.py
@@ -8,7 +8,8 @@
 from __future__ import print_function
 
 import re
-import types
+
+import six
 
 from grit.node import base
 
@@ -166,7 +167,7 @@
     placeholders = []
 
     for item in self.mixed_content:
-      if isinstance(item, types.StringTypes):
+      if isinstance(item, six.string_types):
         # Not a <ph> element: fail if any <ph> formatters are detected.
         if _FORMATTERS.search(item):
           print(_BAD_PLACEHOLDER_MSG % (item, self.source))
@@ -303,7 +304,7 @@
 
     items = message.GetContent()
     for ix, item in enumerate(items):
-      if isinstance(item, types.StringTypes):
+      if isinstance(item, six.string_types):
         # Ensure whitespace at front and back of message is correctly handled.
         if ix == 0:
           item = "'''" + item
diff --git a/tools/grit/grit/tclib.py b/tools/grit/grit/tclib.py
index 23bef75..3403e87a2 100644
--- a/tools/grit/grit/tclib.py
+++ b/tools/grit/grit/tclib.py
@@ -8,7 +8,8 @@
 from __future__ import print_function
 
 import re
-import types
+
+import six
 
 from grit import exception
 from grit import lazy_re
@@ -83,7 +84,7 @@
     '''
     bits = []
     for item in self.parts:
-      if isinstance(item, types.StringTypes):
+      if isinstance(item, six.string_types):
         bits.append(escaping_function(item))
       else:
         bits.append(item.GetOriginal())
@@ -112,7 +113,7 @@
     self.dirty = True
 
   def AppendText(self, text):
-    assert isinstance(text, types.StringTypes)
+    assert isinstance(text, six.string_types)
     assert text != ''
 
     self.parts.append(text)
diff --git a/tools/grit/grit/tclib_unittest.py b/tools/grit/grit/tclib_unittest.py
index 94673a2..8570c8f 100755
--- a/tools/grit/grit/tclib_unittest.py
+++ b/tools/grit/grit/tclib_unittest.py
@@ -12,9 +12,10 @@
 if __name__ == '__main__':
   sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
 
-import types
 import unittest
 
+import six
+
 from grit import tclib
 
 from grit import exception
@@ -26,14 +27,14 @@
     msg = tclib.Message(text=u'Hello Earthlings',
                         description='Greetings\n\t      message')
     self.failUnlessEqual(msg.GetPresentableContent(), 'Hello Earthlings')
-    self.failUnless(isinstance(msg.GetPresentableContent(), types.StringTypes))
+    self.failUnless(isinstance(msg.GetPresentableContent(), six.string_types))
     self.failUnlessEqual(msg.GetDescription(), 'Greetings message')
 
   def testGetAttr(self):
     msg = tclib.Message()
     msg.AppendText(u'Hello')  # Tests __getattr__
     self.failUnless(msg.GetPresentableContent() == 'Hello')
-    self.failUnless(isinstance(msg.GetPresentableContent(), types.StringTypes))
+    self.failUnless(isinstance(msg.GetPresentableContent(), six.string_types))
 
   def testAll(self):
     text = u'Howdie USERNAME'
@@ -43,7 +44,7 @@
 
     trans = tclib.Translation(text=text, placeholders=phs)
     self.failUnless(trans.GetPresentableContent() == 'Howdie USERNAME')
-    self.failUnless(isinstance(trans.GetPresentableContent(), types.StringTypes))
+    self.failUnless(isinstance(trans.GetPresentableContent(), six.string_types))
 
   def testUnicodeReturn(self):
     text = u'\u00fe'
@@ -65,7 +66,7 @@
     transl = tclib.Translation(text=msg.GetPresentableContent(),
                                placeholders=msg.GetPlaceholders())
     content = transl.GetContent()
-    self.failUnless(isinstance(content[3], types.UnicodeType))
+    self.failUnless(isinstance(content[3], six.string_types))
 
   def testFingerprint(self):
     # This has Windows line endings.  That is on purpose.
diff --git a/tools/grit/grit/tool/menu_from_parts.py b/tools/grit/grit/tool/menu_from_parts.py
index 94a1fb0..c4b4adbc 100644
--- a/tools/grit/grit/tool/menu_from_parts.py
+++ b/tools/grit/grit/tool/menu_from_parts.py
@@ -6,7 +6,7 @@
 
 from __future__ import print_function
 
-import types
+import six
 
 from grit import grd_reader
 from grit import util
@@ -61,7 +61,7 @@
 
         contents = message.GetContent()
         for part in contents:
-          if isinstance(part, types.StringTypes):
+          if isinstance(part, six.string_types):
             id = grit.extern.tclib.GenerateMessageId(part)
             if id not in xtb:
               print("WARNING didn't find all translations for menu %s" %
diff --git a/tools/grit/grit/tool/rc2grd.py b/tools/grit/grit/tool/rc2grd.py
index beb80e9..dc406aaa 100644
--- a/tools/grit/grit/tool/rc2grd.py
+++ b/tools/grit/grit/tool/rc2grd.py
@@ -10,8 +10,8 @@
 import getopt
 import re
 import sys
-import types
 
+import six
 from six import StringIO
 
 import grit.node.empty
@@ -341,7 +341,7 @@
         # Messages that contain only placeholders do not need translation.
         is_translateable = False
         for item in msg_obj.GetContent():
-          if isinstance(item, types.StringTypes):
+          if isinstance(item, six.string_types):
             if not _WHITESPACE_ONLY.match(item):
               is_translateable = True
 
@@ -389,7 +389,7 @@
       # TODO(joi) Allow use of non-TotalRecall flavors of HTML placeholderizing
       msg = tr_html.HtmlToMessage(text, True)
       for item in msg.GetContent():
-        if not isinstance(item, types.StringTypes):
+        if not isinstance(item, six.string_types):
           return msg  # Contained at least one placeholder, so we're done
 
       # HTML placeholderization didn't do anything, so try to find printf or
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index ceaf035..e86cc49 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -8800,6 +8800,13 @@
   <int value="7" label="Cookies, Storage, and Cache"/>
 </enum>
 
+<enum name="ClickToCallDeviceState">
+  <int value="0" label="Screen off, in background"/>
+  <int value="1" label="Screen on, in background"/>
+  <int value="2" label="Screen off, in foreground"/>
+  <int value="3" label="Screen on, in foreground"/>
+</enum>
+
 <enum name="ClientAppId">
   <int value="0" label="Other"/>
   <int value="1" label="Gmail"/>
@@ -19013,7 +19020,7 @@
       label="DELETED_EXPERIMENTAL_MEDIAGALLERIES_ASSEMBLEMEDIAFILE"/>
   <int value="150" label="BOOKMARKMANAGERPRIVATE_STARTDRAG"/>
   <int value="151" label="BROWSINGDATA_REMOVEPASSWORDS"/>
-  <int value="152" label="DOWNLOADS_DRAG"/>
+  <int value="152" label="DELETED_DOWNLOADS_DRAG"/>
   <int value="153" label="INPUT_IME_SETCOMPOSITION"/>
   <int value="154" label="METRICSPRIVATE_RECORDUSERACTION"/>
   <int value="155" label="USB_RELEASEINTERFACE"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 02ee05830..862e8ce0 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -7635,6 +7635,9 @@
 
 <histogram name="Ash.WindowCycleController.CycleTime" units="ms"
     expires_after="M77">
+  <obsolete>
+    Deprecated as of 07/2019.
+  </obsolete>
   <owner>wutao@chromium.org</owner>
   <owner>tbuckley@google.com</owner>
   <summary>
@@ -7643,7 +7646,8 @@
   </summary>
 </histogram>
 
-<histogram name="Ash.WindowCycleController.Items" units="items">
+<histogram name="Ash.WindowCycleController.Items" units="items"
+    expires_after="M79">
   <owner>wutao@chromium.org</owner>
   <owner>tbuckley@google.com</owner>
   <summary>
@@ -7654,6 +7658,9 @@
 
 <histogram name="Ash.WindowCycleController.SelectionDepth" units="items"
     expires_after="M77">
+  <obsolete>
+    Deprecated as of 07/2019.
+  </obsolete>
   <owner>wutao@chromium.org</owner>
   <owner>tbuckley@google.com</owner>
   <summary>
@@ -122892,8 +122899,10 @@
 </histogram>
 
 <histogram name="ServiceWorker.BackgroundFetchAbortEvent.Time" units="ms"
-    expires_after="M78">
+    expires_after="M85">
+  <owner>nator@chromium.org</owner>
   <owner>peter@chromium.org</owner>
+  <owner>rayankans@chromium.org</owner>
   <summary>
     The time taken between dispatching a BackgroundFetchAbortEvent to a Service
     Worker and receiving a message that it finished handling the event. Includes
@@ -122901,8 +122910,11 @@
   </summary>
 </histogram>
 
-<histogram name="ServiceWorker.BackgroundFetchClickEvent.Time" units="ms">
+<histogram name="ServiceWorker.BackgroundFetchClickEvent.Time" units="ms"
+    expires_after="M85">
+  <owner>nator@chromium.org</owner>
   <owner>peter@chromium.org</owner>
+  <owner>rayankans@chromium.org</owner>
   <summary>
     The time taken between dispatching a BackgroundFetchClickEvent to a Service
     Worker and receiving a message that it finished handling the event. Includes
@@ -122924,8 +122936,11 @@
   </summary>
 </histogram>
 
-<histogram name="ServiceWorker.BackgroundFetchFailEvent.Time" units="ms">
+<histogram name="ServiceWorker.BackgroundFetchFailEvent.Time" units="ms"
+    expires_after="M85">
+  <owner>nator@chromium.org</owner>
   <owner>peter@chromium.org</owner>
+  <owner>rayankans@chromium.org</owner>
   <summary>
     The time taken between dispatching a BackgroundFetchFailEvent to a Service
     Worker and receiving a message that it finished handling the event. Includes
@@ -126883,6 +126898,27 @@
   </summary>
 </histogram>
 
+<histogram name="Sharing.ClickToCallPhoneCall" units="ms" expires_after="M80">
+  <owner>mvanouwerkerk@chromium.org</owner>
+  <owner>knollr@chromium.org</owner>
+  <summary>
+    The time from opening the dialer until a phone call is initiated. This is
+    logged when we detect an outgoing phone call after opening the dialer as
+    part of the Click to Call feature. Android only.
+  </summary>
+</histogram>
+
+<histogram name="Sharing.ClickToCallReceiveDeviceState"
+    enum="ClickToCallDeviceState" expires_after="M80">
+  <owner>mvanouwerkerk@chromium.org</owner>
+  <owner>knollr@chromium.org</owner>
+  <summary>
+    The device state when receiving a Click to Call message. Indicates if the
+    screen is on or off and if Chrome is running in foreground. Recorded when
+    handling a Click to Call message. Android only.
+  </summary>
+</histogram>
+
 <histogram name="Sharing.ClickToCallSelectedAppIndex" units="index"
     expires_after="2020-02-02">
 <!-- Name completed by histogram_suffixes name="SharingClickToCallUi" -->
@@ -143792,37 +143828,6 @@
   </summary>
 </histogram>
 
-<histogram name="UMA.Dummy.Histogram.CheckOwnersExpansion.Basic">
-  <owner>caitlinfischer@google.com</owner>
-  <owner>src/base/metrics/OWNERS</owner>
-  <summary>
-    The purpose of this histogram is to verify that components can be extracted
-    from an OWNERS file. After verifying, this histogram should be deleted.
-  </summary>
-</histogram>
-
-<histogram
-    name="UMA.Dummy.Histogram.CheckOwnersExpansion.ComponentInHigherLevelDirectory">
-  <owner>caitlinfischer@google.com</owner>
-  <owner>src/chrome/browser/metrics/oom/OWNERS</owner>
-  <summary>
-    The purpose of this histogram is to verify that a component from a
-    higher-level directory's OWNERS file is extracted when a component cannot be
-    found in the given OWNERS file. After verifying, this histogram should be
-    deleted.
-  </summary>
-</histogram>
-
-<histogram name="UMA.Dummy.Histogram.CheckOwnersExpansion.NoComponent">
-  <owner>caitlinfischer@google.com</owner>
-  <owner>src/jingle/OWNERS</owner>
-  <summary>
-    The purpose of this histogram is to verify that no component is added when a
-    component cannot be found in the given OWNERS file or in an OWNERS file in a
-    higher-level directory. After verifying, this histogram should be deleted.
-  </summary>
-</histogram>
-
 <histogram name="UMA.EnrollmentStatus" enum="EnrollmentStatus"
     expires_after="2020-01-26">
   <owner>asvitkine@chromium.org</owner>
diff --git a/tools/perf/benchmarks/benchmark_smoke_unittest.py b/tools/perf/benchmarks/benchmark_smoke_unittest.py
index 519c165a..a5062cc 100644
--- a/tools/perf/benchmarks/benchmark_smoke_unittest.py
+++ b/tools/perf/benchmarks/benchmark_smoke_unittest.py
@@ -24,6 +24,7 @@
 from py_utils import tempfile_ext
 
 from benchmarks import jetstream
+from benchmarks import jetstream2
 from benchmarks import octane
 from benchmarks import rasterize_and_record_micro
 from benchmarks import speedometer
@@ -103,6 +104,7 @@
     rasterize_and_record_micro,  # Always fails on cq bot.
     speedometer,  # Takes 101 seconds.
     jetstream,  # Take 206 seconds.
+    jetstream2, # Causes CQ shard to timeout, crbug.com/992837
     v8_browsing, # Flaky on Android, crbug.com/628368.
 }
 
diff --git a/ui/accessibility/ax_node_position_unittest.cc b/ui/accessibility/ax_node_position_unittest.cc
index 64c03487..f92f31d 100644
--- a/ui/accessibility/ax_node_position_unittest.cc
+++ b/ui/accessibility/ax_node_position_unittest.cc
@@ -49,13 +49,13 @@
  protected:
   void SetUp() override;
   void TearDown() override;
-  AXTree* CreateMultipageDocument(ui::AXNodeData& root_data,
-                                  ui::AXNodeData& page_1_data,
-                                  ui::AXNodeData& page_1_text_data,
-                                  ui::AXNodeData& page_2_data,
-                                  ui::AXNodeData& page_2_text_data,
-                                  ui::AXNodeData& page_3_data,
-                                  ui::AXNodeData& page_3_text_data) {
+  AXTree* CreateMultipageDocument(AXNodeData& root_data,
+                                  AXNodeData& page_1_data,
+                                  AXNodeData& page_1_text_data,
+                                  AXNodeData& page_2_data,
+                                  AXNodeData& page_2_text_data,
+                                  AXNodeData& page_3_data,
+                                  AXNodeData& page_3_text_data) {
     AXNodePosition::SetTreeForTesting(nullptr);
 
     root_data.id = 1;
@@ -98,8 +98,8 @@
 
     root_data.child_ids = {2, 4, 6};
 
-    ui::AXTreeUpdate update;
-    ui::AXTreeData tree_data;
+    AXTreeUpdate update;
+    AXTreeData tree_data;
     AXTreeID new_id = AXTreeID::CreateNewAXTreeID();
     tree_data.tree_id = new_id;
     update.tree_data = tree_data;
@@ -127,17 +127,16 @@
 
   // Creates a new AXTree from a vector of nodes.
   // Assumes the first node in the vector is the root.
-  std::unique_ptr<AXTree> CreateAXTree(
-      const std::vector<ui::AXNodeData>& nodes) {
-    ui::AXTreeUpdate update;
-    ui::AXTreeData tree_data;
-    tree_data.tree_id = ui::AXTreeID::CreateNewAXTreeID();
+  std::unique_ptr<AXTree> CreateAXTree(const std::vector<AXNodeData>& nodes) {
+    AXTreeUpdate update;
+    AXTreeData tree_data;
+    tree_data.tree_id = AXTreeID::CreateNewAXTreeID();
     update.tree_data = tree_data;
     update.has_tree_data = true;
     update.root_id = nodes[0].id;
     update.nodes = nodes;
 
-    tree_data.tree_id = ui::AXTreeID::CreateNewAXTreeID();
+    tree_data.tree_id = AXTreeID::CreateNewAXTreeID();
     update.tree_data = tree_data;
     std::unique_ptr<AXTree> tree = std::make_unique<AXTree>(update);
     AXNodePosition::SetTreeForTesting(tree.get());
@@ -230,8 +229,6 @@
   button_.SetHasPopup(ax::mojom::HasPopup::kMenu);
   button_.SetName("Button");
   button_.relative_bounds.bounds = gfx::RectF(20, 20, 200, 30);
-  button_.AddIntAttribute(ax::mojom::IntAttribute::kNextOnLineId,
-                          check_box_.id);
   root_.child_ids.push_back(button_.id);
 
   check_box_.role = ax::mojom::Role::kCheckBox;
@@ -240,8 +237,6 @@
   check_box_.SetCheckedState(ax::mojom::CheckedState::kTrue);
   check_box_.SetName("Check box");
   check_box_.relative_bounds.bounds = gfx::RectF(20, 50, 200, 30);
-  check_box_.AddIntAttribute(ax::mojom::IntAttribute::kPreviousOnLineId,
-                             button_.id);
   root_.child_ids.push_back(check_box_.id);
 
   text_field_.role = ax::mojom::Role::kTextField;
@@ -525,16 +520,16 @@
 TEST_F(AXPositionTest, GetMaxTextOffsetUpdate) {
   AXNodePosition::SetTreeForTesting(nullptr);
 
-  ui::AXNodeData root_data;
+  AXNodeData root_data;
   root_data.id = 1;
   root_data.role = ax::mojom::Role::kRootWebArea;
 
-  ui::AXNodeData text_data;
+  AXNodeData text_data;
   text_data.id = 2;
   text_data.role = ax::mojom::Role::kStaticText;
   text_data.SetName("some text");
 
-  ui::AXNodeData more_text_data;
+  AXNodeData more_text_data;
   more_text_data.id = 3;
   more_text_data.role = ax::mojom::Role::kStaticText;
   more_text_data.SetName("more text");
@@ -937,41 +932,41 @@
   // ++++++++7 kInlineTextBox "more text"
   AXNodePosition::SetTreeForTesting(nullptr);
 
-  ui::AXNodeData root_data;
+  AXNodeData root_data;
   root_data.id = 1;
   root_data.role = ax::mojom::Role::kRootWebArea;
   root_data.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject,
                              true);
 
-  ui::AXNodeData static_text_data_1;
+  AXNodeData static_text_data_1;
   static_text_data_1.id = 2;
   static_text_data_1.role = ax::mojom::Role::kStaticText;
   static_text_data_1.SetName("some text");
 
-  ui::AXNodeData some_text_data;
+  AXNodeData some_text_data;
   some_text_data.id = 3;
   some_text_data.role = ax::mojom::Role::kInlineTextBox;
   some_text_data.SetName("some text");
 
-  ui::AXNodeData container_data;
+  AXNodeData container_data;
   container_data.id = 4;
   container_data.role = ax::mojom::Role::kGenericContainer;
   container_data.AddBoolAttribute(
       ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
 
-  ui::AXNodeData static_text_data_2;
+  AXNodeData static_text_data_2;
   static_text_data_2.id = 5;
   static_text_data_2.role = ax::mojom::Role::kStaticText;
   static_text_data_2.SetName("\nmore text");
 
-  ui::AXNodeData preserved_newline_data;
+  AXNodeData preserved_newline_data;
   preserved_newline_data.id = 6;
   preserved_newline_data.role = ax::mojom::Role::kInlineTextBox;
   preserved_newline_data.SetName("\n");
   preserved_newline_data.AddBoolAttribute(
       ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
 
-  ui::AXNodeData more_text_data;
+  AXNodeData more_text_data;
   more_text_data.id = 7;
   more_text_data.role = ax::mojom::Role::kInlineTextBox;
   more_text_data.SetName("more text");
@@ -981,19 +976,9 @@
   static_text_data_2.child_ids = {6, 7};
   root_data.child_ids = {2, 4};
 
-  ui::AXTreeUpdate update;
-  ui::AXTreeData tree_data;
-  tree_data.tree_id = ui::AXTreeID::CreateNewAXTreeID();
-  update.tree_data = tree_data;
-  update.has_tree_data = true;
-  update.root_id = root_data.id;
-  update.nodes = {root_data,      static_text_data_1, some_text_data,
-                  container_data, static_text_data_2, preserved_newline_data,
-                  more_text_data};
-
-  std::unique_ptr<AXTree> new_tree;
-  new_tree.reset(new AXTree(update));
-  AXNodePosition::SetTreeForTesting(new_tree.get());
+  std::unique_ptr<AXTree> new_tree = CreateAXTree(
+      {root_data, static_text_data_1, some_text_data, container_data,
+       static_text_data_2, preserved_newline_data, more_text_data});
 
   TestPositionType text_position1 = AXNodePosition::CreateTextPosition(
       new_tree->data().tree_id, root_data.id, 8 /* text_offset */,
@@ -1099,68 +1084,68 @@
   // ++++++++12 kInlineTextBox "\n" isLineBreakingObject
   AXNodePosition::SetTreeForTesting(nullptr);
 
-  ui::AXNodeData root_data;
+  AXNodeData root_data;
   root_data.id = 1;
   root_data.role = ax::mojom::Role::kRootWebArea;
   root_data.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject,
                              true);
 
-  ui::AXNodeData container_data_a;
+  AXNodeData container_data_a;
   container_data_a.id = 2;
   container_data_a.role = ax::mojom::Role::kGenericContainer;
   container_data_a.AddBoolAttribute(
       ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
 
-  ui::AXNodeData static_text_data_a;
+  AXNodeData static_text_data_a;
   static_text_data_a.id = 3;
   static_text_data_a.role = ax::mojom::Role::kStaticText;
   static_text_data_a.SetName("\n");
 
-  ui::AXNodeData inline_text_data_a;
+  AXNodeData inline_text_data_a;
   inline_text_data_a.id = 4;
   inline_text_data_a.role = ax::mojom::Role::kInlineTextBox;
   inline_text_data_a.SetName("\n");
   inline_text_data_a.AddBoolAttribute(
       ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
 
-  ui::AXNodeData container_data_b;
+  AXNodeData container_data_b;
   container_data_b.id = 5;
   container_data_b.role = ax::mojom::Role::kGenericContainer;
   container_data_b.AddBoolAttribute(
       ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
 
-  ui::AXNodeData static_text_data_b;
+  AXNodeData static_text_data_b;
   static_text_data_b.id = 6;
   static_text_data_b.role = ax::mojom::Role::kStaticText;
   static_text_data_b.SetName("some text");
 
-  ui::AXNodeData inline_text_data_b_1;
+  AXNodeData inline_text_data_b_1;
   inline_text_data_b_1.id = 7;
   inline_text_data_b_1.role = ax::mojom::Role::kInlineTextBox;
   inline_text_data_b_1.SetName("some");
 
-  ui::AXNodeData inline_text_data_b_2;
+  AXNodeData inline_text_data_b_2;
   inline_text_data_b_2.id = 8;
   inline_text_data_b_2.role = ax::mojom::Role::kInlineTextBox;
   inline_text_data_b_2.SetName(" ");
 
-  ui::AXNodeData inline_text_data_b_3;
+  AXNodeData inline_text_data_b_3;
   inline_text_data_b_3.id = 9;
   inline_text_data_b_3.role = ax::mojom::Role::kInlineTextBox;
   inline_text_data_b_3.SetName("text");
 
-  ui::AXNodeData container_data_c;
+  AXNodeData container_data_c;
   container_data_c.id = 10;
   container_data_c.role = ax::mojom::Role::kGenericContainer;
   container_data_c.AddBoolAttribute(
       ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
 
-  ui::AXNodeData static_text_data_c;
+  AXNodeData static_text_data_c;
   static_text_data_c.id = 11;
   static_text_data_c.role = ax::mojom::Role::kStaticText;
   static_text_data_c.SetName("\n");
 
-  ui::AXNodeData inline_text_data_c;
+  AXNodeData inline_text_data_c;
   inline_text_data_c.id = 12;
   inline_text_data_c.role = ax::mojom::Role::kInlineTextBox;
   inline_text_data_c.SetName("\n");
@@ -1178,28 +1163,11 @@
   container_data_c.child_ids = {static_text_data_c.id};
   static_text_data_c.child_ids = {inline_text_data_c.id};
 
-  ui::AXTreeUpdate update;
-  ui::AXTreeData tree_data;
-  tree_data.tree_id = ui::AXTreeID::CreateNewAXTreeID();
-  update.tree_data = tree_data;
-  update.has_tree_data = true;
-  update.root_id = root_data.id;
-  update.nodes = {root_data,
-                  container_data_a,
-                  container_data_b,
-                  container_data_c,
-                  static_text_data_a,
-                  static_text_data_b,
-                  static_text_data_c,
-                  inline_text_data_a,
-                  inline_text_data_b_1,
-                  inline_text_data_b_2,
-                  inline_text_data_b_3,
-                  inline_text_data_c};
-
-  std::unique_ptr<AXTree> new_tree;
-  new_tree.reset(new AXTree(update));
-  AXNodePosition::SetTreeForTesting(new_tree.get());
+  std::unique_ptr<AXTree> new_tree = CreateAXTree(
+      {root_data, container_data_a, container_data_b, container_data_c,
+       static_text_data_a, static_text_data_b, static_text_data_c,
+       inline_text_data_a, inline_text_data_b_1, inline_text_data_b_2,
+       inline_text_data_b_3, inline_text_data_c});
 
   TestPositionType text_position1 = AXNodePosition::CreateTextPosition(
       new_tree->data().tree_id, inline_text_data_a.id, 0 /* text_offset */,
@@ -1989,17 +1957,8 @@
 
   root_data.child_ids = {text_data.id, more_text_data.id};
 
-  AXTreeUpdate update;
-  AXTreeData tree_data;
-  tree_data.tree_id = AXTreeID::CreateNewAXTreeID();
-  update.tree_data = tree_data;
-  update.has_tree_data = true;
-  update.root_id = root_data.id;
-  update.nodes = {root_data, text_data, more_text_data};
-
-  std::unique_ptr<AXTree> new_tree;
-  new_tree.reset(new AXTree(update));
-  AXNodePosition::SetTreeForTesting(new_tree.get());
+  std::unique_ptr<AXTree> new_tree =
+      CreateAXTree({root_data, text_data, more_text_data});
 
   // Test CreatePreviousFormatStartPosition at the start of the document.
   TestPositionType text_position = AXNodePosition::CreateTextPosition(
@@ -2025,16 +1984,14 @@
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(more_text_data.id, test_position->anchor_id());
   EXPECT_EQ(9, test_position->text_offset());
-
-  AXNodePosition::SetTreeForTesting(&tree_);
 }
 
 TEST_F(AXPositionTest, CreatePositionAtPageBoundaryWithTextPosition) {
   AXNodePosition::SetTreeForTesting(nullptr);
 
-  ui::AXNodeData root_data, page_1_data, page_1_text_data, page_2_data,
+  AXNodeData root_data, page_1_data, page_1_text_data, page_2_data,
       page_2_text_data, page_3_data, page_3_text_data;
-  std::unique_ptr<ui::AXTree> new_tree(CreateMultipageDocument(
+  std::unique_ptr<AXTree> new_tree(CreateMultipageDocument(
       root_data, page_1_data, page_1_text_data, page_2_data, page_2_text_data,
       page_3_data, page_3_text_data));
   AXNodePosition::SetTreeForTesting(new_tree.get());
@@ -2150,15 +2107,14 @@
       AXBoundaryBehavior::CrossBoundary);
   EXPECT_NE(nullptr, null_position);
   EXPECT_TRUE(null_position->IsNullPosition());
-
-  AXNodePosition::SetTreeForTesting(&tree_);
 }
 
 TEST_F(AXPositionTest, CreatePositionAtPageBoundaryWithTreePosition) {
   AXNodePosition::SetTreeForTesting(nullptr);
-  ui::AXNodeData root_data, page_1_data, page_1_text_data, page_2_data,
+
+  AXNodeData root_data, page_1_data, page_1_text_data, page_2_data,
       page_2_text_data, page_3_data, page_3_text_data;
-  std::unique_ptr<ui::AXTree> new_tree(CreateMultipageDocument(
+  std::unique_ptr<AXTree> new_tree(CreateMultipageDocument(
       root_data, page_1_data, page_1_text_data, page_2_data, page_2_text_data,
       page_3_data, page_3_text_data));
   AXNodePosition::SetTreeForTesting(new_tree.get());
@@ -2273,8 +2229,6 @@
       AXBoundaryBehavior::CrossBoundary);
   EXPECT_NE(nullptr, null_position);
   EXPECT_TRUE(null_position->IsNullPosition());
-
-  AXNodePosition::SetTreeForTesting(&tree_);
 }
 
 TEST_F(AXPositionTest, CreatePagePositionWithNullPosition) {
@@ -3739,18 +3693,8 @@
   root_data.child_ids = {text_data.id, text_field_data.id, more_text_data.id};
   text_field_data.child_ids = {empty_text_data.id};
 
-  AXTreeUpdate update;
-  AXTreeData tree_data;
-  tree_data.tree_id = AXTreeID::CreateNewAXTreeID();
-  update.tree_data = tree_data;
-  update.has_tree_data = true;
-  update.root_id = root_data.id;
-  update.nodes = {root_data, text_data, text_field_data, empty_text_data,
-                  more_text_data};
-
-  std::unique_ptr<AXTree> new_tree;
-  new_tree.reset(new AXTree(update));
-  AXNodePosition::SetTreeForTesting(new_tree.get());
+  std::unique_ptr<AXTree> new_tree = CreateAXTree(
+      {root_data, text_data, text_field_data, empty_text_data, more_text_data});
 
   // Test that CreateNextAnchorPosition will successfully navigate past the
   // empty text field.
@@ -3761,8 +3705,140 @@
   ASSERT_FALSE(text_position1->CreateNextAnchorPosition()
                    ->CreateNextAnchorPosition()
                    ->IsNullPosition());
+}
 
-  AXNodePosition::SetTreeForTesting(&tree_);
+TEST_F(AXPositionTest, CreateLinePositionsMultipleAnchorsInSingleLine) {
+  // This test updates the tree structure to test a specific edge case -
+  // Create next and previous line start/end positions on a single line composed
+  // by multiple anchors; only two line boundaries should be resolved: either
+  // the start of the "before" text or at the end of "after".
+  // ++1 kRootWebArea
+  // ++++2 kStaticText
+  // ++++++3 kInlineTextBox "before" kNextOnLineId=6
+  // ++++4 kGenericContainer
+  // ++++++5 kStaticText
+  // ++++++++6 kInlineTextBox "inside" kPreviousOnLineId=3 kNextOnLineId=8
+  // ++++7 kStaticText
+  // ++++++8 kInlineTextBox "after" kPreviousOnLineId=6
+  AXNodePosition::SetTreeForTesting(nullptr);
+
+  AXNodeData root;
+  AXNodeData inline_box1;
+  AXNodeData inline_box2;
+  AXNodeData inline_box3;
+  AXNodeData inline_block;
+  AXNodeData static_text1;
+  AXNodeData static_text2;
+  AXNodeData static_text3;
+
+  root.id = 1;
+  static_text1.id = 2;
+  inline_box1.id = 3;
+  inline_block.id = 4;
+  static_text2.id = 5;
+  inline_box2.id = 6;
+  static_text3.id = 7;
+  inline_box3.id = 8;
+
+  root.role = ax::mojom::Role::kRootWebArea;
+  root.child_ids = {static_text1.id, inline_block.id, static_text3.id};
+
+  static_text1.role = ax::mojom::Role::kStaticText;
+  static_text1.SetName("before");
+  static_text1.child_ids = {inline_box1.id};
+
+  inline_box1.role = ax::mojom::Role::kInlineTextBox;
+  inline_box1.SetName("before");
+  inline_box1.AddIntAttribute(ax::mojom::IntAttribute::kNextOnLineId,
+                              inline_box2.id);
+
+  inline_block.role = ax::mojom::Role::kGenericContainer;
+  inline_block.child_ids = {static_text2.id};
+
+  static_text2.role = ax::mojom::Role::kStaticText;
+  static_text2.SetName("inside");
+  static_text2.child_ids = {inline_box2.id};
+
+  inline_box2.role = ax::mojom::Role::kInlineTextBox;
+  inline_box2.SetName("inside");
+  inline_box2.AddIntAttribute(ax::mojom::IntAttribute::kPreviousOnLineId,
+                              inline_box1.id);
+  inline_box2.AddIntAttribute(ax::mojom::IntAttribute::kNextOnLineId,
+                              inline_box3.id);
+
+  static_text3.role = ax::mojom::Role::kStaticText;
+  static_text3.SetName("after");
+  static_text3.child_ids = {inline_box3.id};
+
+  inline_box3.role = ax::mojom::Role::kInlineTextBox;
+  inline_box3.SetName("after");
+  inline_box3.AddIntAttribute(ax::mojom::IntAttribute::kPreviousOnLineId,
+                              inline_box2.id);
+
+  std::unique_ptr<AXTree> new_tree =
+      CreateAXTree({root, static_text1, inline_box1, inline_block, static_text2,
+                    inline_box2, static_text3, inline_box3});
+
+  TestPositionType text_position = AXNodePosition::CreateTextPosition(
+      new_tree->data().tree_id, inline_block.id, 3 /* text_offset */,
+      ax::mojom::TextAffinity::kDownstream);
+  ASSERT_NE(nullptr, text_position);
+  ASSERT_TRUE(text_position->IsTextPosition());
+
+  TestPositionType next_line_start_position =
+      text_position->CreateNextLineStartPosition(
+          AXBoundaryBehavior::CrossBoundary);
+  ASSERT_NE(nullptr, next_line_start_position);
+  EXPECT_TRUE(next_line_start_position->IsTextPosition());
+  EXPECT_EQ(inline_box3.id, next_line_start_position->anchor_id());
+  EXPECT_EQ(5, next_line_start_position->text_offset());
+
+  next_line_start_position =
+      next_line_start_position->CreateNextLineStartPosition(
+          AXBoundaryBehavior::CrossBoundary);
+  ASSERT_NE(nullptr, next_line_start_position);
+  EXPECT_TRUE(next_line_start_position->IsNullPosition());
+
+  TestPositionType previous_line_start_position =
+      text_position->CreatePreviousLineStartPosition(
+          AXBoundaryBehavior::CrossBoundary);
+  ASSERT_NE(nullptr, previous_line_start_position);
+  EXPECT_TRUE(previous_line_start_position->IsTextPosition());
+  EXPECT_EQ(inline_box1.id, previous_line_start_position->anchor_id());
+  EXPECT_EQ(0, previous_line_start_position->text_offset());
+
+  previous_line_start_position =
+      previous_line_start_position->CreatePreviousLineStartPosition(
+          AXBoundaryBehavior::CrossBoundary);
+  ASSERT_NE(nullptr, previous_line_start_position);
+  EXPECT_TRUE(previous_line_start_position->IsNullPosition());
+
+  TestPositionType next_line_end_position =
+      text_position->CreateNextLineEndPosition(
+          AXBoundaryBehavior::CrossBoundary);
+  ASSERT_NE(nullptr, next_line_end_position);
+  EXPECT_TRUE(next_line_end_position->IsTextPosition());
+  EXPECT_EQ(inline_box3.id, next_line_end_position->anchor_id());
+  EXPECT_EQ(5, next_line_end_position->text_offset());
+
+  next_line_end_position = next_line_end_position->CreateNextLineEndPosition(
+      AXBoundaryBehavior::CrossBoundary);
+  ASSERT_NE(nullptr, next_line_end_position);
+  EXPECT_TRUE(next_line_end_position->IsNullPosition());
+
+  TestPositionType previous_line_end_position =
+      text_position->CreatePreviousLineEndPosition(
+          AXBoundaryBehavior::CrossBoundary);
+  ASSERT_NE(nullptr, previous_line_end_position);
+  EXPECT_TRUE(previous_line_end_position->IsTextPosition());
+  EXPECT_EQ(inline_box1.id, previous_line_end_position->anchor_id());
+  EXPECT_EQ(0, previous_line_end_position->text_offset());
+
+  previous_line_end_position =
+      previous_line_end_position->CreatePreviousLineEndPosition(
+          AXBoundaryBehavior::CrossBoundary);
+  ASSERT_NE(nullptr, previous_line_end_position);
+  EXPECT_TRUE(previous_line_end_position->IsNullPosition());
 }
 
 //
@@ -4853,7 +4929,7 @@
                   {"TextPosition anchor_id=1 text_offset=6 "
                    "affinity=downstream annotated_text=Line 1<\n>Line 2",
                    "TextPosition anchor_id=1 text_offset=0 "
-                   "affinity=downstream annotated_text=<L>ine 1\nLine 2",
+                   "affinity=upstream annotated_text=<L>ine 1\nLine 2",
                    "NullPosition"}},
         TestParam{base::BindRepeating([](const TestPositionType& position) {
                     return position->CreatePreviousLineEndPosition(
@@ -4863,8 +4939,8 @@
                   13 /* text_offset at end of text field */,
                   {"TextPosition anchor_id=4 text_offset=6 "
                    "affinity=downstream annotated_text=Line 1<\n>Line 2",
-                   "TextPosition anchor_id=4 text_offset=0 "
-                   "affinity=downstream annotated_text=<L>ine 1\nLine 2",
+                   "TextPosition anchor_id=2 text_offset=0 "
+                   "affinity=downstream annotated_text=<>",
                    "NullPosition"}},
         TestParam{base::BindRepeating([](const TestPositionType& position) {
                     return position->CreatePreviousLineEndPosition(
@@ -4873,7 +4949,7 @@
                   ROOT_ID,
                   5 /* text_offset on the last character of "Line 1". */,
                   {"TextPosition anchor_id=1 text_offset=0 "
-                   "affinity=downstream annotated_text=<L>ine 1\nLine 2",
+                   "affinity=upstream annotated_text=<L>ine 1\nLine 2",
                    "NullPosition"}},
         TestParam{base::BindRepeating([](const TestPositionType& position) {
                     return position->CreatePreviousLineEndPosition(
@@ -4881,8 +4957,8 @@
                   }),
                   TEXT_FIELD_ID,
                   5 /* text_offset on the last character of "Line 1". */,
-                  {"TextPosition anchor_id=4 text_offset=0 "
-                   "affinity=downstream annotated_text=<L>ine 1\nLine 2",
+                  {"TextPosition anchor_id=2 text_offset=0 "
+                   "affinity=downstream annotated_text=<>",
                    "NullPosition"}},
         TestParam{base::BindRepeating([](const TestPositionType& position) {
                     return position->CreatePreviousLineEndPosition(
@@ -4892,8 +4968,8 @@
                   4 /* text_offset */,
                   {"TextPosition anchor_id=6 text_offset=6 "
                    "affinity=downstream annotated_text=Line 1<>",
-                   "TextPosition anchor_id=6 text_offset=0 "
-                   "affinity=downstream annotated_text=<L>ine 1",
+                   "TextPosition anchor_id=2 text_offset=0 "
+                   "affinity=downstream annotated_text=<>",
                    "NullPosition"}},
         TestParam{base::BindRepeating([](const TestPositionType& position) {
                     return position->CreatePreviousLineEndPosition(
@@ -4903,8 +4979,8 @@
                   0 /* text_offset */,
                   {"TextPosition anchor_id=6 text_offset=6 "
                    "affinity=downstream annotated_text=Line 1<>",
-                   "TextPosition anchor_id=6 text_offset=0 "
-                   "affinity=downstream annotated_text=<L>ine 1",
+                   "TextPosition anchor_id=2 text_offset=0 "
+                   "affinity=downstream annotated_text=<>",
                    "NullPosition"}}));
 
 INSTANTIATE_TEST_SUITE_P(
diff --git a/ui/accessibility/ax_position.h b/ui/accessibility/ax_position.h
index 076d171..5f1bd11 100644
--- a/ui/accessibility/ax_position.h
+++ b/ui/accessibility/ax_position.h
@@ -1160,10 +1160,9 @@
     } while (boundary_behavior != AXBoundaryBehavior::StopIfAlreadyAtBoundary &&
              *this == *text_position);
 
-    // If the word boundary is in the same subtree, return a position rooted
-    // at the current position. This is necessary because we don't want to
-    // return any position that might be in the shadow DOM if the original
-    // position was not.
+    // If the word boundary is in the same subtree, return a position rooted at
+    // this position's anchor. This is necessary because we don't want to return
+    // a position that might be in the shadow DOM when this position is not.
     AXPositionInstance common_ancestor =
         text_position->LowestCommonAncestor(*this);
     if (GetAnchor() == common_ancestor->GetAnchor()) {
@@ -1223,10 +1222,9 @@
     } while (boundary_behavior != AXBoundaryBehavior::StopIfAlreadyAtBoundary &&
              *this == *text_position);
 
-    // If the word boundary is in the same subtree, return a position rooted
-    // at the current position. This is necessary because we don't want to
-    // return any position that might be in the shadow DOM if the original
-    // position was not.
+    // If the word boundary is in the same subtree, return a position rooted at
+    // this position's anchor. This is necessary because we don't want to return
+    // a position that might be in the shadow DOM when this position is not.
     AXPositionInstance common_ancestor =
         text_position->LowestCommonAncestor(*this);
     if (GetAnchor() == common_ancestor->GetAnchor()) {
@@ -1291,10 +1289,9 @@
     } while (boundary_behavior != AXBoundaryBehavior::StopIfAlreadyAtBoundary &&
              *this == *text_position);
 
-    // If the word boundary is in the same subtree, return a position rooted
-    // at the current position. This is necessary because we don't want to
-    // return any position that might be in the shadow DOM if the original
-    // position was not.
+    // If the word boundary is in the same subtree, return a position rooted at
+    // this position's anchor. This is necessary because we don't want to return
+    // a position that might be in the shadow DOM when this position is not.
     AXPositionInstance common_ancestor =
         text_position->LowestCommonAncestor(*this);
     if (GetAnchor() == common_ancestor->GetAnchor()) {
@@ -1361,10 +1358,9 @@
     } while (boundary_behavior != AXBoundaryBehavior::StopIfAlreadyAtBoundary &&
              *this == *text_position);
 
-    // If the word boundary is in the same subtree, return a position rooted
-    // at the current position. This is necessary because we don't want to
-    // return any position that might be in the shadow DOM if the original
-    // position was not.
+    // If the word boundary is in the same subtree, return a position rooted at
+    // this position's anchor. This is necessary because we don't want to return
+    // a position that might be in the shadow DOM when this position is not.
     AXPositionInstance common_ancestor =
         text_position->LowestCommonAncestor(*this);
     if (GetAnchor() == common_ancestor->GetAnchor()) {
@@ -1384,6 +1380,7 @@
     AXPositionInstance text_position = AsLeafTextPosition();
     if (text_position->IsNullPosition())
       return text_position;
+
     if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary &&
         text_position->AtStartOfLine()) {
       AXPositionInstance clone = Clone();
@@ -1392,25 +1389,32 @@
     }
 
     do {
-      text_position = text_position->CreateNextLeafTextPosition();
-      if (text_position->IsNullPosition()) {
-        if (AtEndOfAnchor() &&
-            boundary_behavior == AXBoundaryBehavior::CrossBoundary)
-          return text_position;
+      AXPositionInstance next_position =
+          text_position->CreateNextLeafTextPosition();
+
+      if (next_position->IsNullPosition()) {
+        if (boundary_behavior == AXBoundaryBehavior::CrossBoundary) {
+          if (AtEndOfAnchor())
+            return next_position;
+          // We can't simply return the following position; break and after this
+          // loop we'll try to do some adjustments to the result position.
+          text_position = text_position->CreatePositionAtEndOfAnchor();
+          break;
+        }
         return CreatePositionAtEndOfAnchor();
       }
 
       // Continue searching for the next line start until the next logical text
       // position is reached.
+      text_position = std::move(next_position);
     } while (
         !text_position->AtStartOfLine() ||
         (boundary_behavior != AXBoundaryBehavior::StopIfAlreadyAtBoundary &&
          *this == *text_position));
 
     // If the line boundary is in the same subtree, return a position rooted at
-    // the current position.
-    // This is necessary because we don't want to return any position that might
-    // be in the shadow DOM if the original position was not.
+    // this position's anchor. This is necessary because we don't want to return
+    // a position that might be in the shadow DOM when this position is not.
     AXPositionInstance common_ancestor =
         text_position->LowestCommonAncestor(*this);
     if (GetAnchor() == common_ancestor->GetAnchor()) {
@@ -1428,6 +1432,9 @@
       AXBoundaryBehavior boundary_behavior) const {
     bool was_tree_position = IsTreePosition();
     AXPositionInstance text_position = AsLeafTextPosition();
+    if (text_position->IsNullPosition())
+      return text_position;
+
     if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary &&
         text_position->AtStartOfLine()) {
       AXPositionInstance clone = Clone();
@@ -1436,11 +1443,9 @@
     }
 
     do {
-      if (text_position->AtStartOfAnchor()) {
-        text_position = text_position->CreatePreviousLeafTextPosition();
-      } else {
-        text_position = text_position->CreatePositionAtStartOfAnchor();
-      }
+      text_position = text_position->AtStartOfAnchor()
+                          ? text_position->CreatePreviousLeafTextPosition()
+                          : text_position->CreatePositionAtStartOfAnchor();
 
       if (text_position->IsNullPosition()) {
         if (boundary_behavior == AXBoundaryBehavior::StopAtAnchorBoundary)
@@ -1456,9 +1461,8 @@
          *this == *text_position));
 
     // If the line boundary is in the same subtree, return a position rooted at
-    // the current position.
-    // This is necessary because we don't want to return any position that might
-    // be in the shadow DOM if the original position was not.
+    // this position's anchor. This is necessary because we don't want to return
+    // a position that might be in the shadow DOM when this position is not.
     AXPositionInstance common_ancestor =
         text_position->LowestCommonAncestor(*this);
     if (GetAnchor() == common_ancestor->GetAnchor()) {
@@ -1478,6 +1482,9 @@
       AXBoundaryBehavior boundary_behavior) const {
     bool was_tree_position = IsTreePosition();
     AXPositionInstance text_position = AsLeafTextPosition();
+    if (text_position->IsNullPosition())
+      return text_position;
+
     if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary &&
         text_position->AtEndOfLine()) {
       AXPositionInstance clone = Clone();
@@ -1492,12 +1499,9 @@
     }
 
     do {
-      if (text_position->AtEndOfAnchor()) {
-        text_position = text_position->CreateNextLeafTextPosition()
-                            ->CreatePositionAtEndOfAnchor();
-      } else {
-        text_position = text_position->CreatePositionAtEndOfAnchor();
-      }
+      if (text_position->AtEndOfAnchor())
+        text_position = text_position->CreateNextLeafTextPosition();
+      text_position = text_position->CreatePositionAtEndOfAnchor();
 
       if (text_position->IsNullPosition()) {
         if (boundary_behavior == AXBoundaryBehavior::StopAtAnchorBoundary)
@@ -1513,9 +1517,8 @@
          *this == *text_position));
 
     // If the line boundary is in the same subtree, return a position rooted at
-    // the current position. This is necessary because we don't want to return
-    // any position that might be in the shadow DOM if the original position was
-    // not.
+    // this position's anchor. This is necessary because we don't want to return
+    // a position that might be in the shadow DOM when this position is not.
     AXPositionInstance common_ancestor =
         text_position->LowestCommonAncestor(*this);
     if (GetAnchor() == common_ancestor->GetAnchor()) {
@@ -1537,6 +1540,7 @@
     AXPositionInstance text_position = AsLeafTextPosition();
     if (text_position->IsNullPosition())
       return text_position;
+
     if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary &&
         text_position->AtEndOfLine()) {
       AXPositionInstance clone = Clone();
@@ -1551,26 +1555,33 @@
     }
 
     do {
-      text_position = text_position->CreatePreviousLeafTextPosition()
-                          ->CreatePositionAtEndOfAnchor();
-      if (text_position->IsNullPosition()) {
-        if (AtStartOfAnchor() &&
-            boundary_behavior == AXBoundaryBehavior::CrossBoundary)
-          return text_position;
+      AXPositionInstance previous_position =
+          text_position->CreatePreviousLeafTextPosition()
+              ->CreatePositionAtEndOfAnchor();
+
+      if (previous_position->IsNullPosition()) {
+        if (boundary_behavior == AXBoundaryBehavior::CrossBoundary) {
+          if (AtStartOfAnchor())
+            return previous_position;
+          // We can't simply return the following position; break and after this
+          // loop we'll try to do some adjustments to the result position.
+          text_position = text_position->CreatePositionAtStartOfAnchor();
+          break;
+        }
         return CreatePositionAtStartOfAnchor();
       }
 
       // Continue searching for the previous line end until the next logical
       // text position is reached.
+      text_position = std::move(previous_position);
     } while (
         !text_position->AtEndOfLine() ||
         (boundary_behavior != AXBoundaryBehavior::StopIfAlreadyAtBoundary &&
          *this == *text_position));
 
     // If the line boundary is in the same subtree, return a position rooted at
-    // the current position. This is necessary because we don't want to return
-    // any position that might be in the shadow DOM if the original position was
-    // not.
+    // this position's anchor. This is necessary because we don't want to return
+    // a position that might be in the shadow DOM when this position is not.
     AXPositionInstance common_ancestor =
         text_position->LowestCommonAncestor(*this);
     if (GetAnchor() == common_ancestor->GetAnchor()) {
@@ -1670,10 +1681,9 @@
         (boundary_behavior != AXBoundaryBehavior::StopIfAlreadyAtBoundary &&
          *this == *text_position));
 
-    // If the boundary is in the same subtree, return a position rooted at the
-    // current position. This is necessary because we don't want to return any
-    // position that might be in the shadow DOM if the original position was
-    // not.
+    // If the boundary is in the same subtree, return a position rooted at this
+    // position's anchor. This is necessary because we don't want to return a
+    // position that might be in the shadow DOM when this position is not.
     AXPositionInstance common_ancestor =
         text_position->LowestCommonAncestor(*this);
     if (GetAnchor() == common_ancestor->GetAnchor()) {
@@ -1713,17 +1723,16 @@
         return text_position;
       }
 
-      // Continue searching for the previous page start until the next
+      // Continue searching for the previous boundary start until the next
       // logical text position is reached.
     } while (
         !at_start_condition.Run(text_position) ||
         (boundary_behavior != AXBoundaryBehavior::StopIfAlreadyAtBoundary &&
          *this == *text_position));
 
-    // If the boundary is in the same subtree, return a position rooted at the
-    // current position. This is necessary because we don't want to return any
-    // position that might be in the shadow DOM if the original position was
-    // not.
+    // If the boundary is in the same subtree, return a position rooted at this
+    // position's anchor. This is necessary because we don't want to return a
+    // position that might be in the shadow DOM when this position is not.
     AXPositionInstance common_ancestor =
         text_position->LowestCommonAncestor(*this);
     if (GetAnchor() == common_ancestor->GetAnchor()) {
@@ -1777,10 +1786,9 @@
         (boundary_behavior != AXBoundaryBehavior::StopIfAlreadyAtBoundary &&
          *this == *text_position));
 
-    // If the boundary is in the same subtree, return a position rooted at the
-    // current position. This is necessary because we don't want to return any
-    // position that might be in the shadow DOM if the original position was
-    // not.
+    // If the boundary is in the same subtree, return a position rooted at this
+    // position's anchor. This is necessary because we don't want to return a
+    // position that might be in the shadow DOM when this position is not.
     AXPositionInstance common_ancestor =
         text_position->LowestCommonAncestor(*this);
     if (GetAnchor() == common_ancestor->GetAnchor()) {
@@ -1831,10 +1839,9 @@
         (boundary_behavior != AXBoundaryBehavior::StopIfAlreadyAtBoundary &&
          *this == *text_position));
 
-    // If the boundary is in the same subtree, return a position rooted at the
-    // current position. This is necessary because we don't want to return any
-    // position that might be in the shadow DOM if the original position was
-    // not.
+    // If the boundary is in the same subtree, return a position rooted at this
+    // position's anchor. This is necessary because we don't want to return a
+    // position that might be in the shadow DOM when this position is not.
     AXPositionInstance common_ancestor =
         text_position->LowestCommonAncestor(*this);
     if (GetAnchor() == common_ancestor->GetAnchor()) {
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
index 7f32ce0..feb79f4 100644
--- a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
@@ -2725,8 +2725,8 @@
   // <button>Button</button><input type="checkbox">Line 1<br>Line 2
   // |---------------------||---------------------|
   ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit(
-      TextPatternRangeEndpoint_End, TextUnit_Line, /*count*/ -1, &count));
-  ASSERT_EQ(-1, count);
+      TextPatternRangeEndpoint_End, TextUnit_Word, /*count*/ -2, &count));
+  ASSERT_EQ(-2, count);
   EXPECT_HRESULT_SUCCEEDED(
       text_range_provider->GetBoundingRectangles(rectangles.Receive()));
   expected_values = {20, 20, 200, 30, /* button */
diff --git a/ui/android/java/res/values/color_palette.xml b/ui/android/java/res/values/color_palette.xml
index 7bf330e..7c44f37 100644
--- a/ui/android/java/res/values/color_palette.xml
+++ b/ui/android/java/res/values/color_palette.xml
@@ -20,16 +20,16 @@
     <color name="modern_grey_900">#202124</color>
     <color name="modern_grey_900_alpha_38" tools:ignore="UnusedResources">#61202124</color>
 
-    <color name="modern_grey_900_with_grey_200_alpha_4">#292A2D</color>
-    <color name="modern_grey_900_with_grey_200_alpha_6">#303134</color>
-    <color name="modern_grey_900_with_grey_200_alpha_8">#35363A</color>
-    <color name="modern_grey_900_with_grey_200_alpha_10">#38383C</color>
+    <color name="modern_grey_900_with_grey_200_alpha_5">#292A2D</color>
+    <color name="modern_grey_900_with_grey_200_alpha_8">#303134</color>
+    <color name="modern_grey_900_with_grey_200_alpha_11">#35363A</color>
+    <color name="modern_grey_900_with_grey_200_alpha_12">#38383C</color>
 
     <color name="black_alpha_38" tools:ignore="UnusedResources">#61000000</color>
 
     <color name="white_alpha_10" tools:ignore="UnusedResources">#1AFFFFFF</color>
     <color name="white_alpha_12" tools:ignore="UnusedResources">#1FFFFFFF</color>
-    <color name="white_alpha_20">#33FFFFFF</color>
+    <color name="white_alpha_20" tools:ignore="UnusedResources">#33FFFFFF</color>
     <color name="white_alpha_38" tools:ignore="UnusedResources">#61FFFFFF</color>
     <color name="white_alpha_50" tools:ignore="UnusedResources">#80FFFFFF</color>
     <color name="white_alpha_70">#B3FFFFFF</color>
@@ -48,14 +48,14 @@
         @android:color/white
     </color>
     <color name="default_icon_color_white_disabled" tools:ignore="UnusedResources">
-        @color/white_alpha_20
+        @color/white_alpha_50
     </color>
     <color name="default_icon_color_white_pressed" tools:ignore="UnusedResources">
         @color/white_alpha_50
     </color>
 
     <color name="default_icon_color_secondary_dark">@color/modern_grey_600</color>
-    <color name="default_icon_color_secondary_light">@color/modern_grey_500</color>
+    <color name="default_icon_color_secondary_light">@color/white_alpha_70</color>
 
     <!-- Common text colors -->
     <color name="default_text_color_dark">@color/modern_grey_900</color>
@@ -77,16 +77,16 @@
         @color/modern_grey_900
     </color>
     <color name="default_bg_color_dark_elev_1" tools:ignore="UnusedResources">
-        @color/modern_grey_900_with_grey_200_alpha_4
+        @color/modern_grey_900_with_grey_200_alpha_5
     </color>
     <color name="default_bg_color_dark_elev_2" tools:ignore="UnusedResources">
-        @color/modern_grey_900_with_grey_200_alpha_6
-    </color>
-    <color name="default_bg_color_dark_elev_3" tools:ignore="UnusedResources">
         @color/modern_grey_900_with_grey_200_alpha_8
     </color>
+    <color name="default_bg_color_dark_elev_3" tools:ignore="UnusedResources">
+        @color/modern_grey_900_with_grey_200_alpha_11
+    </color>
     <color name="default_bg_color_dark_elev_4" tools:ignore="UnusedResources">
-        @color/modern_grey_900_with_grey_200_alpha_10
+        @color/modern_grey_900_with_grey_200_alpha_12
     </color>
     <color name="divider_bg_color_dark">@color/modern_grey_300</color>
     <color name="divider_bg_color_light">@color/white_alpha_12</color>
diff --git a/ui/android/java/res_night/values-night/colors.xml b/ui/android/java/res_night/values-night/colors.xml
index 26624138..133b5f2 100644
--- a/ui/android/java/res_night/values-night/colors.xml
+++ b/ui/android/java/res_night/values-night/colors.xml
@@ -8,7 +8,7 @@
     <color name="default_text_color">@color/default_text_color_light</color>
     <color name="default_text_color_inverse">@color/default_text_color_dark</color>
     <color name="default_text_color_secondary">@color/white_alpha_70</color>
-    <color name="default_text_color_tertiary">@color/white_alpha_38</color>
+    <color name="default_text_color_tertiary">@color/white_alpha_50</color>
     <color name="default_text_color_blue">@color/modern_blue_300</color>
     <color name="default_text_color_link">@color/modern_blue_300</color>
     <color name="disabled_text_color_link">@color/modern_grey_300_alpha_38</color>
diff --git a/ui/aura/client/aura_constants.cc b/ui/aura/client/aura_constants.cc
index 5826c67..079633f 100644
--- a/ui/aura/client/aura_constants.cc
+++ b/ui/aura/client/aura_constants.cc
@@ -70,7 +70,6 @@
                              kPreFullscreenShowStateKey,
                              ui::SHOW_STATE_DEFAULT)
 DEFINE_UI_CLASS_PROPERTY_KEY(int, kResizeBehaviorKey, kResizeBehaviorCanResize)
-DEFINE_UI_CLASS_PROPERTY_KEY(int, kResizeHandleInset, 0)
 DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::Rect, kRestoreBoundsKey, nullptr)
 DEFINE_UI_CLASS_PROPERTY_KEY(ui::WindowShowState,
                              kShowStateKey,
diff --git a/ui/aura/client/aura_constants.h b/ui/aura/client/aura_constants.h
index 0991ada..0dc161c5 100644
--- a/ui/aura/client/aura_constants.h
+++ b/ui/aura/client/aura_constants.h
@@ -134,12 +134,6 @@
 // ResizeBehavior values.
 AURA_EXPORT extern const WindowProperty<int>* const kResizeBehaviorKey;
 
-// Reserves a number of dip around the window (i.e. inset from its exterior
-// border) for event routing back to the top level window. This is used for
-// routing events to toplevel window resize handles. It should only be respected
-// for restored windows (maximized and fullscreen can't be drag-resized).
-AURA_EXPORT extern const WindowProperty<int>* const kResizeHandleInset;
-
 // A property key to store the restore bounds in screen coordinates for a
 // window.
 AURA_EXPORT extern const WindowProperty<gfx::Rect*>* const kRestoreBoundsKey;
diff --git a/ui/events/BUILD.gn b/ui/events/BUILD.gn
index f4e54c54..28496fb 100644
--- a/ui/events/BUILD.gn
+++ b/ui/events/BUILD.gn
@@ -513,6 +513,7 @@
       "blink/prediction/kalman_predictor_unittest.cc",
       "blink/prediction/least_squares_predictor_unittest.cc",
       "blink/prediction/linear_predictor_unittest.cc",
+      "blink/prediction/one_euro_filter_unittests.cc",
       "blink/scroll_predictor_unittest.cc",
       "blink/web_input_event_traits_unittest.cc",
       "blink/web_input_event_unittest.cc",
diff --git a/ui/events/blink/BUILD.gn b/ui/events/blink/BUILD.gn
index e4b823f..3f1e498c 100644
--- a/ui/events/blink/BUILD.gn
+++ b/ui/events/blink/BUILD.gn
@@ -53,6 +53,8 @@
     "prediction/least_squares_predictor.h",
     "prediction/linear_predictor.cc",
     "prediction/linear_predictor.h",
+    "prediction/one_euro_filter.cc",
+    "prediction/one_euro_filter.h",
     "prediction/predictor_factory.cc",
     "prediction/predictor_factory.h",
     "scroll_predictor.cc",
diff --git a/ui/events/blink/DEPS b/ui/events/blink/DEPS
index 4a931578..adc4c31 100644
--- a/ui/events/blink/DEPS
+++ b/ui/events/blink/DEPS
@@ -22,4 +22,6 @@
   "+ui/display/win",
   "+ui/gfx",
   "+ui/gfx/geometry",
+
+  "+third_party/one_euro_filter/src/one_euro_filter.h",
 ]
diff --git a/ui/events/blink/prediction/empty_filter.cc b/ui/events/blink/prediction/empty_filter.cc
index dd3a3ff1..66a5056 100644
--- a/ui/events/blink/prediction/empty_filter.cc
+++ b/ui/events/blink/prediction/empty_filter.cc
@@ -10,9 +10,9 @@
 EmptyFilter::EmptyFilter() {}
 EmptyFilter::~EmptyFilter() {}
 
-bool EmptyFilter::Filter(const base::TimeTicks timestamp,
+bool EmptyFilter::Filter(const base::TimeTicks& timestamp,
                          gfx::PointF* position) const {
-  return true;
+  return position != nullptr;
 }
 
 const char* EmptyFilter::GetName() const {
diff --git a/ui/events/blink/prediction/empty_filter.h b/ui/events/blink/prediction/empty_filter.h
index 4b8bdd5..ed661d0 100644
--- a/ui/events/blink/prediction/empty_filter.h
+++ b/ui/events/blink/prediction/empty_filter.h
@@ -18,7 +18,7 @@
 
   // Filters the position sent to the filter at a specific timestamp.
   // Returns true if the value is filtered, false otherwise.
-  bool Filter(const base::TimeTicks timestamp,
+  bool Filter(const base::TimeTicks& timestamp,
               gfx::PointF* position) const override;
 
   // Returns the name of the filter
diff --git a/ui/events/blink/prediction/filter_factory.cc b/ui/events/blink/prediction/filter_factory.cc
index 65de8e9c..5928dd002 100644
--- a/ui/events/blink/prediction/filter_factory.cc
+++ b/ui/events/blink/prediction/filter_factory.cc
@@ -3,28 +3,91 @@
 // found in the LICENSE file.
 
 #include "ui/events/blink/prediction/filter_factory.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/strings/string_number_conversions.h"
 #include "ui/events/blink/prediction/empty_filter.h"
+#include "ui/events/blink/prediction/one_euro_filter.h"
+#include "ui/events/blink/prediction/predictor_factory.h"
 
 namespace ui {
 
 namespace input_prediction {
 
 const char kFilterNameEmpty[] = "empty_filter";
+const char kFilterNameOneEuro[] = "one_euro_filter";
 
 }  // namespace input_prediction
 
 namespace {
 using input_prediction::FilterType;
+using input_prediction::PredictorType;
 }  // namespace
 
+FilterFactory::FilterFactory(
+    const base::Feature& feature,
+    const input_prediction::PredictorType predictor_type,
+    const input_prediction::FilterType filter_type) {
+  LoadFilterParams(feature, predictor_type, filter_type);
+}
+
+FilterFactory::~FilterFactory() {}
+
+void FilterFactory::LoadFilterParams(
+    const base::Feature& feature,
+    const input_prediction::PredictorType predictor_type,
+    const input_prediction::FilterType filter_type) {
+  if (filter_type == FilterType::kOneEuro) {
+    base::FieldTrialParams one_euro_filter_param = {
+        {OneEuroFilter::kParamBeta, ""}, {OneEuroFilter::kParamMincutoff, ""}};
+    double beta, mincutoff;
+    // Only save the params if they are given in the fieldtrials params
+    if (base::GetFieldTrialParamsByFeature(feature, &one_euro_filter_param) &&
+        base::StringToDouble(one_euro_filter_param[OneEuroFilter::kParamBeta],
+                             &beta) &&
+        base::StringToDouble(
+            one_euro_filter_param[OneEuroFilter::kParamMincutoff],
+            &mincutoff)) {
+      FilterParamMapKey param_key = {FilterType::kOneEuro, predictor_type};
+      FilterParams param_value = {{OneEuroFilter::kParamMincutoff, mincutoff},
+                                  {OneEuroFilter::kParamBeta, beta}};
+      filter_params_map_.insert(std::make_pair(param_key, param_value));
+    }
+  }
+}
+
 FilterType FilterFactory::GetFilterTypeFromName(
     const std::string& filter_name) {
-  return FilterType::kEmpty;
+  if (filter_name == input_prediction::kFilterNameOneEuro)
+    return FilterType::kOneEuro;
+  else
+    return FilterType::kEmpty;
 }
 
 std::unique_ptr<InputFilter> FilterFactory::CreateFilter(
-    input_prediction::FilterType filter_type) {
-  return std::make_unique<EmptyFilter>();
+    const FilterType filter_type,
+    const PredictorType predictor_type) {
+  FilterParams filter_params;
+  GetFilterParams(filter_type, predictor_type, &filter_params);
+  if (filter_type == FilterType::kOneEuro) {
+    if (filter_params.empty())
+      return std::make_unique<OneEuroFilter>();
+    else
+      return std::make_unique<OneEuroFilter>(
+          filter_params.find(OneEuroFilter::kParamMincutoff)->second,
+          filter_params.find(OneEuroFilter::kParamBeta)->second);
+  } else
+    return std::make_unique<EmptyFilter>();
+}
+
+void FilterFactory::GetFilterParams(const FilterType filter_type,
+                                    const PredictorType predictor_type,
+                                    FilterParams* filter_params) {
+  FilterParamMapKey key = {filter_type, predictor_type};
+  auto params = filter_params_map_.find(key);
+  if (params != filter_params_map_.end()) {
+    *filter_params = params->second;
+  }
 }
 
 }  // namespace ui
diff --git a/ui/events/blink/prediction/filter_factory.h b/ui/events/blink/prediction/filter_factory.h
index 12da7406..42447b9 100644
--- a/ui/events/blink/prediction/filter_factory.h
+++ b/ui/events/blink/prediction/filter_factory.h
@@ -5,38 +5,95 @@
 #ifndef UI_EVENTS_BLINK_PREDICTION_FILTER_FACTORY_H_
 #define UI_EVENTS_BLINK_PREDICTION_FILTER_FACTORY_H_
 
+#include "base/feature_list.h"
 #include "ui/events/blink/prediction/input_filter.h"
+#include "ui/events/blink/prediction/predictor_factory.h"
 
 namespace ui {
 
-namespace input_prediction {
+namespace test {
+class FilterFactoryTest;
+}  // namespace test
 
+namespace input_prediction {
 extern const char kFilterNameEmpty[];
+extern const char kFilterNameOneEuro[];
 
 enum class FilterType {
   kEmpty,
+  kOneEuro,
 };
 }  // namespace input_prediction
 
-// FilterFactory is a class containing static public methods to create filters.
+// Structure used as key in the unordered_map to store different filter params
+// in function of a trio {Filter, Predictor, Feature}
+struct FilterParamMapKey {
+  bool operator==(const FilterParamMapKey& other) const {
+    return filter_type == other.filter_type &&
+           predictor_type == other.predictor_type;
+  }
+  input_prediction::FilterType filter_type;
+  input_prediction::PredictorType predictor_type;
+};
+
+// Used to compute a hash value for FilterParamMapKey so it can be used as key
+// in a hashmap
+struct FilterParamMapKeyHash {
+  std::size_t operator()(const FilterParamMapKey& k) const {
+    return std::hash<const input_prediction::FilterType>{}(k.filter_type) ^
+           std::hash<const input_prediction::PredictorType>{}(k.predictor_type);
+  }
+};
+
+using FilterParams = std::unordered_map<std::string, double>;
+using FilterParamsMap =
+    std::unordered_map<FilterParamMapKey, FilterParams, FilterParamMapKeyHash>;
+
+// FilterFactory is a class containing methods to create filters.
 // It defines filters name and type constants. It also reads filter settings
 // from fieldtrials if needed.
 class FilterFactory {
  public:
+  FilterFactory(const base::Feature& feature,
+                const input_prediction::PredictorType predictor_type,
+                const input_prediction::FilterType filter_type);
+  ~FilterFactory();
+
   // Returns the FilterType associated to the given filter
   // name if found, otherwise returns kFilterTypeEmpty
-  static input_prediction::FilterType GetFilterTypeFromName(
+  input_prediction::FilterType GetFilterTypeFromName(
       const std::string& filter_name);
 
   // Returns the filter designed by its type.
-  static std::unique_ptr<InputFilter> CreateFilter(
-      input_prediction::FilterType filter_type);
+  // Since filters can have different parameters in function of the current
+  // predictor used, it also needs to be given as parameter.
+  std::unique_ptr<InputFilter> CreateFilter(
+      const input_prediction::FilterType filter_type,
+      const input_prediction::PredictorType predictor_type);
 
  private:
-  FilterFactory() = delete;
-  ~FilterFactory() = delete;
-};
+  friend class test::FilterFactoryTest;
 
+  // Map storing filter parameters for a pair {FilterType, PredictorType}.
+  // Currently the map is only storing values from fieldtrials params, but
+  // default parameters might be added for a specific predictor/filter pair
+  // in the future.
+  FilterParamsMap filter_params_map_;
+
+  // Initialize the filter_params_map_ with values from fieldtrials params for
+  // a given feature, predictor and filter.
+  // Might initialize some default values for specific predictor/filter pair in
+  // the future.
+  void LoadFilterParams(const base::Feature& feature,
+                        const input_prediction::PredictorType predictor_type,
+                        const input_prediction::FilterType filter_type);
+
+  // Gets filter params for a specific key couple {FilterType, PredictorType}
+  // If params are found, update the given filter_params map.
+  void GetFilterParams(const input_prediction::FilterType filter_type,
+                       const input_prediction::PredictorType predictor_type,
+                       FilterParams* filter_params);
+};
 }  // namespace ui
 
 #endif  // UI_EVENTS_BLINK_PREDICTION_FILTER_FACTORY_H_
\ No newline at end of file
diff --git a/ui/events/blink/prediction/filter_factory_unittests.cc b/ui/events/blink/prediction/filter_factory_unittests.cc
index 4cc7906..41e8aadf 100644
--- a/ui/events/blink/prediction/filter_factory_unittests.cc
+++ b/ui/events/blink/prediction/filter_factory_unittests.cc
@@ -2,32 +2,135 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/test/scoped_feature_list.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/blink/blink_features.h"
 #include "ui/events/blink/prediction/filter_factory.h"
+#include "ui/events/blink/prediction/one_euro_filter.h"
 
 namespace ui {
 namespace test {
 
+namespace {
+using base::Feature;
+using input_prediction::FilterType;
+using input_prediction::PredictorType;
+}  // namespace
+
 class FilterFactoryTest : public testing::Test {
  public:
-  explicit FilterFactoryTest() {}
+  FilterFactoryTest() {
+    CreateNewFactory(features::kFilteringScrollPrediction,
+                     PredictorType::kScrollPredictorTypeKalman,
+                     FilterType::kEmpty);
+  }
+
+  void GetFilterParams(const FilterType& filter_type,
+                       const PredictorType& predictor_type,
+                       FilterParams* filter_params) {
+    factory_->GetFilterParams(filter_type, predictor_type, filter_params);
+  }
+
+  FilterType GetFilterTypeFromName(const std::string& filter_name) {
+    return factory_->GetFilterTypeFromName(filter_name);
+  }
+
+  std::unique_ptr<InputFilter> CreateFilter(
+      const input_prediction::FilterType filter_type,
+      const input_prediction::PredictorType predictor_type) {
+    return factory_->CreateFilter(filter_type, predictor_type);
+  }
+
+  void CreateNewFactory(const base::Feature& feature,
+                        const input_prediction::PredictorType predictor_type,
+                        const input_prediction::FilterType filter_type) {
+    factory_ =
+        std::make_unique<FilterFactory>(feature, predictor_type, filter_type);
+  }
+
+ private:
+  std::unique_ptr<FilterFactory> factory_;
 
   DISALLOW_COPY_AND_ASSIGN(FilterFactoryTest);
 };
 
 // Check if the FilterType returned is correct
 TEST_F(FilterFactoryTest, TestGetFilterType) {
-  EXPECT_EQ(
-      input_prediction::FilterType::kEmpty,
-      FilterFactory::GetFilterTypeFromName(input_prediction::kFilterNameEmpty));
-  // Default type Empty
   EXPECT_EQ(input_prediction::FilterType::kEmpty,
-            FilterFactory::GetFilterTypeFromName(""));
+            GetFilterTypeFromName(input_prediction::kFilterNameEmpty));
+
+  EXPECT_EQ(input_prediction::FilterType::kOneEuro,
+            GetFilterTypeFromName(input_prediction::kFilterNameOneEuro));
+
+  // Default type Empty
+  EXPECT_EQ(input_prediction::FilterType::kEmpty, GetFilterTypeFromName(""));
+}
+
+TEST_F(FilterFactoryTest, TestCreateFilter) {
+  EXPECT_STREQ(
+      input_prediction::kFilterNameEmpty,
+      CreateFilter(input_prediction::FilterType::kEmpty,
+                   input_prediction::PredictorType::kScrollPredictorTypeEmpty)
+          ->GetName());
+
+  EXPECT_STREQ(
+      input_prediction::kFilterNameOneEuro,
+      CreateFilter(input_prediction::FilterType::kOneEuro,
+                   input_prediction::PredictorType::kScrollPredictorTypeEmpty)
+          ->GetName());
+}
+
+// Test there is no params available for OneEuro filter
+TEST_F(FilterFactoryTest, TestOneEuroNoParams) {
+  FilterParams filter_params;
+
+  GetFilterParams(FilterType::kOneEuro,
+                  PredictorType::kScrollPredictorTypeKalman, &filter_params);
+  EXPECT_TRUE(filter_params.empty());
+}
+
+// Test we get the params sent via fieldtrials params
+TEST_F(FilterFactoryTest, TestOneEuroParams) {
+  FilterParams filter_params;
+
+  base::test::ScopedFeatureList scoped_feature_list;
+  base::FieldTrialParams field_trial_params;
+
+  field_trial_params[OneEuroFilter::kParamMincutoff] = "33";
+  field_trial_params[OneEuroFilter::kParamBeta] = "42";
+  scoped_feature_list.Reset();
+  scoped_feature_list.InitAndEnableFeatureWithParameters(
+      features::kFilteringScrollPrediction, field_trial_params);
+
+  // Create a new factory to load fieldtrials params values
+  CreateNewFactory(features::kFilteringScrollPrediction,
+                   PredictorType::kScrollPredictorTypeKalman,
+                   FilterType::kOneEuro);
+
+  GetFilterParams(FilterType::kOneEuro,
+                  PredictorType::kScrollPredictorTypeKalman, &filter_params);
+
+  EXPECT_EQ((int)filter_params.size(), 2);
+  EXPECT_EQ(filter_params.find(OneEuroFilter::kParamMincutoff)->second, 33);
+  EXPECT_EQ(filter_params.find(OneEuroFilter::kParamBeta)->second, 42);
+
+  // fieldtrials params shouldn't be available for another predictor
+  filter_params.clear();
+  GetFilterParams(FilterType::kOneEuro, PredictorType::kScrollPredictorTypeLsq,
+                  &filter_params);
+
+  EXPECT_TRUE(filter_params.empty());
 }
 
 TEST_F(FilterFactoryTest, TestGetFilter) {
-  EXPECT_STREQ(input_prediction::kFilterNameEmpty,
-               FilterFactory::CreateFilter(input_prediction::FilterType::kEmpty)
+  EXPECT_STREQ(
+      input_prediction::kFilterNameEmpty,
+      CreateFilter(FilterType::kEmpty, PredictorType::kScrollPredictorTypeEmpty)
+          ->GetName());
+
+  EXPECT_STREQ(input_prediction::kFilterNameOneEuro,
+               CreateFilter(FilterType::kOneEuro,
+                            PredictorType::kScrollPredictorTypeEmpty)
                    ->GetName());
 }
 
diff --git a/ui/events/blink/prediction/input_filter.h b/ui/events/blink/prediction/input_filter.h
index 68aab232..264d58dc 100644
--- a/ui/events/blink/prediction/input_filter.h
+++ b/ui/events/blink/prediction/input_filter.h
@@ -18,7 +18,7 @@
 
   // Filters the position sent to the filter at a specific timestamp.
   // Returns true if the value is filtered, false otherwise.
-  virtual bool Filter(const base::TimeTicks timestamp,
+  virtual bool Filter(const base::TimeTicks& timestamp,
                       gfx::PointF* position) const = 0;
 
   // Returns the name of the filter
diff --git a/ui/events/blink/prediction/one_euro_filter.cc b/ui/events/blink/prediction/one_euro_filter.cc
new file mode 100644
index 0000000..8e14dbe
--- /dev/null
+++ b/ui/events/blink/prediction/one_euro_filter.cc
@@ -0,0 +1,53 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/events/blink/prediction/one_euro_filter.h"
+#include "ui/events/blink/prediction/filter_factory.h"
+
+namespace ui {
+
+const double OneEuroFilter::kDefaultFrequency;
+const double OneEuroFilter::kDefaultMincutoff;
+const double OneEuroFilter::kDefaultBeta;
+const double OneEuroFilter::kDefaultDcutoff;
+
+const char OneEuroFilter::kParamBeta[];
+const char OneEuroFilter::kParamMincutoff[];
+
+OneEuroFilter::OneEuroFilter(double mincutoff, double beta) {
+  x_filter_ = std::make_unique<one_euro_filter::OneEuroFilter>(
+      kDefaultFrequency, mincutoff, beta, kDefaultDcutoff);
+  y_filter_ = std::make_unique<one_euro_filter::OneEuroFilter>(
+      kDefaultFrequency, mincutoff, beta, kDefaultDcutoff);
+}
+
+OneEuroFilter::~OneEuroFilter() {}
+
+bool OneEuroFilter::Filter(const base::TimeTicks& timestamp,
+                           gfx::PointF* position) const {
+  if (position == nullptr)
+    return false;
+  one_euro_filter::TimeStamp ts = (timestamp - base::TimeTicks()).InSecondsF();
+  position->set_x(x_filter_->Filter(position->x(), ts));
+  position->set_y(y_filter_->Filter(position->y(), ts));
+  return true;
+}
+
+const char* OneEuroFilter::GetName() const {
+  return input_prediction::kFilterNameOneEuro;
+}
+
+InputFilter* OneEuroFilter::Clone() {
+  OneEuroFilter* new_filter = new OneEuroFilter();
+  new_filter->x_filter_.reset(x_filter_->Clone());
+  new_filter->y_filter_.reset(y_filter_->Clone());
+  return new_filter;
+}
+
+void OneEuroFilter::Reset() {
+  x_filter_->Reset();
+  y_filter_->Reset();
+}
+
+}  // namespace ui
\ No newline at end of file
diff --git a/ui/events/blink/prediction/one_euro_filter.h b/ui/events/blink/prediction/one_euro_filter.h
new file mode 100644
index 0000000..480b0b69
--- /dev/null
+++ b/ui/events/blink/prediction/one_euro_filter.h
@@ -0,0 +1,50 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_EVENTS_BLINK_PREDICTION_ONE_EURO_FILTER_H_
+#define UI_EVENTS_BLINK_PREDICTION_ONE_EURO_FILTER_H_
+
+#include "third_party/one_euro_filter/src/one_euro_filter.h"
+#include "ui/events/blink/prediction/input_filter.h"
+
+namespace ui {
+
+// This class uses the 1€ filter from third party.
+// See this page : http://cristal.univ-lille.fr/~casiez/1euro/
+// to know how the filter works and how to tune it
+class OneEuroFilter : public InputFilter {
+ public:
+  OneEuroFilter(double mincutoff = kDefaultMincutoff,
+                double beta = kDefaultBeta);
+  ~OneEuroFilter() override;
+
+  bool Filter(const base::TimeTicks& timestamp,
+              gfx::PointF* position) const override;
+
+  const char* GetName() const override;
+
+  InputFilter* Clone() override;
+
+  void Reset() override;
+
+  // Default parameters values for the filter
+  static constexpr double kDefaultFrequency = 60;
+  static constexpr double kDefaultMincutoff = 1.0;
+  static constexpr double kDefaultBeta = 0.001;
+  static constexpr double kDefaultDcutoff = 1.0;
+
+  // Names of the fieldtrials used to tune the filter
+  static constexpr char kParamBeta[] = "beta";
+  static constexpr char kParamMincutoff[] = "mincutoff";
+
+ private:
+  std::unique_ptr<one_euro_filter::OneEuroFilter> x_filter_;
+  std::unique_ptr<one_euro_filter::OneEuroFilter> y_filter_;
+
+  DISALLOW_COPY_AND_ASSIGN(OneEuroFilter);
+};
+
+}  // namespace ui
+
+#endif  // UI_EVENTS_BLINK_PREDICTION_ONE_EURO_FILTER_H_
\ No newline at end of file
diff --git a/ui/events/blink/prediction/one_euro_filter_unittests.cc b/ui/events/blink/prediction/one_euro_filter_unittests.cc
new file mode 100644
index 0000000..7131a71a
--- /dev/null
+++ b/ui/events/blink/prediction/one_euro_filter_unittests.cc
@@ -0,0 +1,46 @@
+// Copyright 2019 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/rand_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/blink/prediction/filter_factory.h"
+#include "ui/events/blink/prediction/input_filter_unittest_helpers.h"
+#include "ui/events/blink/prediction/one_euro_filter.h"
+
+namespace ui {
+namespace test {
+
+class OneEuroFilterTest : public InputFilterTest {
+ public:
+  explicit OneEuroFilterTest() {}
+
+  void SetUp() override { filter_ = std::make_unique<ui::OneEuroFilter>(1, 1); }
+
+  DISALLOW_COPY_AND_ASSIGN(OneEuroFilterTest);
+};
+
+TEST_F(OneEuroFilterTest, TestClone) {
+  TestCloneFilter();
+}
+
+TEST_F(OneEuroFilterTest, TestReset) {
+  TestResetFilter();
+}
+
+// Check if sending values between 0 and 1 keeps filtered values between 0 and 1
+TEST_F(OneEuroFilterTest, filteringValues) {
+  base::TimeTicks ts = blink::WebInputEvent::GetStaticTimeStampForTests();
+  gfx::PointF point;
+  for (int i = 0; i < 100; i++) {
+    point.SetPoint(base::RandDouble(), base::RandDouble());
+    EXPECT_TRUE(filter_->Filter(ts, &point));
+    EXPECT_LT(point.x(), 1.0);
+    EXPECT_LT(point.y(), 1.0);
+    EXPECT_GT(point.x(), 0.0);
+    EXPECT_GT(point.y(), 0.0);
+  }
+}
+
+}  // namespace test
+}  // namespace ui
\ No newline at end of file
diff --git a/ui/events/blink/scroll_predictor.cc b/ui/events/blink/scroll_predictor.cc
index e973aac..09d2c48 100644
--- a/ui/events/blink/scroll_predictor.cc
+++ b/ui/events/blink/scroll_predictor.cc
@@ -8,7 +8,6 @@
 #include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/trace_event/trace_event.h"
-#include "ui/events/blink/prediction/filter_factory.h"
 #include "ui/events/blink/prediction/predictor_factory.h"
 
 using blink::WebInputEvent;
@@ -34,8 +33,12 @@
         features::kFilteringScrollPrediction, "filter");
 
     input_prediction::FilterType filter_type =
-        ui::FilterFactory::GetFilterTypeFromName(filter_name);
-    filter_ = ui::FilterFactory::CreateFilter(filter_type);
+        filter_factory_->GetFilterTypeFromName(filter_name);
+
+    filter_factory_ = std::make_unique<FilterFactory>(
+        features::kFilteringScrollPrediction, predictor_type, filter_type);
+
+    filter_ = filter_factory_->CreateFilter(filter_type, predictor_type);
   }
 }
 
diff --git a/ui/events/blink/scroll_predictor.h b/ui/events/blink/scroll_predictor.h
index 08d50cb5..b9b7d44 100644
--- a/ui/events/blink/scroll_predictor.h
+++ b/ui/events/blink/scroll_predictor.h
@@ -9,7 +9,7 @@
 
 #include "ui/events/base_event_utils.h"
 #include "ui/events/blink/event_with_callback.h"
-#include "ui/events/blink/prediction/input_filter.h"
+#include "ui/events/blink/prediction/filter_factory.h"
 #include "ui/events/blink/prediction/input_predictor.h"
 
 namespace ui {
@@ -63,6 +63,8 @@
   std::unique_ptr<InputPredictor> predictor_;
   std::unique_ptr<InputFilter> filter_;
 
+  std::unique_ptr<FilterFactory> filter_factory_;
+
   // Whether predicted scroll events should be filtered or not
   bool filtering_enabled_ = false;
 
diff --git a/ui/events/blink/scroll_predictor_unittest.cc b/ui/events/blink/scroll_predictor_unittest.cc
index 568d57f96..e944b97f 100644
--- a/ui/events/blink/scroll_predictor_unittest.cc
+++ b/ui/events/blink/scroll_predictor_unittest.cc
@@ -111,23 +111,20 @@
 
   bool isFilteringEnabled() { return scroll_predictor_->filtering_enabled_; }
 
-  void ConfigurePredictorFieldTrial(const base::Feature& feature,
-                                    const std::string& predictor_type) {
+  void ConfigurePredictorFieldTrialAndInitialize(
+      const base::Feature& feature,
+      const std::string& predictor_type) {
     base::FieldTrialParams params;
     params["predictor"] = predictor_type;
-
     scoped_feature_list_.Reset();
     scoped_feature_list_.InitAndEnableFeatureWithParameters(feature, params);
     EXPECT_EQ(params["predictor"],
               GetFieldTrialParamValueByFeature(feature, "predictor"));
+    scroll_predictor_ = std::make_unique<ScrollPredictor>();
   }
 
-  void VerifyPredictorType(const char* expected_type) {
-    EXPECT_EQ(expected_type, scroll_predictor_->predictor_->GetName());
-  }
-
-  void ConfigureFilterFieldTrial(const base::Feature& feature,
-                                 const std::string& filter_name) {
+  void ConfigureFilterFieldTrialAndInitialize(const base::Feature& feature,
+                                              const std::string& filter_name) {
     base::FieldTrialParams params;
     params["filter"] = filter_name;
 
@@ -135,6 +132,38 @@
     scoped_feature_list_.InitAndEnableFeatureWithParameters(feature, params);
     EXPECT_EQ(params["filter"],
               GetFieldTrialParamValueByFeature(feature, "filter"));
+    scroll_predictor_ = std::make_unique<ScrollPredictor>();
+  }
+
+  void ConfigurePredictorAndFilterFieldTrialAndInitialize(
+      const base::Feature& pred_feature,
+      const std::string& predictor_type,
+      const base::Feature& filter_feature,
+      const std::string& filter_type) {
+    base::FieldTrialParams pred_field_params;
+    pred_field_params["predictor"] = predictor_type;
+    base::test::ScopedFeatureList::FeatureAndParams prediction_params = {
+        pred_feature, pred_field_params};
+
+    base::FieldTrialParams filter_field_params;
+    filter_field_params["filter"] = filter_type;
+    base::test::ScopedFeatureList::FeatureAndParams filter_params = {
+        filter_feature, filter_field_params};
+
+    scoped_feature_list_.Reset();
+    scoped_feature_list_.InitWithFeaturesAndParameters(
+        {prediction_params, filter_params}, {});
+
+    EXPECT_EQ(pred_field_params["predictor"],
+              GetFieldTrialParamValueByFeature(pred_feature, "predictor"));
+    EXPECT_EQ(filter_field_params["filter"],
+              GetFieldTrialParamValueByFeature(filter_feature, "filter"));
+
+    scroll_predictor_ = std::make_unique<ScrollPredictor>();
+  }
+
+  void VerifyPredictorType(const char* expected_type) {
+    EXPECT_EQ(expected_type, scroll_predictor_->predictor_->GetName());
   }
 
   void VerifyFilterType(const char* expected_type) {
@@ -397,40 +426,43 @@
 
   // When resampling is enabled, predictor type is set from
   // kResamplingScrollEvents.
-  ConfigurePredictorFieldTrial(features::kResamplingScrollEvents,
-                               input_prediction::kScrollPredictorNameEmpty);
-  scroll_predictor_ = std::make_unique<ScrollPredictor>();
+  ConfigurePredictorFieldTrialAndInitialize(
+      features::kResamplingScrollEvents,
+      input_prediction::kScrollPredictorNameEmpty);
   VerifyPredictorType(input_prediction::kScrollPredictorNameEmpty);
 
-  ConfigurePredictorFieldTrial(features::kResamplingScrollEvents,
-                               input_prediction::kScrollPredictorNameLsq);
-  scroll_predictor_ = std::make_unique<ScrollPredictor>();
+  ConfigurePredictorFieldTrialAndInitialize(
+      features::kResamplingScrollEvents,
+      input_prediction::kScrollPredictorNameLsq);
   VerifyPredictorType(input_prediction::kScrollPredictorNameLsq);
 
-  ConfigurePredictorFieldTrial(features::kResamplingScrollEvents,
-                               input_prediction::kScrollPredictorNameKalman);
-  scroll_predictor_ = std::make_unique<ScrollPredictor>();
+  ConfigurePredictorFieldTrialAndInitialize(
+      features::kResamplingScrollEvents,
+      input_prediction::kScrollPredictorNameKalman);
   VerifyPredictorType(input_prediction::kScrollPredictorNameKalman);
 
-  ConfigurePredictorFieldTrial(
+  ConfigurePredictorFieldTrialAndInitialize(
       features::kResamplingScrollEvents,
       input_prediction::kScrollPredictorNameLinearFirst);
-  scroll_predictor_ = std::make_unique<ScrollPredictor>();
   VerifyPredictorType(input_prediction::kScrollPredictorNameLinearFirst);
 }
 
 // Check the right filter is selected
 TEST_F(ScrollPredictorTest, DefaultFilter) {
-  ConfigureFilterFieldTrial(features::kFilteringScrollPrediction, "");
-  scroll_predictor_ = std::make_unique<ScrollPredictor>();
+  ConfigureFilterFieldTrialAndInitialize(features::kFilteringScrollPrediction,
+                                         "");
   VerifyFilterType(input_prediction::kFilterNameEmpty);
   EXPECT_TRUE(isFilteringEnabled());
 
-  ConfigureFilterFieldTrial(features::kFilteringScrollPrediction,
-                            input_prediction::kFilterNameEmpty);
-  scroll_predictor_ = std::make_unique<ScrollPredictor>();
+  ConfigureFilterFieldTrialAndInitialize(features::kFilteringScrollPrediction,
+                                         input_prediction::kFilterNameEmpty);
   VerifyFilterType(input_prediction::kFilterNameEmpty);
   EXPECT_TRUE(isFilteringEnabled());
+
+  ConfigureFilterFieldTrialAndInitialize(features::kFilteringScrollPrediction,
+                                         input_prediction::kFilterNameOneEuro);
+  VerifyFilterType(input_prediction::kFilterNameOneEuro);
+  EXPECT_TRUE(isFilteringEnabled());
 }
 
 // We first send 100 events to the scroll predictor with kalman predictor
@@ -438,9 +470,9 @@
 // We then send the same events with kalman and the empty filter, we should
 // expect the same results.
 TEST_F(ScrollPredictorTest, FilteringPrediction) {
-  ConfigureFilterFieldTrial(features::kResamplingScrollEvents,
-                            input_prediction::kScrollPredictorNameKalman);
-  scroll_predictor_ = std::make_unique<ScrollPredictor>();
+  ConfigurePredictorFieldTrialAndInitialize(
+      features::kResamplingScrollEvents,
+      input_prediction::kScrollPredictorNameKalman);
 
   std::vector<double> accumulated_deltas;
   WebScopedInputEvent gesture_update;
@@ -456,10 +488,10 @@
   EXPECT_EQ((int)accumulated_deltas.size(), 100);
 
   // Now we enable filtering and compare the deltas
-  ConfigurePredictorFieldTrial(features::kResamplingScrollEvents,
-                               input_prediction::kScrollPredictorNameKalman);
-  ConfigureFilterFieldTrial(features::kFilteringScrollPrediction,
-                            input_prediction::kFilterNameEmpty);
+  ConfigurePredictorAndFilterFieldTrialAndInitialize(
+      features::kResamplingScrollEvents,
+      input_prediction::kScrollPredictorNameKalman,
+      features::kFilteringScrollPrediction, input_prediction::kFilterNameEmpty);
   scroll_predictor_ = std::make_unique<ScrollPredictor>();
 
   for (int i = 0; i < 100; i++) {
diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn
index fd72f31..877db007 100644
--- a/ui/gl/BUILD.gn
+++ b/ui/gl/BUILD.gn
@@ -4,6 +4,7 @@
 
 import("//build/buildflag_header.gni")
 import("//build/config/chrome_build.gni")
+import("//build/config/chromecast_build.gni")
 import("//build/config/jumbo.gni")
 import("//build/config/linux/pkg_config.gni")
 import("//build/config/ui.gni")
@@ -13,7 +14,7 @@
 
 declare_args() {
   enable_swiftshader = (is_win || is_linux || (is_mac && use_egl) ||
-                        is_chromeos || is_fuchsia) &&
+                        is_chromeos || is_fuchsia) && !is_cast_audio_only &&
                        (target_cpu == "x86" || target_cpu == "x64" ||
                         target_cpu == "arm" || target_cpu == "arm64" ||
                         target_cpu == "mipsel" || target_cpu == "mips64el")
diff --git a/ui/gl/OWNERS b/ui/gl/OWNERS
index 6502886..f59dfd6 100644
--- a/ui/gl/OWNERS
+++ b/ui/gl/OWNERS
@@ -1,5 +1,6 @@
 backer@chromium.org
 kbr@chromium.org
+sunnyps@chromium.org
 zmo@chromium.org
 per-file *gl_image*=reveman@chromium.org
 per-file *gl_image*=dcastagna@chromium.org
diff --git a/ui/native_theme/native_theme.h b/ui/native_theme/native_theme.h
index cd7070b3..a5066b03 100644
--- a/ui/native_theme/native_theme.h
+++ b/ui/native_theme/native_theme.h
@@ -7,6 +7,7 @@
 
 #include <map>
 
+#include "base/containers/flat_map.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
 #include "build/build_config.h"
diff --git a/ui/ozone/platform/headless/BUILD.gn b/ui/ozone/platform/headless/BUILD.gn
index 635cc8f..c71628cf 100644
--- a/ui/ozone/platform/headless/BUILD.gn
+++ b/ui/ozone/platform/headless/BUILD.gn
@@ -31,6 +31,7 @@
     "//ui/events/ozone:events_ozone_layout",
     "//ui/events/platform",
     "//ui/gfx/geometry",
+    "//ui/gl:buildflags",
     "//ui/ozone:ozone_base",
     "//ui/ozone/common",
     "//ui/platform_window",
diff --git a/ui/ozone/platform/headless/headless_surface_factory.cc b/ui/ozone/platform/headless/headless_surface_factory.cc
index 4ec93cec..7218de3a3 100644
--- a/ui/ozone/platform/headless/headless_surface_factory.cc
+++ b/ui/ozone/platform/headless/headless_surface_factory.cc
@@ -20,6 +20,7 @@
 #include "ui/gfx/native_pixmap.h"
 #include "ui/gfx/skia_util.h"
 #include "ui/gfx/vsync_provider.h"
+#include "ui/gl/buildflags.h"
 #include "ui/gl/gl_surface_egl.h"
 #include "ui/ozone/common/egl_util.h"
 #include "ui/ozone/common/gl_ozone_egl.h"
@@ -174,7 +175,11 @@
 
 std::vector<gl::GLImplementation>
 HeadlessSurfaceFactory::GetAllowedGLImplementations() {
-  return std::vector<gl::GLImplementation>{gl::kGLImplementationSwiftShaderGL};
+  return std::vector<gl::GLImplementation> {
+#if BUILDFLAG(ENABLE_SWIFTSHADER)
+    gl::kGLImplementationSwiftShaderGL,
+#endif
+  };
 }
 
 GLOzone* HeadlessSurfaceFactory::GetGLOzone(
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn
index 9a434f2..278263d 100644
--- a/ui/views/BUILD.gn
+++ b/ui/views/BUILD.gn
@@ -204,7 +204,6 @@
     "layout/flex_layout.h",
     "layout/flex_layout_types.h",
     "layout/grid_layout.h",
-    "layout/interpolating_layout_manager.h",
     "layout/layout_manager.h",
     "layout/layout_manager_base.h",
     "layout/layout_provider.h",
@@ -413,7 +412,6 @@
     "layout/flex_layout_types.cc",
     "layout/flex_layout_types_internal.cc",
     "layout/grid_layout.cc",
-    "layout/interpolating_layout_manager.cc",
     "layout/layout_manager.cc",
     "layout/layout_manager_base.cc",
     "layout/layout_provider.cc",
@@ -1050,7 +1048,6 @@
     "layout/flex_layout_types_internal_unittest.cc",
     "layout/flex_layout_unittest.cc",
     "layout/grid_layout_unittest.cc",
-    "layout/interpolating_layout_manager_unittest.cc",
     "layout/layout_manager_base_unittest.cc",
     "metadata/metadata_unittest.cc",
     "metadata/type_conversion_unittest.cc",
diff --git a/ui/views/accessible_pane_view.h b/ui/views/accessible_pane_view.h
index 1c70cd36d..813fd13 100644
--- a/ui/views/accessible_pane_view.h
+++ b/ui/views/accessible_pane_view.h
@@ -35,7 +35,7 @@
   // If |initial_focus| is not NULL, that control will get
   // the initial focus, if it's enabled and focusable. Returns true if
   // the pane was able to receive focus.
-  virtual bool SetPaneFocus(View* initial_focus);
+  bool SetPaneFocus(View* initial_focus);
 
   bool pane_has_focus() const { return pane_has_focus_; }
 
@@ -75,15 +75,15 @@
 
   // Returns the parent of |v|. Subclasses can override this if
   // they need custom focus search behavior.
-  virtual View* GetParentForFocusSearch(View* v);
+  View* GetParentForFocusSearch(View* v);
 
   // Returns true if |v| is contained within the hierarchy rooted at |root|
   // for the purpose of focus searching. Subclasses can override this if
   // they need custom focus search behavior.
-  virtual bool ContainsForFocusSearch(View* root, const View* v);
+  bool ContainsForFocusSearch(View* root, const View* v);
 
   // Remove pane focus.
-  virtual void RemovePaneFocus();
+  void RemovePaneFocus();
 
   View* GetFirstFocusableChild();
   View* GetLastFocusableChild();
diff --git a/ui/views/controls/button/label_button.h b/ui/views/controls/button/label_button.h
index c183274e..2162f9e 100644
--- a/ui/views/controls/button/label_button.h
+++ b/ui/views/controls/button/label_button.h
@@ -134,13 +134,13 @@
 
   // Returns the available area for the label and image. Subclasses can change
   // these bounds if they need room to do manual painting.
-  virtual gfx::Rect GetChildAreaBounds();
+  gfx::Rect GetChildAreaBounds();
 
   // Fills |params| with information about the button.
   virtual void GetExtraParams(ui::NativeTheme::ExtraParams* params) const;
 
   // Resets colors from the NativeTheme, explicitly set colors are unchanged.
-  virtual void ResetColorsFromNativeTheme();
+  void ResetColorsFromNativeTheme();
 
   // Changes the visual styling to match changes in the default state.  Returns
   // the PropertyEffects triggered as a result.
diff --git a/ui/views/layout/flex_layout_types.h b/ui/views/layout/flex_layout_types.h
index 4c6d71a..1e6c1e06 100644
--- a/ui/views/layout/flex_layout_types.h
+++ b/ui/views/layout/flex_layout_types.h
@@ -128,9 +128,9 @@
 };
 
 // Represents insets in a single dimension.
-class Inset1D {
+class VIEWS_EXPORT Inset1D {
  public:
-  constexpr Inset1D() = default;
+  constexpr Inset1D() {}
   constexpr explicit Inset1D(int all) : leading_(all), trailing_(all) {}
   constexpr Inset1D(int leading, int trailing)
       : leading_(leading), trailing_(trailing) {}
@@ -159,9 +159,9 @@
 };
 
 // Represents a line segment in one dimension with a starting point and length.
-class Span {
+class VIEWS_EXPORT Span {
  public:
-  constexpr Span() = default;
+  constexpr Span() {}
   constexpr Span(int start, int length) : start_(start), length_(length) {}
 
   constexpr int start() const { return start_; }
diff --git a/ui/views/layout/layout_manager_base.cc b/ui/views/layout/layout_manager_base.cc
index 1992d5c..261e101c 100644
--- a/ui/views/layout/layout_manager_base.cc
+++ b/ui/views/layout/layout_manager_base.cc
@@ -11,42 +11,59 @@
 
 namespace views {
 
+bool LayoutManagerBase::ChildLayout::operator==(
+    const ChildLayout& other) const {
+  // Note: if the view is not visible, the bounds do not matter as they will not
+  // be set.
+  return child_view == other.child_view && visible == other.visible &&
+         (!visible || bounds == other.bounds);
+}
+
 LayoutManagerBase::ProposedLayout::ProposedLayout() = default;
 LayoutManagerBase::ProposedLayout::ProposedLayout(const ProposedLayout& other) =
     default;
 LayoutManagerBase::ProposedLayout::ProposedLayout(ProposedLayout&& other) =
     default;
+LayoutManagerBase::ProposedLayout::ProposedLayout(
+    const gfx::Size& size,
+    const std::initializer_list<ChildLayout>& children)
+    : host_size(size), child_layouts(children) {}
 LayoutManagerBase::ProposedLayout::~ProposedLayout() = default;
 LayoutManagerBase::ProposedLayout& LayoutManagerBase::ProposedLayout::operator=(
     const ProposedLayout& other) = default;
 LayoutManagerBase::ProposedLayout& LayoutManagerBase::ProposedLayout::operator=(
     ProposedLayout&& other) = default;
 
+bool LayoutManagerBase::ProposedLayout::operator==(
+    const ProposedLayout& other) const {
+  return host_size == other.host_size && child_layouts == other.child_layouts;
+}
+
 LayoutManagerBase::~LayoutManagerBase() = default;
 
 gfx::Size LayoutManagerBase::GetPreferredSize(const View* host) const {
   DCHECK_EQ(host_view_, host);
-  if (!preferred_size_)
-    preferred_size_ = CalculateProposedLayout(SizeBounds()).host_size;
-  return *preferred_size_;
+  if (!cached_preferred_size_)
+    cached_preferred_size_ = CalculateProposedLayout(SizeBounds()).host_size;
+  return *cached_preferred_size_;
 }
 
 gfx::Size LayoutManagerBase::GetMinimumSize(const View* host) const {
   DCHECK_EQ(host_view_, host);
-  if (!minimum_size_)
-    minimum_size_ = CalculateProposedLayout(SizeBounds(0, 0)).host_size;
-  return *minimum_size_;
+  if (!cached_minimum_size_)
+    cached_minimum_size_ = CalculateProposedLayout(SizeBounds(0, 0)).host_size;
+  return *cached_minimum_size_;
 }
 
 int LayoutManagerBase::GetPreferredHeightForWidth(const View* host,
                                                   int width) const {
-  if (!last_height_for_width_ || last_height_for_width_->width() != width) {
+  if (!cached_height_for_width_ || cached_height_for_width_->width() != width) {
     const int height = CalculateProposedLayout(SizeBounds(width, base::nullopt))
                            .host_size.height();
-    last_height_for_width_ = gfx::Size(width, height);
+    cached_height_for_width_ = gfx::Size(width, height);
   }
 
-  return last_height_for_width_->height();
+  return cached_height_for_width_->height();
 }
 
 void LayoutManagerBase::Layout(View* host) {
@@ -56,19 +73,19 @@
 }
 
 void LayoutManagerBase::InvalidateLayout() {
-  minimum_size_.reset();
-  preferred_size_.reset();
-  last_height_for_width_.reset();
-  last_requested_size_.reset();
+  cached_minimum_size_.reset();
+  cached_preferred_size_.reset();
+  cached_height_for_width_.reset();
+  cached_layout_size_.reset();
 }
 
 LayoutManagerBase::ProposedLayout LayoutManagerBase::GetProposedLayout(
     const gfx::Size& host_size) const {
-  if (!last_requested_size_ || *last_requested_size_ != host_size) {
-    last_requested_size_ = host_size;
-    last_layout_ = CalculateProposedLayout(SizeBounds(host_size));
+  if (cached_layout_size_ != host_size) {
+    cached_layout_size_ = host_size;
+    cached_layout_ = CalculateProposedLayout(SizeBounds(host_size));
   }
-  return last_layout_;
+  return cached_layout_;
 }
 
 void LayoutManagerBase::SetChildViewIgnoredByLayout(View* child_view,
@@ -138,7 +155,13 @@
 
 bool LayoutManagerBase::IsChildIncludedInLayout(const View* child) const {
   const auto it = child_infos_.find(child);
-  DCHECK(it != child_infos_.end());
+
+  // During callbacks when a child is removed we can get in a state where a view
+  // in the child list of the host view is not in |child_infos_|. In that case,
+  // the view is being removed and is not part of the layout.
+  if (it == child_infos_.end())
+    return false;
+
   return !it->second.ignored && it->second.can_be_visible;
 }
 
diff --git a/ui/views/layout/layout_manager_base.h b/ui/views/layout/layout_manager_base.h
index 5ff97926..6b7b22f 100644
--- a/ui/views/layout/layout_manager_base.h
+++ b/ui/views/layout/layout_manager_base.h
@@ -31,9 +31,14 @@
   // Represents layout information for a child view within a host being laid
   // out.
   struct VIEWS_EXPORT ChildLayout {
+    bool operator==(const ChildLayout& other) const;
+    bool operator!=(const ChildLayout& other) const {
+      return !(*this == other);
+    }
+
     View* child_view = nullptr;
-    gfx::Rect bounds;
     bool visible = false;
+    gfx::Rect bounds;
   };
 
   // Contains a full layout specification for the children of the host view.
@@ -42,9 +47,16 @@
     ~ProposedLayout();
     ProposedLayout(const ProposedLayout& other);
     ProposedLayout(ProposedLayout&& other);
+    ProposedLayout(const gfx::Size& size,
+                   const std::initializer_list<ChildLayout>& children);
     ProposedLayout& operator=(const ProposedLayout& other);
     ProposedLayout& operator=(ProposedLayout&& other);
 
+    bool operator==(const ProposedLayout& other) const;
+    bool operator!=(const ProposedLayout& other) const {
+      return !(*this == other);
+    }
+
     // The size of the host view given the size bounds for this layout. If both
     // dimensions of the size bounds are specified, this will be the same size.
     gfx::Size host_size;
@@ -83,6 +95,41 @@
  protected:
   LayoutManagerBase();
 
+  // Direct cache control for subclasses that want to override default caching
+  // behavior. Use at your own risk.
+  base::Optional<gfx::Size> cached_minimum_size() const {
+    return cached_minimum_size_;
+  }
+  void set_cached_minimum_size(
+      const base::Optional<gfx::Size>& minimum_size) const {
+    cached_minimum_size_ = minimum_size;
+  }
+  const base::Optional<gfx::Size>& cached_preferred_size() const {
+    return cached_preferred_size_;
+  }
+  void set_cached_preferred_size(
+      const base::Optional<gfx::Size>& preferred_size) const {
+    cached_preferred_size_ = preferred_size;
+  }
+  const base::Optional<gfx::Size>& cached_height_for_width() const {
+    return cached_height_for_width_;
+  }
+  void set_cached_height_for_width(
+      const base::Optional<gfx::Size>& height_for_width) const {
+    cached_height_for_width_ = height_for_width;
+  }
+  const base::Optional<gfx::Size>& cached_layout_size() const {
+    return cached_layout_size_;
+  }
+  void set_cached_layout_size(
+      const base::Optional<gfx::Size>& layout_size) const {
+    cached_layout_size_ = layout_size;
+  }
+  const ProposedLayout& cached_layout() const { return cached_layout_; }
+  void set_cached_layout(const ProposedLayout& layout) const {
+    cached_layout_ = layout;
+  }
+
   bool IsChildIncludedInLayout(const View* child) const;
 
   // Creates a proposed layout for the host view, including bounds and
@@ -111,11 +158,11 @@
 
   // Do some really simple caching because layout generation can cost as much
   // as 1ms or more for complex views.
-  mutable base::Optional<gfx::Size> minimum_size_;
-  mutable base::Optional<gfx::Size> preferred_size_;
-  mutable base::Optional<gfx::Size> last_height_for_width_;
-  mutable base::Optional<gfx::Size> last_requested_size_;
-  mutable ProposedLayout last_layout_;
+  mutable base::Optional<gfx::Size> cached_minimum_size_;
+  mutable base::Optional<gfx::Size> cached_preferred_size_;
+  mutable base::Optional<gfx::Size> cached_height_for_width_;
+  mutable base::Optional<gfx::Size> cached_layout_size_;
+  mutable ProposedLayout cached_layout_;
 
   DISALLOW_COPY_AND_ASSIGN(LayoutManagerBase);
 };
diff --git a/ui/views/layout/layout_manager_base_unittest.cc b/ui/views/layout/layout_manager_base_unittest.cc
index 36e39551a..eb333a2 100644
--- a/ui/views/layout/layout_manager_base_unittest.cc
+++ b/ui/views/layout/layout_manager_base_unittest.cc
@@ -164,7 +164,7 @@
         layout.host_size.set_height(std::max(
             layout.host_size.height(), bounds.bottom() + kChildViewPadding));
       }
-      layout.child_layouts.push_back({*it, bounds, visible});
+      layout.child_layouts.push_back({*it, visible, bounds});
     }
     ++num_layouts_generated_;
     return layout;
@@ -225,12 +225,9 @@
   // Set the child visibility and bounds.
   constexpr gfx::Rect kChild1Bounds(3, 4, 10, 15);
   constexpr gfx::Rect kChild3Bounds(20, 21, 12, 14);
-  layout.child_layouts.push_back(
-      LayoutManagerBase::ChildLayout{child(0), kChild1Bounds, true});
-  layout.child_layouts.push_back(
-      LayoutManagerBase::ChildLayout{child(1), gfx::Rect(), false});
-  layout.child_layouts.push_back(
-      LayoutManagerBase::ChildLayout{child(2), kChild3Bounds, true});
+  layout.child_layouts.push_back({child(0), true, kChild1Bounds});
+  layout.child_layouts.push_back({child(1), false});
+  layout.child_layouts.push_back({child(2), true, kChild3Bounds});
 
   layout_manager()->ApplyLayout(layout);
 
@@ -251,10 +248,8 @@
   // Set the child visibility and bounds.
   constexpr gfx::Rect kChild1Bounds(3, 4, 10, 15);
   constexpr gfx::Rect kChild2Bounds(1, 2, 3, 4);
-  layout.child_layouts.push_back(
-      LayoutManagerBase::ChildLayout{child(0), kChild1Bounds, true});
-  layout.child_layouts.push_back(
-      LayoutManagerBase::ChildLayout{child(2), gfx::Rect(), false});
+  layout.child_layouts.push_back({child(0), true, kChild1Bounds});
+  layout.child_layouts.push_back({child(2), false});
 
   // We'll set the second child separately.
   child(1)->SetVisible(true);
@@ -476,4 +471,39 @@
   delete child_view;
 }
 
+TEST(LayoutManagerBase_ProposedLayoutTest, Equality) {
+  View* ptr0 = nullptr;
+  View* ptr1 = ptr0 + 1;
+  View* ptr2 = ptr0 + 2;
+  using ProposedLayout = LayoutManagerBase::ProposedLayout;
+  ProposedLayout a;
+  ProposedLayout b;
+  EXPECT_TRUE(a == b);
+  a.host_size = {1, 2};
+  EXPECT_FALSE(a == b);
+  b.host_size = {1, 2};
+  EXPECT_TRUE(a == b);
+  a.child_layouts.push_back({ptr0, true, {1, 1, 2, 2}});
+  EXPECT_FALSE(a == b);
+  b.child_layouts.push_back(a.child_layouts[0]);
+  EXPECT_TRUE(a == b);
+  a.child_layouts[0].visible = false;
+  EXPECT_FALSE(a == b);
+  b.child_layouts[0].visible = false;
+  EXPECT_TRUE(a == b);
+  b.child_layouts[0].bounds = {0, 0, 3, 3};
+  // Since |visible| == false, changing bounds doesn't change anything.
+  EXPECT_TRUE(a == b);
+  a.child_layouts[0].visible = true;
+  b.child_layouts[0].visible = true;
+  EXPECT_FALSE(a == b);
+  a.child_layouts[0].visible = false;
+  b.child_layouts[0].visible = false;
+  a.child_layouts.push_back({ptr1, true, {1, 2, 3, 4}});
+  b.child_layouts.push_back({ptr2, true, {1, 2, 3, 4}});
+  EXPECT_FALSE(a == b);
+  b.child_layouts[1].child_view = ptr1;
+  EXPECT_TRUE(a == b);
+}
+
 }  // namespace views
diff --git a/ui/views/test/views_test_base.cc b/ui/views/test/views_test_base.cc
index c2ea8a7..f2181fe 100644
--- a/ui/views/test/views_test_base.cc
+++ b/ui/views/test/views_test_base.cc
@@ -64,7 +64,12 @@
 
 }  // namespace
 
-ViewsTestBase::ViewsTestBase() = default;
+ViewsTestBase::ViewsTestBase() {
+  // MaterialDesignController is initialized here instead of in SetUp because
+  // a subclass might construct a MaterialDesignControllerTestAPI as a member to
+  // override the value, and this must happen first.
+  ui::MaterialDesignController::Initialize();
+}
 
 ViewsTestBase::~ViewsTestBase() {
   CHECK(setup_called_)
@@ -82,7 +87,6 @@
   has_compositing_manager_ = InitializeVisuals();
 
   testing::Test::SetUp();
-  ui::MaterialDesignController::Initialize();
   setup_called_ = true;
   if (!views_delegate_for_setup_)
     views_delegate_for_setup_ = std::make_unique<TestViewsDelegate>();
diff --git a/ui/views/view.h b/ui/views/view.h
index 75f488b..1a40510 100644
--- a/ui/views/view.h
+++ b/ui/views/view.h
@@ -1095,13 +1095,13 @@
   // Note that you can set multiple accelerators for a view by invoking this
   // method several times. Note also that AcceleratorPressed is invoked only
   // when CanHandleAccelerators() is true.
-  virtual void AddAccelerator(const ui::Accelerator& accelerator);
+  void AddAccelerator(const ui::Accelerator& accelerator);
 
   // Removes the specified accelerator for this view.
-  virtual void RemoveAccelerator(const ui::Accelerator& accelerator);
+  void RemoveAccelerator(const ui::Accelerator& accelerator);
 
   // Removes all the keyboard accelerators for this view.
-  virtual void ResetAccelerators();
+  void ResetAccelerators();
 
   // Overridden from AcceleratorTarget:
   bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
@@ -1144,8 +1144,8 @@
   // Convenience method to retrieve the FocusManager associated with the
   // Widget that contains this view.  This can return NULL if this view is not
   // part of a view hierarchy with a Widget.
-  virtual FocusManager* GetFocusManager();
-  virtual const FocusManager* GetFocusManager() const;
+  FocusManager* GetFocusManager();
+  const FocusManager* GetFocusManager() const;
 
   // Request keyboard focus. The receiving view will become the focused view.
   virtual void RequestFocus();
@@ -1330,7 +1330,7 @@
 
   // Scrolls the view's bounds or some subset thereof to be visible. By default
   // this function calls ScrollRectToVisible(GetLocalBounds()).
-  virtual void ScrollViewToVisible();
+  void ScrollViewToVisible();
 
   // The following methods are used by ScrollView to determine the amount
   // to scroll relative to the visible bounds of the view. For example, a
@@ -1351,10 +1351,12 @@
   //
   // See VariableRowHeightScrollHelper and FixedRowHeightScrollHelper for
   // implementations of common cases.
-  virtual int GetPageScrollIncrement(ScrollView* scroll_view,
-                                     bool is_horizontal, bool is_positive);
-  virtual int GetLineScrollIncrement(ScrollView* scroll_view,
-                                     bool is_horizontal, bool is_positive);
+  int GetPageScrollIncrement(ScrollView* scroll_view,
+                             bool is_horizontal,
+                             bool is_positive);
+  int GetLineScrollIncrement(ScrollView* scroll_view,
+                             bool is_horizontal,
+                             bool is_positive);
 
   void AddObserver(ViewObserver* observer);
   void RemoveObserver(ViewObserver* observer);
@@ -1518,7 +1520,7 @@
   // Finds the layer that this view paints to (it may belong to an ancestor
   // view), then reorders the immediate children of that layer to match the
   // order of the view tree.
-  virtual void ReorderLayers();
+  void ReorderLayers();
 
   // This reorders the immediate children of |*parent_layer| to match the
   // order of the view tree. Child layers which are owned by a view are
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_nameservers.html b/ui/webui/resources/cr_components/chromeos/network/network_nameservers.html
index 907971e..c15c64182 100644
--- a/ui/webui/resources/cr_components/chromeos/network/network_nameservers.html
+++ b/ui/webui/resources/cr_components/chromeos/network/network_nameservers.html
@@ -32,6 +32,8 @@
       .nameservers {
         /* Aligns with the start of cr-radio-button's text. */
         margin-inline-start: 38px;
+        padding-bottom: 0;
+        padding-top: 0;
       }
 
       .nameservers:not([changeable]) {