diff --git a/DEPS b/DEPS
index 540a4e19..1a536c6f 100644
--- a/DEPS
+++ b/DEPS
@@ -39,11 +39,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '28f45b949acc746849100fbe112ee5280f0594c9',
+  'skia_revision': '706d21ffd03a0a446f7b997c801356abb891eaeb',
   # 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': '3a64285df68a0f0791271cccf242e59e6b40b669',
+  'v8_revision': '609ae417e503d25c01b7284e1d1eab3ddd853b75',
   # 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.
@@ -59,7 +59,7 @@
   # 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': '5ad8474335798295a9c502999324635845d28ff7',
+  'pdfium_revision': '258f19f26b3ccfc6b64429111a4a11bdc64be131',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -191,7 +191,7 @@
    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '60fc535386f97c6a0078738ba13ba3c4ef94ae01',
 
   'src/third_party/libjingle/source/talk':
-    Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + 'a4cc90bc9bfb5cc932075aebccb734e38932b107', # commit position 11754
+    Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + 'f608241f0aa331004210377c2744a5e5e74c044f', # commit position 11893
 
   'src/third_party/usrsctp/usrsctplib':
     Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + 'c60ec8b35c3fe6027d7a3faae89d1c8d7dd3ce98',
@@ -215,7 +215,7 @@
    Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067',
 
   'src/third_party/webrtc':
-    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '73a89e6a418e17421667bdebbd9a8ad40512fecb', # commit position 11890
+    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '4b88ad3da9fe9ab8043593f577737ec531de1e86', # commit position 11897
 
   'src/third_party/openmax_dl':
     Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' +  Var('openmax_dl_revision'),
@@ -270,7 +270,7 @@
 
   'src/third_party/catapult':
     Var('chromium_git') + '/external/github.com/catapult-project/catapult.git' + '@' +
-    '1ae15ca2ece76a60c1b1b20951c3cd38c2fa855a',
+    '271451854ad0fc877ee2ee2c380a0e30d00cb144',
 
   'src/third_party/openh264/src':
     Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + 'b37cda248234162033e3e11b0335f3131cdfe488',
@@ -815,6 +815,21 @@
     ],
   },
   {
+    'name': 'blimp_fonts',
+    'pattern': '\\.sha1',
+    'action': [ 'download_from_google_storage',
+                '--no_resume',
+                '--platform=linux*',
+                '--directory',
+                '--recursive',
+                '--quiet',
+                '--no_auth',
+                '--num_threads=16',
+                '--bucket', 'chromium-fonts',
+                'src/third_party/blimp_fonts',
+    ],
+  },
+  {
     # Pull sanitizer-instrumented third-party libraries if requested via
     # GYP_DEFINES.
     'name': 'instrumented_libraries',
diff --git a/ash/mus/sysui_application.cc b/ash/mus/sysui_application.cc
index 9154947..16585a31 100644
--- a/ash/mus/sysui_application.cc
+++ b/ash/mus/sysui_application.cc
@@ -278,8 +278,7 @@
 SysUIApplication::~SysUIApplication() {}
 
 void SysUIApplication::Initialize(mojo::Connector* connector,
-                                  const std::string& url,
-                                  const std::string& user_id,
+                                  const mojo::Identity& identity,
                                   uint32_t id) {
   ash_init_.reset(new AshInit());
   ash_init_->Initialize(connector);
diff --git a/ash/mus/sysui_application.h b/ash/mus/sysui_application.h
index 78d15990..dba0f5e 100644
--- a/ash/mus/sysui_application.h
+++ b/ash/mus/sysui_application.h
@@ -23,8 +23,7 @@
  private:
   // mojo::ShellClient:
   void Initialize(mojo::Connector* connector,
-                  const std::string& url,
-                  const std::string& user_id,
+                  const mojo::Identity& identity,
                   uint32_t id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
diff --git a/base/win/object_watcher.cc b/base/win/object_watcher.cc
index 93efd06..4df54a4 100644
--- a/base/win/object_watcher.cc
+++ b/base/win/object_watcher.cc
@@ -51,7 +51,7 @@
   object_ = NULL;
   wait_object_ = NULL;
 
-  MessageLoop::current()->RemoveDestructionObserver(this);
+  origin_loop_->RemoveDestructionObserver(this);
   return true;
 }
 
@@ -82,6 +82,11 @@
     NOTREACHED() << "Already watching an object";
     return false;
   }
+
+  origin_loop_ = MessageLoop::current();
+  if (!origin_loop_)
+    return false;
+
   run_once_ = execute_only_once;
 
   // Since our job is to just notice when an object is signaled and report the
@@ -95,7 +100,6 @@
   callback_ = base::Bind(&ObjectWatcher::Signal, weak_factory_.GetWeakPtr(),
                          delegate);
   object_ = object;
-  origin_loop_ = MessageLoop::current();
 
   if (!RegisterWaitForSingleObject(&wait_object_, object, DoneWaiting,
                                    this, INFINITE, wait_flags)) {
@@ -107,7 +111,7 @@
 
   // We need to know if the current message loop is going away so we can
   // prevent the wait thread from trying to access a dead message loop.
-  MessageLoop::current()->AddDestructionObserver(this);
+  origin_loop_->AddDestructionObserver(this);
   return true;
 }
 
diff --git a/base/win/object_watcher.h b/base/win/object_watcher.h
index 3701d0f..e1e86fe7 100644
--- a/base/win/object_watcher.h
+++ b/base/win/object_watcher.h
@@ -46,6 +46,10 @@
 // If the object is already signaled before being watched, OnObjectSignaled is
 // still called after (but not necessarily immediately after) watch is started.
 //
+// NOTE: Use of this class requires that there be a current message loop;
+// otherwise, when the object is signaled, there would be no loop to post the
+// callback task to.  This means that you cannot use ObjectWatcher in test code
+// that doesn't create a message loop (unless you add such a loop).
 class BASE_EXPORT ObjectWatcher : public MessageLoop::DestructionObserver {
  public:
   class BASE_EXPORT Delegate {
@@ -62,14 +66,14 @@
   // When the object is signaled, the given delegate is notified on the thread
   // where StartWatchingOnce is called. The ObjectWatcher is not responsible for
   // deleting the delegate.
-  // Returns true if the watch was started.  Otherwise, false is returned.
+  // Returns whether watching was successfully initiated.
   bool StartWatchingOnce(HANDLE object, Delegate* delegate);
 
   // Notifies the delegate, on the thread where this method is called, each time
   // the object is set. By definition, the handle must be an auto-reset object.
   // The caller must ensure that it (or any Windows system code) doesn't reset
   // the event or else the delegate won't be called.
-  // Returns true if the watch was started.  Otherwise, false is returned.
+  // Returns whether watching was successfully initiated.
   bool StartWatchingMultipleTimes(HANDLE object, Delegate* delegate);
 
   // Stops watching.  Does nothing if the watch has already completed.  If the
diff --git a/base/win/registry.cc b/base/win/registry.cc
index ee7b8cda..7837b8a68 100644
--- a/base/win/registry.cc
+++ b/base/win/registry.cc
@@ -415,7 +415,7 @@
   if (!key_watcher_)
     key_watcher_.reset(new Watcher(this));
 
-  if (!key_watcher_.get()->StartWatching(key_, callback))
+  if (!key_watcher_->StartWatching(key_, callback))
     return false;
 
   return true;
diff --git a/blimp/README.md b/blimp/README.md
index adff5d3..3ed48f9 100644
--- a/blimp/README.md
+++ b/blimp/README.md
@@ -14,7 +14,10 @@
 
 For running blimp, read more at [running](docs/running.md).
 
+## Updating Fonts
+
+For updating the fonts that blimp supports, read more at [fonts](docs/fonts.md).
+
 ## New to Markdown?
 
 For learning more about Markdown, read more at [markdown](docs/markdown.md).
-
diff --git a/blimp/docs/container.md b/blimp/docs/container.md
index 31adc80..7a1902a 100644
--- a/blimp/docs/container.md
+++ b/blimp/docs/container.md
@@ -43,7 +43,7 @@
 
 ```bash
 ./blimp/tools/generate-engine-manifest.py \
-    --build-dir out-linux/Debug \
+    --build-dir out-chromeos/Debug \
     --target //blimp/engine:blimp_engine \
     --output blimp/engine/engine-manifest.txt
 ```
@@ -56,7 +56,7 @@
 Using the tarfile you can create a Docker image:
 
 ```bash
-docker build -t blimp_engine - < ./out-linux/Debug/blimp_engine_bundle.tar
+docker build -t blimp_engine - < ./out-chromeos/Debug/blimp_engine_bundle.tar.gz
 ```
 
 ## Running the Engine in a Docker Container
@@ -74,7 +74,8 @@
     public certificate. Permissions should be set to 644.
 *   `$CONFIG_DIR/client_token`: A file with a non-empty string used as the
     client token (the shared secret between the client and the engine).
-    Persmissions should also be set to 644.
+    Permissions should also be set to 644. See [running](running.md) for how
+    to get the default token from the source code.
 
 This setup step is only required once and can be reused for all the rest of the
 runs of the engine.
@@ -94,4 +95,3 @@
 ```
 See the [blimp engine `Dockerfile`](../engine/Dockerfile) to find out what flags
 are passed by default.
-
diff --git a/blimp/docs/fonts.md b/blimp/docs/fonts.md
new file mode 100644
index 0000000..44b744f
--- /dev/null
+++ b/blimp/docs/fonts.md
@@ -0,0 +1,39 @@
+# Updating Blimp Fonts
+
+1.  Clone the git-repositories listed in
+    `//third_party/blimp_fonts/README.chromium`, and roll forward to the commit
+    you want.
+1.  Copy the necessary files to `//third_party/blimp_fonts`.
+1.  Verify that the `LICENSE` file is still up to date and lists all relevant
+    licenses and which fonts use which license.
+1.  Update the `//third_party/blimp_fonts:fonts` target to include all the
+    current fonts and their license files.
+1.  Update the engine dependencies using
+    `//blimp/tools/generate-engine-manifest.py`. This step is documented in
+    `//blimp/docs/container.md`.
+1.  Run the `upload_to_google_storage.py` (from depot_tools) script to upload
+    the files. To do this, execute:
+
+    ```bash
+    find ./third_party/blimp_fonts \
+        -regex '^.*.\(ttf\|otf\)$' -type f -print0 | \
+        upload_to_google_storage.py --use_null_terminator -b chromium-fonts -
+    ```
+
+    If the set of fonts includes more than `.ttf` or `.otf` files, you must
+    update the regular expression to include such fonts.
+1.  Verify that `//third_party/blimp_fonts/.gitignore` lists the correct files
+    to ignore.
+1.  Add all the `.sha1` files to the chromium src repository, by executing the
+    following command:
+
+    ```bash
+    git add ./third_party/blimp_fonts/*.sha1
+    ```
+
+1.  Commit and upload the change for review:
+
+    ```bash
+    git commit
+    git cl upload
+    ```
diff --git a/blimp/docs/running.md b/blimp/docs/running.md
index 8accd3e..bb92199f 100644
--- a/blimp/docs/running.md
+++ b/blimp/docs/running.md
@@ -100,6 +100,8 @@
   compositor.
 * `--disable-cached-picture-raster`: Ensures that rasterized content is not
   destroyed before serialization.
+* `--android-fonts-path=$PATH`: Path to where the fonts are located.
+  Typically this would be `out-linux/Debug/gen/third_party/blimp_fonts`.
 
 #### Typical invocation
 When the client connects to a manually specified engine instead of using the
@@ -122,6 +124,7 @@
   --disable-cached-picture-raster \
   --blimp-client-token-path=/tmp/blimpengine-token \
   --user-data-dir=/tmp/blimpengine \
+  --android-fonts-path=out-linux/Debug/gen/third_party/blimp_fonts \
   --enable-logging=stderr \
   --vmodule="blimp*=1"
 ```
diff --git a/blimp/engine/BUILD.gn b/blimp/engine/BUILD.gn
index 5bd4c21..a19eb10 100644
--- a/blimp/engine/BUILD.gn
+++ b/blimp/engine/BUILD.gn
@@ -223,6 +223,7 @@
       ":blimp_engine_app",
       ":pak",
       "//sandbox/linux:chrome_sandbox",
+      "//third_party/blimp_fonts",
     ]
 
     # List dependencies as both deps and data_deps to ensure changes trigger a
diff --git a/blimp/engine/DEPS b/blimp/engine/DEPS
index e4ebc4e..5c16370 100644
--- a/blimp/engine/DEPS
+++ b/blimp/engine/DEPS
@@ -6,6 +6,7 @@
   "+components/web_cache/renderer",
   "+content/public",
   "+net",
+  "+third_party/blimp_fonts",
   "+third_party/khronos/GLES2/gl2.h",
   "+third_party/WebKit/public/web/WebInputEvent.h",
   "+ui/aura",
diff --git a/blimp/engine/Dockerfile b/blimp/engine/Dockerfile
index 0410cf8..7e3cbbaa 100644
--- a/blimp/engine/Dockerfile
+++ b/blimp/engine/Dockerfile
@@ -13,7 +13,10 @@
 
 RUN useradd -ms /bin/bash blimp_user
 
+# The glob below expands to all files, but does not add directories
+# recursively.
 ADD * /engine/
+ADD gen/third_party/blimp_fonts /engine/fonts
 RUN mv /engine/chrome_sandbox /engine/chrome-sandbox
 RUN chown -R blimp_user /engine
 
@@ -21,4 +24,3 @@
 WORKDIR "/engine"
 
 ENTRYPOINT ["/engine/start_engine.sh"]
-
diff --git a/blimp/engine/engine-manifest.txt b/blimp/engine/engine-manifest.txt
index d84b8f9..b24bcc8b 100644
--- a/blimp/engine/engine-manifest.txt
+++ b/blimp/engine/engine-manifest.txt
@@ -1,7 +1,7 @@
 # Runtime dependencies for the Blimp Engine
 #
 # This file was generated by running:
-# generate-engine-manifest.py --build-dir out/Linux --target //blimp/engine:blimp_engine --output blimp/engine/engine-manifest.txt
+# generate-engine-manifest.py --build-dir out-chromeos/Debug --target //blimp/engine:blimp_engine --output blimp/engine/engine-manifest.txt
 #
 # Note: Any unnecessary dependencies should be added to
 #       manifest-blacklist.txt and this file should be regenerated.
@@ -9,4 +9,209 @@
 icudtl.dat
 natives_blob.bin
 blimp_engine.pak
-./chrome_sandbox
\ No newline at end of file
+./chrome_sandbox
+gen/third_party/blimp_fonts/AndroidClock.ttf
+gen/third_party/blimp_fonts/AndroidClock_Highlight.ttf
+gen/third_party/blimp_fonts/AndroidClock_Solid.ttf
+gen/third_party/blimp_fonts/CarroisGothicSC-Regular.ttf
+gen/third_party/blimp_fonts/Clockopia.ttf
+gen/third_party/blimp_fonts/ComingSoon.ttf
+gen/third_party/blimp_fonts/CutiveMono.ttf
+gen/third_party/blimp_fonts/DancingScript-Bold.ttf
+gen/third_party/blimp_fonts/DancingScript-Regular.ttf
+gen/third_party/blimp_fonts/DroidSansFallback.ttf
+gen/third_party/blimp_fonts/DroidSansFallbackFull.ttf
+gen/third_party/blimp_fonts/DroidSansMono.ttf
+gen/third_party/blimp_fonts/LICENSE
+gen/third_party/blimp_fonts/LICENSE.Apache
+gen/third_party/blimp_fonts/LICENSE.OFL
+gen/third_party/blimp_fonts/MTLc3m.ttf
+gen/third_party/blimp_fonts/MTLmr3m.ttf
+gen/third_party/blimp_fonts/NanumGothic.ttf
+gen/third_party/blimp_fonts/NanumGothicBold.ttf
+gen/third_party/blimp_fonts/NotoColorEmoji.ttf
+gen/third_party/blimp_fonts/NotoKufiArabic-Bold.ttf
+gen/third_party/blimp_fonts/NotoKufiArabic-Regular.ttf
+gen/third_party/blimp_fonts/NotoNaskhArabic-Bold.ttf
+gen/third_party/blimp_fonts/NotoNaskhArabic-Regular.ttf
+gen/third_party/blimp_fonts/NotoNaskhArabicUI-Bold.ttf
+gen/third_party/blimp_fonts/NotoNaskhArabicUI-Regular.ttf
+gen/third_party/blimp_fonts/NotoSans-Bold.ttf
+gen/third_party/blimp_fonts/NotoSans-BoldItalic.ttf
+gen/third_party/blimp_fonts/NotoSans-Italic.ttf
+gen/third_party/blimp_fonts/NotoSans-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansArmenian-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansArmenian-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansAvestan-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansBalinese-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansBamum-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansBatak-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansBengali-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansBengali-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansBengaliUI-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansBengaliUI-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansBrahmi-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansBuginese-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansBuhid-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansCanadianAboriginal-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansCarian-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansCham-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansCham-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansCherokee-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansCoptic-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansCuneiform-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansCypriot-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansDeseret-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansDevanagari-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansDevanagari-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansDevanagariUI-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansDevanagariUI-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansEgyptianHieroglyphs-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansEthiopic-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansEthiopic-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansGeorgian-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansGeorgian-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansGlagolitic-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansGothic-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansGujarati-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansGujarati-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansGujaratiUI-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansGujaratiUI-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansGurmukhi-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansGurmukhi-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansGurmukhiUI-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansGurmukhiUI-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansHanunoo-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansHebrew-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansHebrew-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansImperialAramaic-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansInscriptionalPahlavi-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansInscriptionalParthian-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansJP-Regular-Subsetted.otf
+gen/third_party/blimp_fonts/NotoSansJP-Regular.otf
+gen/third_party/blimp_fonts/NotoSansJavanese-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansKR-Regular.otf
+gen/third_party/blimp_fonts/NotoSansKaithi-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansKannada-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansKannada-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansKannadaUI-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansKannadaUI-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansKayahLi-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansKharoshthi-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansKhmer-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansKhmer-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansKhmerUI-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansKhmerUI-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansLao-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansLao-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansLaoUI-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansLaoUI-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansLepcha-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansLimbu-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansLinearB-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansLisu-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansLycian-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansLydian-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansMalayalam-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansMalayalam-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansMalayalamUI-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansMalayalamUI-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansMandaic-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansMeeteiMayek-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansMongolian-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansMyanmar-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansMyanmar-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansMyanmarUI-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansMyanmarUI-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansNKo-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansNewTaiLue-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansOgham-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansOlChiki-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansOldItalic-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansOldPersian-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansOldSouthArabian-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansOldTurkic-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansOriya-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansOriya-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansOriyaUI-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansOriyaUI-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansOsmanya-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansPhagsPa-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansPhoenician-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansRejang-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansRunic-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansSC-Regular.otf
+gen/third_party/blimp_fonts/NotoSansSamaritan-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansSaurashtra-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansShavian-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansSinhala-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansSinhala-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansSundanese-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansSylotiNagri-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansSymbols-Regular-Subsetted.ttf
+gen/third_party/blimp_fonts/NotoSansSymbols-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansSyriacEastern-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansSyriacEstrangela-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansSyriacWestern-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansTC-Regular.otf
+gen/third_party/blimp_fonts/NotoSansTagalog-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansTagbanwa-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansTaiLe-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansTaiTham-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansTaiViet-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansTamil-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansTamil-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansTamilUI-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansTamilUI-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansTelugu-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansTelugu-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansTeluguUI-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansTeluguUI-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansThaana-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansThaana-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansThai-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansThai-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansThaiUI-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansThaiUI-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansTibetan-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansTifinagh-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansUI-Bold.ttf
+gen/third_party/blimp_fonts/NotoSansUI-BoldItalic.ttf
+gen/third_party/blimp_fonts/NotoSansUI-Italic.ttf
+gen/third_party/blimp_fonts/NotoSansUI-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansUgaritic-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansVai-Regular.ttf
+gen/third_party/blimp_fonts/NotoSansYi-Regular.ttf
+gen/third_party/blimp_fonts/NotoSerif-Bold.ttf
+gen/third_party/blimp_fonts/NotoSerif-BoldItalic.ttf
+gen/third_party/blimp_fonts/NotoSerif-Italic.ttf
+gen/third_party/blimp_fonts/NotoSerif-Regular.ttf
+gen/third_party/blimp_fonts/NotoSerifArmenian-Bold.ttf
+gen/third_party/blimp_fonts/NotoSerifArmenian-Regular.ttf
+gen/third_party/blimp_fonts/NotoSerifGeorgian-Bold.ttf
+gen/third_party/blimp_fonts/NotoSerifGeorgian-Regular.ttf
+gen/third_party/blimp_fonts/NotoSerifKhmer-Bold.ttf
+gen/third_party/blimp_fonts/NotoSerifKhmer-Regular.ttf
+gen/third_party/blimp_fonts/NotoSerifLao-Bold.ttf
+gen/third_party/blimp_fonts/NotoSerifLao-Regular.ttf
+gen/third_party/blimp_fonts/NotoSerifThai-Bold.ttf
+gen/third_party/blimp_fonts/NotoSerifThai-Regular.ttf
+gen/third_party/blimp_fonts/Roboto-Black.ttf
+gen/third_party/blimp_fonts/Roboto-BlackItalic.ttf
+gen/third_party/blimp_fonts/Roboto-Bold.ttf
+gen/third_party/blimp_fonts/Roboto-BoldItalic.ttf
+gen/third_party/blimp_fonts/Roboto-Italic.ttf
+gen/third_party/blimp_fonts/Roboto-Light.ttf
+gen/third_party/blimp_fonts/Roboto-LightItalic.ttf
+gen/third_party/blimp_fonts/Roboto-Medium.ttf
+gen/third_party/blimp_fonts/Roboto-MediumItalic.ttf
+gen/third_party/blimp_fonts/Roboto-Regular.ttf
+gen/third_party/blimp_fonts/Roboto-Thin.ttf
+gen/third_party/blimp_fonts/Roboto-ThinItalic.ttf
+gen/third_party/blimp_fonts/RobotoCondensed-Bold.ttf
+gen/third_party/blimp_fonts/RobotoCondensed-BoldItalic.ttf
+gen/third_party/blimp_fonts/RobotoCondensed-Italic.ttf
+gen/third_party/blimp_fonts/RobotoCondensed-Light.ttf
+gen/third_party/blimp_fonts/RobotoCondensed-LightItalic.ttf
+gen/third_party/blimp_fonts/RobotoCondensed-Regular.ttf
+gen/third_party/blimp_fonts/fonts.xml
\ No newline at end of file
diff --git a/blimp/engine/start_engine.sh b/blimp/engine/start_engine.sh
index f507c24..a9cf193 100755
--- a/blimp/engine/start_engine.sh
+++ b/blimp/engine/start_engine.sh
@@ -8,11 +8,12 @@
   -p /engine/data/stunnel.pem \
   -P /engine/stunnel.pid \
   -d 25466 -r 25467 -f &
-/engine/blimp_engine_app \
+LD_LIBRARY_PATH=/engine/ /engine/blimp_engine_app \
   --disable-gpu \
   --use-remote-compositing \
   --disable-cached-picture-raster \
   --blimp-client-token-path=/engine/data/client_token \
+  --android-fonts-path=/engine/fonts \
   $@ &
 
 # Stop execution if either stunnel or blimp_engine_app die.
diff --git a/blimp/tools/manifest-blacklist.txt b/blimp/tools/manifest-blacklist.txt
index ce4c1c9b..d21b052a 100644
--- a/blimp/tools/manifest-blacklist.txt
+++ b/blimp/tools/manifest-blacklist.txt
@@ -2,13 +2,11 @@
 # Wildcards (* or ?) are allowed.
 
 *.mojo
+*mojom.js
 ./libfont_service_library.so
 ./libtracing_library.so
 ./libmus_library.so
 ./libosmesa.so
 ./libresource_provider_library.so
 ./mojo_runner
-gen/*
-mus/mus.mojo
 snapshot_blob.bin
-
diff --git a/build/config/gcc/BUILD.gn b/build/config/gcc/BUILD.gn
index 41473eb..2c1c61f 100644
--- a/build/config/gcc/BUILD.gn
+++ b/build/config/gcc/BUILD.gn
@@ -60,7 +60,7 @@
   }
 }
 
-# Settings for executables and shared libraries.
+# Settings for executables.
 config("executable_ldconfig") {
   if (is_android) {
     ldflags = [
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index 5d31a221..9b5c57f6 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -83,8 +83,6 @@
       clip_tree_index_(-1),
       scroll_tree_index_(-1),
       draw_depth_(0.f),
-      needs_push_properties_(false),
-      num_dependents_need_push_properties_(0),
       sorting_context_id_(0),
       current_draw_mode_(DRAW_MODE_NONE),
       element_id_(0),
@@ -129,6 +127,7 @@
     layer_tree_impl()->RemoveLayerWithCopyOutputRequest(this);
   layer_tree_impl_->UnregisterScrollLayer(this);
   layer_tree_impl_->UnregisterLayer(this);
+  layer_tree_impl_->RemoveLayerShouldPushProperties(this);
 
   layer_tree_impl_->RemoveFromElementMap(this);
 
@@ -158,12 +157,6 @@
 }
 
 void LayerImpl::SetParent(LayerImpl* parent) {
-  if (parent_should_know_need_push_properties()) {
-    if (parent_)
-      parent_->RemoveDependentNeedsPushProperties();
-    if (parent)
-      parent->AddDependentNeedsPushProperties();
-  }
   parent_ = parent;
 }
 
@@ -631,8 +624,7 @@
   // Reset any state that should be cleared for the next update.
   layer_property_changed_ = false;
   update_rect_ = gfx::Rect();
-  needs_push_properties_ = false;
-  num_dependents_need_push_properties_ = 0;
+  layer_tree_impl()->RemoveLayerShouldPushProperties(this);
 }
 
 bool LayerImpl::IsAffectedByPageScale() const {
@@ -763,7 +755,7 @@
   return "cc::LayerImpl";
 }
 
-void LayerImpl::ResetAllChangeTrackingForSubtree() {
+void LayerImpl::ResetAllChangeTrackingForSubtreeInternal() {
   layer_property_changed_ = false;
   if (TransformNode* transform_node =
           layer_tree_impl_->property_trees()->transform_tree.Node(
@@ -778,18 +770,20 @@
     render_surface_->ResetPropertyChangedFlag();
 
   if (mask_layer_)
-    mask_layer_->ResetAllChangeTrackingForSubtree();
+    mask_layer_->ResetAllChangeTrackingForSubtreeInternal();
 
   if (replica_layer_) {
     // This also resets the replica mask, if it exists.
-    replica_layer_->ResetAllChangeTrackingForSubtree();
+    replica_layer_->ResetAllChangeTrackingForSubtreeInternal();
   }
 
   for (size_t i = 0; i < children_.size(); ++i)
-    children_[i]->ResetAllChangeTrackingForSubtree();
+    children_[i]->ResetAllChangeTrackingForSubtreeInternal();
+}
 
-  needs_push_properties_ = false;
-  num_dependents_need_push_properties_ = 0;
+void LayerImpl::ResetAllChangeTrackingForSubtree() {
+  layer_tree_impl()->LayersThatShouldPushProperties().clear();
+  ResetAllChangeTrackingForSubtreeInternal();
 }
 
 int LayerImpl::num_copy_requests_in_target_subtree() {
@@ -1568,28 +1562,8 @@
 }
 
 void LayerImpl::SetNeedsPushProperties() {
-  if (needs_push_properties_)
-    return;
-  if (!parent_should_know_need_push_properties() && parent_)
-    parent_->AddDependentNeedsPushProperties();
-  needs_push_properties_ = true;
-}
-
-void LayerImpl::AddDependentNeedsPushProperties() {
-  DCHECK_GE(num_dependents_need_push_properties_, 0);
-
-  if (!parent_should_know_need_push_properties() && parent_)
-    parent_->AddDependentNeedsPushProperties();
-
-  num_dependents_need_push_properties_++;
-}
-
-void LayerImpl::RemoveDependentNeedsPushProperties() {
-  num_dependents_need_push_properties_--;
-  DCHECK_GE(num_dependents_need_push_properties_, 0);
-
-  if (!parent_should_know_need_push_properties() && parent_)
-      parent_->RemoveDependentNeedsPushProperties();
+  if (layer_tree_impl_)
+    layer_tree_impl()->AddLayerShouldPushProperties(this);
 }
 
 void LayerImpl::GetAllPrioritizedTilesForTracing(
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h
index 91d3e0d..211673b 100644
--- a/cc/layers/layer_impl.h
+++ b/cc/layers/layer_impl.h
@@ -591,16 +591,6 @@
   virtual size_t GPUMemoryUsageInBytes() const;
 
   void SetNeedsPushProperties();
-  void AddDependentNeedsPushProperties();
-  void RemoveDependentNeedsPushProperties();
-  bool parent_should_know_need_push_properties() const {
-    return needs_push_properties() || descendant_needs_push_properties();
-  }
-
-  bool needs_push_properties() const { return needs_push_properties_; }
-  bool descendant_needs_push_properties() const {
-    return num_dependents_need_push_properties_ > 0;
-  }
 
   virtual void RunMicroBenchmark(MicroBenchmarkImpl* benchmark);
 
@@ -701,6 +691,7 @@
 
   void NoteLayerPropertyChangedForDescendantsInternal();
   void PushLayerPropertyChangedForSubtreeInternal();
+  void ResetAllChangeTrackingForSubtreeInternal();
 
   virtual const char* LayerTypeAsString() const;
 
@@ -804,15 +795,6 @@
  protected:
   friend class TreeSynchronizer;
 
-  // This flag is set when the layer needs to push properties to the active
-  // side.
-  bool needs_push_properties_;
-
-  // The number of direct children or dependent layers that need to be recursed
-  // to in order for them or a descendent of them to push properties to the
-  // active side.
-  int num_dependents_need_push_properties_;
-
   // Layers that share a sorting context id will be sorted together in 3d
   // space.  0 is a special value that means this layer will not be sorted and
   // will be drawn in paint order.
diff --git a/cc/layers/layer_impl_unittest.cc b/cc/layers/layer_impl_unittest.cc
index a8336d8..bd221ce 100644
--- a/cc/layers/layer_impl_unittest.cc
+++ b/cc/layers/layer_impl_unittest.cc
@@ -26,48 +26,60 @@
 namespace cc {
 namespace {
 
-#define EXECUTE_AND_VERIFY_SUBTREE_CHANGED(code_to_test)             \
-  root->ResetAllChangeTrackingForSubtree();                          \
-  root->layer_tree_impl()->property_trees()->ResetAllChangeTracking( \
-      PropertyTrees::ResetFlags::ALL_TREES);                         \
-  code_to_test;                                                      \
-  EXPECT_TRUE(root->needs_push_properties());                        \
-  EXPECT_FALSE(child->needs_push_properties());                      \
-  EXPECT_FALSE(grand_child->needs_push_properties());                \
-  EXPECT_TRUE(root->LayerPropertyChanged());                         \
-  EXPECT_TRUE(child->LayerPropertyChanged());                        \
+#define EXECUTE_AND_VERIFY_SUBTREE_CHANGED(code_to_test)                    \
+  root->ResetAllChangeTrackingForSubtree();                                 \
+  root->layer_tree_impl()->property_trees()->ResetAllChangeTracking(        \
+      PropertyTrees::ResetFlags::ALL_TREES);                                \
+  code_to_test;                                                             \
+  EXPECT_TRUE(                                                              \
+      root->layer_tree_impl()->LayerNeedsPushPropertiesForTesting(root));   \
+  EXPECT_FALSE(                                                             \
+      root->layer_tree_impl()->LayerNeedsPushPropertiesForTesting(child));  \
+  EXPECT_FALSE(root->layer_tree_impl()->LayerNeedsPushPropertiesForTesting( \
+      grand_child));                                                        \
+  EXPECT_TRUE(root->LayerPropertyChanged());                                \
+  EXPECT_TRUE(child->LayerPropertyChanged());                               \
   EXPECT_TRUE(grand_child->LayerPropertyChanged());
 
-#define EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(code_to_test)                \
-  root->ResetAllChangeTrackingForSubtree();                                    \
-  code_to_test;                                                                \
-  EXPECT_FALSE(root->needs_push_properties());                                 \
-  EXPECT_FALSE(child->needs_push_properties());                                \
-  EXPECT_FALSE(grand_child->needs_push_properties());                          \
-  EXPECT_FALSE(root->LayerPropertyChanged());                                  \
-  EXPECT_FALSE(child->LayerPropertyChanged());                                 \
+#define EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(code_to_test)             \
+  root->ResetAllChangeTrackingForSubtree();                                 \
+  code_to_test;                                                             \
+  EXPECT_FALSE(                                                             \
+      root->layer_tree_impl()->LayerNeedsPushPropertiesForTesting(root));   \
+  EXPECT_FALSE(                                                             \
+      root->layer_tree_impl()->LayerNeedsPushPropertiesForTesting(child));  \
+  EXPECT_FALSE(root->layer_tree_impl()->LayerNeedsPushPropertiesForTesting( \
+      grand_child));                                                        \
+  EXPECT_FALSE(root->LayerPropertyChanged());                               \
+  EXPECT_FALSE(child->LayerPropertyChanged());                              \
   EXPECT_FALSE(grand_child->LayerPropertyChanged());
 
-#define EXECUTE_AND_VERIFY_NEEDS_PUSH_PROPERTIES_AND_SUBTREE_DID_NOT_CHANGE(   \
-      code_to_test)                                                            \
-  root->ResetAllChangeTrackingForSubtree();                                    \
-  code_to_test;                                                                \
-  EXPECT_TRUE(root->needs_push_properties());                                  \
-  EXPECT_FALSE(child->needs_push_properties());                                \
-  EXPECT_FALSE(grand_child->needs_push_properties());                          \
-  EXPECT_FALSE(root->LayerPropertyChanged());                                  \
-  EXPECT_FALSE(child->LayerPropertyChanged());                                 \
+#define EXECUTE_AND_VERIFY_NEEDS_PUSH_PROPERTIES_AND_SUBTREE_DID_NOT_CHANGE( \
+    code_to_test)                                                            \
+  root->ResetAllChangeTrackingForSubtree();                                  \
+  code_to_test;                                                              \
+  EXPECT_TRUE(                                                               \
+      root->layer_tree_impl()->LayerNeedsPushPropertiesForTesting(root));    \
+  EXPECT_FALSE(                                                              \
+      root->layer_tree_impl()->LayerNeedsPushPropertiesForTesting(child));   \
+  EXPECT_FALSE(root->layer_tree_impl()->LayerNeedsPushPropertiesForTesting(  \
+      grand_child));                                                         \
+  EXPECT_FALSE(root->LayerPropertyChanged());                                \
+  EXPECT_FALSE(child->LayerPropertyChanged());                               \
   EXPECT_FALSE(grand_child->LayerPropertyChanged());
 
-#define EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(code_to_test)             \
-  root->ResetAllChangeTrackingForSubtree();                             \
-  root->layer_tree_impl()->property_trees()->full_tree_damaged = false; \
-  code_to_test;                                                         \
-  EXPECT_TRUE(root->needs_push_properties());                           \
-  EXPECT_FALSE(child->needs_push_properties());                         \
-  EXPECT_FALSE(grand_child->needs_push_properties());                   \
-  EXPECT_TRUE(root->LayerPropertyChanged());                            \
-  EXPECT_FALSE(child->LayerPropertyChanged());                          \
+#define EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(code_to_test)                 \
+  root->ResetAllChangeTrackingForSubtree();                                 \
+  root->layer_tree_impl()->property_trees()->full_tree_damaged = false;     \
+  code_to_test;                                                             \
+  EXPECT_TRUE(                                                              \
+      root->layer_tree_impl()->LayerNeedsPushPropertiesForTesting(root));   \
+  EXPECT_FALSE(                                                             \
+      root->layer_tree_impl()->LayerNeedsPushPropertiesForTesting(child));  \
+  EXPECT_FALSE(root->layer_tree_impl()->LayerNeedsPushPropertiesForTesting( \
+      grand_child));                                                        \
+  EXPECT_TRUE(root->LayerPropertyChanged());                                \
+  EXPECT_FALSE(child->LayerPropertyChanged());                              \
   EXPECT_FALSE(grand_child->LayerPropertyChanged());
 
 #define VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(code_to_test)                \
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index 8e823d9..a12fb282 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -140,7 +140,7 @@
   // We always need to push properties.
   // See http://crbug.com/303943
   // TODO(danakj): Stop always pushing properties since we don't swap tilings.
-  needs_push_properties_ = true;
+  layer_tree_impl()->AddLayerShouldPushProperties(this);
 }
 
 void PictureLayerImpl::AppendQuads(RenderPass* render_pass,
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index c7bcf2c..adf570b5 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -1983,8 +1983,14 @@
       else
         active_tree_->root_layer()->PushLayerPropertyChangedForSubtree();
     }
-    TreeSynchronizer::PushProperties(pending_tree_->root_layer(),
-                                     active_tree_->root_layer());
+
+    std::unordered_set<LayerImpl*> layers_that_should_push_properties =
+        pending_tree_->LayersThatShouldPushProperties();
+    for (auto pending_layer : layers_that_should_push_properties) {
+      LayerImpl* active_layer = active_tree_->LayerById(pending_layer->id());
+      DCHECK(active_layer);
+      pending_layer->PushPropertiesTo(active_layer);
+    }
     pending_tree_->PushPropertiesTo(active_tree_.get());
     if (pending_tree_->root_layer())
       pending_tree_->property_trees()->ResetAllChangeTracking(
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index 89567a5e..87fe6cf6 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -956,6 +956,24 @@
   return iter != layer_id_map_.end() ? iter->second : NULL;
 }
 
+void LayerTreeImpl::AddLayerShouldPushProperties(LayerImpl* layer) {
+  layers_that_should_push_properties_.insert(layer);
+}
+
+void LayerTreeImpl::RemoveLayerShouldPushProperties(LayerImpl* layer) {
+  layers_that_should_push_properties_.erase(layer);
+}
+
+std::unordered_set<LayerImpl*>&
+LayerTreeImpl::LayersThatShouldPushProperties() {
+  return layers_that_should_push_properties_;
+}
+
+bool LayerTreeImpl::LayerNeedsPushPropertiesForTesting(LayerImpl* layer) {
+  return layers_that_should_push_properties_.find(layer) !=
+         layers_that_should_push_properties_.end();
+}
+
 void LayerTreeImpl::RegisterLayer(LayerImpl* layer) {
   DCHECK(!LayerById(layer->id()));
   layer_id_map_[layer->id()] = layer;
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h
index 9f20b13..57523f97 100644
--- a/cc/trees/layer_tree_impl.h
+++ b/cc/trees/layer_tree_impl.h
@@ -299,6 +299,11 @@
 
   LayerImpl* LayerById(int id) const;
 
+  void AddLayerShouldPushProperties(LayerImpl* layer);
+  void RemoveLayerShouldPushProperties(LayerImpl* layer);
+  std::unordered_set<LayerImpl*>& LayersThatShouldPushProperties();
+  bool LayerNeedsPushPropertiesForTesting(LayerImpl* layer);
+
   // These should be called by LayerImpl's ctor/dtor.
   void RegisterLayer(LayerImpl* layer);
   void UnregisterLayer(LayerImpl* layer);
@@ -515,6 +520,8 @@
 
   using LayerIdMap = std::unordered_map<int, LayerImpl*>;
   LayerIdMap layer_id_map_;
+  // Set of layers that need to push properties.
+  std::unordered_set<LayerImpl*> layers_that_should_push_properties_;
 
   std::unordered_map<uint64_t, ElementLayers> element_layers_map_;
 
diff --git a/cc/trees/tree_synchronizer.cc b/cc/trees/tree_synchronizer.cc
index a257c57b..af87056 100644
--- a/cc/trees/tree_synchronizer.cc
+++ b/cc/trees/tree_synchronizer.cc
@@ -129,10 +129,8 @@
       new_layers, old_layers, layer, tree_impl);
 }
 
-// static
-template <typename LayerType>
 void TreeSynchronizer::PushPropertiesInternal(
-    LayerType* layer,
+    Layer* layer,
     LayerImpl* layer_impl,
     int* num_dependents_need_push_properties_for_parent) {
   if (!layer) {
@@ -246,10 +244,4 @@
 #endif
 }
 
-void TreeSynchronizer::PushProperties(LayerImpl* layer, LayerImpl* layer_impl) {
-  int num_dependents_need_push_properties = 0;
-  PushPropertiesInternal(
-      layer, layer_impl, &num_dependents_need_push_properties);
-}
-
 }  // namespace cc
diff --git a/cc/trees/tree_synchronizer.h b/cc/trees/tree_synchronizer.h
index a580362c..2e6e8f09 100644
--- a/cc/trees/tree_synchronizer.h
+++ b/cc/trees/tree_synchronizer.h
@@ -38,9 +38,8 @@
  private:
   TreeSynchronizer();  // Not instantiable.
 
-  template <typename LayerType>
   static void PushPropertiesInternal(
-      LayerType* layer,
+      Layer* layer,
       LayerImpl* layer_impl,
       int* num_dependents_need_push_properties_for_parent);
 
diff --git a/chrome/VERSION b/chrome/VERSION
index 8be6c9e2..e9cb17c0 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=51
 MINOR=0
-BUILD=2671
+BUILD=2672
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java
index 2780051..12f58378 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java
@@ -15,6 +15,7 @@
 import android.text.style.ClickableSpan;
 import android.view.View;
 
+import org.chromium.base.VisibleForTesting;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.omnibox.OmniboxUrlEmphasizer;
@@ -35,14 +36,14 @@
         implements ItemChooserDialog.ItemSelectedCallback, WindowAndroid.PermissionCallback {
     // These constants match BluetoothChooserAndroid::ShowDiscoveryState, and are used in
     // notifyDiscoveryState().
-    private static final int DISCOVERY_FAILED_TO_START = 0;
-    private static final int DISCOVERING = 1;
-    private static final int DISCOVERY_IDLE = 2;
+    static final int DISCOVERY_FAILED_TO_START = 0;
+    static final int DISCOVERING = 1;
+    static final int DISCOVERY_IDLE = 2;
 
     // Values passed to nativeOnDialogFinished:eventType, and only used in the native function.
-    private static final int DIALOG_FINISHED_DENIED_PERMISSION = 0;
-    private static final int DIALOG_FINISHED_CANCELLED = 1;
-    private static final int DIALOG_FINISHED_SELECTED = 2;
+    static final int DIALOG_FINISHED_DENIED_PERMISSION = 0;
+    static final int DIALOG_FINISHED_CANCELLED = 1;
+    static final int DIALOG_FINISHED_SELECTED = 2;
 
     // The window that owns this dialog.
     final WindowAndroid mWindowAndroid;
@@ -79,7 +80,8 @@
      *
      * @param context Context which is used for launching a dialog.
      */
-    private BluetoothChooserDialog(WindowAndroid windowAndroid, String origin, int securityLevel,
+    @VisibleForTesting
+    BluetoothChooserDialog(WindowAndroid windowAndroid, String origin, int securityLevel,
             long nativeBluetoothChooserDialogPtr) {
         mWindowAndroid = windowAndroid;
         mContext = windowAndroid.getActivity().get();
@@ -92,7 +94,8 @@
     /**
      * Show the BluetoothChooserDialog.
      */
-    private void show() {
+    @VisibleForTesting
+    void show() {
         // Emphasize the origin.
         Profile profile = Profile.getLastUsedProfile();
         SpannableString origin = new SpannableString(mOrigin);
@@ -287,27 +290,31 @@
         return dialog;
     }
 
+    @VisibleForTesting
     @CalledByNative
-    private void addDevice(String deviceId, String deviceName) {
+    void addDevice(String deviceId, String deviceName) {
         List<ItemChooserDialog.ItemChooserRow> devices =
                 new ArrayList<ItemChooserDialog.ItemChooserRow>();
         devices.add(new ItemChooserDialog.ItemChooserRow(deviceId, deviceName));
         mItemChooserDialog.addItemsToList(devices);
     }
 
+    @VisibleForTesting
     @CalledByNative
-    private void closeDialog() {
+    void closeDialog() {
         mNativeBluetoothChooserDialogPtr = 0;
         mItemChooserDialog.dismiss();
     }
 
+    @VisibleForTesting
     @CalledByNative
-    private void removeDevice(String deviceId) {
+    void removeDevice(String deviceId) {
         mItemChooserDialog.setEnabled(deviceId, false);
     }
 
+    @VisibleForTesting
     @CalledByNative
-    private void notifyAdapterTurnedOff() {
+    void notifyAdapterTurnedOff() {
         SpannableString adapterOffMessage = SpanApplier.applySpans(
                 mContext.getString(R.string.bluetooth_adapter_off),
                 new SpanInfo("<link>", "</link>",
@@ -328,8 +335,9 @@
         }
     }
 
+    @VisibleForTesting
     @CalledByNative
-    private void notifyDiscoveryState(int discoveryState) {
+    void notifyDiscoveryState(int discoveryState) {
         switch (discoveryState) {
             case DISCOVERY_FAILED_TO_START: {
                 // FAILED_TO_START might be caused by a missing Location permission.
@@ -348,11 +356,16 @@
         }
     }
 
-    private native void nativeOnDialogFinished(
+    @VisibleForTesting
+    native void nativeOnDialogFinished(
             long nativeBluetoothChooserAndroid, int eventType, String deviceId);
-    private native void nativeRestartSearch(long nativeBluetoothChooserAndroid);
+    @VisibleForTesting
+    native void nativeRestartSearch(long nativeBluetoothChooserAndroid);
     // Help links.
-    private native void nativeShowBluetoothOverviewLink(long nativeBluetoothChooserAndroid);
-    private native void nativeShowBluetoothAdapterOffLink(long nativeBluetoothChooserAndroid);
-    private native void nativeShowNeedLocationPermissionLink(long nativeBluetoothChooserAndroid);
+    @VisibleForTesting
+    native void nativeShowBluetoothOverviewLink(long nativeBluetoothChooserAndroid);
+    @VisibleForTesting
+    native void nativeShowBluetoothAdapterOffLink(long nativeBluetoothChooserAndroid);
+    @VisibleForTesting
+    native void nativeShowNeedLocationPermissionLink(long nativeBluetoothChooserAndroid);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
index c7cc7ff0..9b44f6a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -181,13 +181,18 @@
 
     @Override
     public void onStop() {
-        super.onStop();
-        CustomTabsConnection.getInstance(getApplication())
-                .dontKeepAliveForSession(mIntentDataProvider.getSession());
+        // This happens before super.onStop() to maximize chances of getting the Tab while it's
+        // alive.
+        // TODO(dfalcantara): Once this is addressed on M50, consider transferring the Tab directly
+        //                    via Tab reparenting.
         if (mIntentDataProvider.isOpenedByBrowser()) {
             createHerbResultIntent(RESULT_STOPPED);
             finish();
         }
+
+        super.onStop();
+        CustomTabsConnection.getInstance(getApplication())
+                .dontKeepAliveForSession(mIntentDataProvider.getSession());
     }
 
     @Override
@@ -552,8 +557,7 @@
                                 && TextUtils.equals(getPackageName(), creatorPackage)) {
                             RecordUserAction.record(
                                     "TaskManagement.OpenInChromeActionButtonClicked");
-                            openCurrentUrlInBrowser();
-                            finish();
+                            if (openCurrentUrlInBrowser()) finish();
                         } else {
                             mIntentDataProvider.sendButtonPendingIntentWithUrl(
                                     getApplicationContext(), getActivityTab().getUrl());
@@ -721,9 +725,12 @@
 
     /**
      * Opens the URL currently being displayed in the Custom Tab in the regular browser.
+     *
+     * @return Whether or not the tab was sent over successfully.
      */
-    void openCurrentUrlInBrowser() {
-        if (getActivityTab() == null) return;
+    boolean openCurrentUrlInBrowser() {
+        if (getActivityTab() == null) return false;
+
         String url = getTabModelSelector().getCurrentTab().getUrl();
         if (DomDistillerUrlUtils.isDistilledPage(url)) {
             url = DomDistillerUrlUtils.getOriginalUrlFromDistillerUrl(url);
@@ -776,6 +783,7 @@
         } finally {
             StrictMode.setThreadPolicy(oldPolicy);
         }
+        return true;
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ClearBrowsingDataCheckBoxPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ClearBrowsingDataCheckBoxPreference.java
index 05072296..a7d360c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ClearBrowsingDataCheckBoxPreference.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ClearBrowsingDataCheckBoxPreference.java
@@ -17,6 +17,7 @@
  * A preference representing one browsing data type in ClearBrowsingDataPreferences.
  */
 public class ClearBrowsingDataCheckBoxPreference extends ChromeBaseCheckBoxPreference {
+    private LinearLayout mView;
 
     /**
      * Constructor for inflating from XML.
@@ -27,18 +28,20 @@
 
     @Override
     public View onCreateView(ViewGroup parent) {
-        LinearLayout view = (LinearLayout) super.onCreateView(parent);
+        if (mView != null) return mView;
+
+        mView = (LinearLayout) super.onCreateView(parent);
 
         // Checkboxes in the Clear Browsing Data dialog will show and hide the results of
         // BrowsingDataCounter. It is important that they will not change height when doing so.
         // We will therefore set a fixed height.
         int height = getContext().getResources().getDimensionPixelSize(
                 R.dimen.clear_browsing_data_checkbox_height);
-        view.setMinimumHeight(height);
+        mView.setMinimumHeight(height);
 
         // The title and summary are enclosed in a common RelativeLayout. We must remove
         // its vertical padding for it to be correctly vertically centered in the fixed-height view.
-        View textLayout = (View) view.findViewById(android.R.id.title).getParent();
+        View textLayout = (View) mView.findViewById(android.R.id.title).getParent();
         ApiCompatibilityUtils.setPaddingRelative(
                 textLayout,
                 ApiCompatibilityUtils.getPaddingStart(textLayout),
@@ -46,6 +49,10 @@
                 ApiCompatibilityUtils.getPaddingEnd(textLayout),
                 0);
 
-        return view;
+        return mView;
+    }
+
+    public void announceForAccessibility(CharSequence announcement) {
+        if (mView != null) mView.announceForAccessibility(announcement);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SpinnerPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SpinnerPreference.java
index ff8b6e09..1ad2a640 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SpinnerPreference.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SpinnerPreference.java
@@ -23,6 +23,7 @@
     private Spinner mSpinner;
     private ArrayAdapter<Object> mAdapter;
     private int mSelectedIndex;
+    private View mView;
 
     /**
      * Constructor for inflating from XML.
@@ -55,10 +56,11 @@
 
     @Override
     public View onCreateView(ViewGroup parent) {
-        View view = super.onCreateView(parent);
+        if (mView != null) return mView;
 
-        ((TextView) view.findViewById(R.id.title)).setText(getTitle());
-        mSpinner = (Spinner) view.findViewById(R.id.spinner);
+        mView = super.onCreateView(parent);
+        ((TextView) mView.findViewById(R.id.title)).setText(getTitle());
+        mSpinner = (Spinner) mView.findViewById(R.id.spinner);
         mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
             @Override
             public void onItemSelected(
@@ -76,12 +78,19 @@
             }
         });
 
-        return view;
+        return mView;
     }
 
     @Override
     protected void onBindView(View view) {
-        mSpinner.setAdapter(mAdapter);
+        super.onBindView(view);
+
+        // Screen readers notice the setAdapter() call and announce it. We do not want the spinner
+        // to be announced every time the view is bound (e.g. when the user scrolls away from it
+        // and then back). Therefore, only update the adapter if it has actually changed.
+        if (mSpinner.getAdapter() != mAdapter) {
+            mSpinner.setAdapter(mAdapter);
+        }
         mSpinner.setSelection(mSelectedIndex);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferences.java
index 54e1914..ee0a710 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferences.java
@@ -7,7 +7,6 @@
 import android.app.Activity;
 import android.app.ProgressDialog;
 import android.os.Bundle;
-import android.preference.CheckBoxPreference;
 import android.preference.Preference;
 import android.preference.PreferenceFragment;
 import android.widget.ListView;
@@ -16,6 +15,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.BrowsingDataType;
 import org.chromium.chrome.browser.preferences.ButtonPreference;
+import org.chromium.chrome.browser.preferences.ClearBrowsingDataCheckBoxPreference;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 import org.chromium.chrome.browser.preferences.SpinnerPreference;
 import org.chromium.chrome.browser.preferences.privacy.BrowsingDataCounterBridge.BrowsingDataCounterCallback;
@@ -39,19 +39,20 @@
                                          Preference.OnPreferenceClickListener {
         private final ClearBrowsingDataPreferences mParent;
         private final DialogOption mOption;
-        private final CheckBoxPreference mCheckbox;
+        private final ClearBrowsingDataCheckBoxPreference mCheckbox;
         private BrowsingDataCounterBridge mCounter;
+        private boolean mShouldAnnounceCounterResult;
 
         public Item(ClearBrowsingDataPreferences parent,
                     DialogOption option,
-                    CheckBoxPreference checkbox,
+                    ClearBrowsingDataCheckBoxPreference checkbox,
                     boolean selected,
                     boolean enabled) {
             super();
             mParent = parent;
             mOption = option;
-            mCounter = new BrowsingDataCounterBridge(this, mOption.getDataType());
             mCheckbox = checkbox;
+            mCounter = new BrowsingDataCounterBridge(this, mOption.getDataType());
 
             mCheckbox.setOnPreferenceClickListener(this);
             mCheckbox.setEnabled(enabled);
@@ -76,6 +77,7 @@
             assert mCheckbox == preference;
 
             mParent.updateButtonState();
+            mShouldAnnounceCounterResult = true;
             PrefServiceBridge.getInstance().setBrowsingDataDeletionPreference(
                     mOption.getDataType(), mCheckbox.isChecked());
             return true;
@@ -83,7 +85,19 @@
 
         @Override
         public void onCounterFinished(String result) {
-            if (mCheckbox != null) mCheckbox.setSummaryOn(result);
+            mCheckbox.setSummaryOn(result);
+            if (mShouldAnnounceCounterResult) {
+                mCheckbox.announceForAccessibility(result);
+            }
+        }
+
+        /**
+         * Sets whether the BrowsingDataCounter result should be announced. This is when the counter
+         * recalculation was caused by a checkbox state change (as opposed to fragment
+         * initialization or time period change).
+         */
+        public void setShouldAnnounceCounterResult(boolean value) {
+            mShouldAnnounceCounterResult = value;
         }
     }
 
@@ -272,6 +286,12 @@
     @Override
     public boolean onPreferenceChange(Preference preference, Object value) {
         if (preference.getKey().equals(PREF_TIME_RANGE)) {
+            // Inform the items that a recalculation is going to happen as a result of the time
+            // period change.
+            for (Item item : mItems) {
+                item.setShouldAnnounceCounterResult(false);
+            }
+
             PrefServiceBridge.getInstance().setBrowsingDataDeletionTimePeriod(
                     ((TimePeriodSpinnerOption) value).getTimePeriod());
             return true;
@@ -310,7 +330,7 @@
             mItems[i] = new Item(
                 this,
                 options[i],
-                (CheckBoxPreference) findPreference(options[i].getPreferenceKey()),
+                (ClearBrowsingDataCheckBoxPreference) findPreference(options[i].getPreferenceKey()),
                 isOptionSelectedByDefault(options[i]),
                 enabled);
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
index f1cdf130..d960e737 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
@@ -186,28 +186,29 @@
         CommandLine.addResetListener(sResetListener);
     }
 
+    private static boolean isHerbDisallowed(Context context) {
+        return isDocumentMode(context) || ChromeVersionInfo.isStableBuild()
+                || ChromeVersionInfo.isBetaBuild() || DeviceFormFactor.isTablet(context);
+    }
+
     /**
      * @return Which flavor of Herb is being tested.  See {@link ChromeSwitches#HERB_FLAVOR_ANISE}
      *         and its related switches.
      */
     public static String getHerbFlavor() {
+        Context context = ApplicationStatus.getApplicationContext();
+        if (isHerbDisallowed(context)) return ChromeSwitches.HERB_FLAVOR_DISABLED;
+
         if (!sIsHerbFlavorCached) {
             sCachedHerbFlavor = null;
 
-            Context context = ApplicationStatus.getApplicationContext();
-            if (isDocumentMode(context) || ChromeVersionInfo.isStableBuild()
-                    || ChromeVersionInfo.isBetaBuild() || DeviceFormFactor.isTablet(context)) {
-                // Disable Herb.
-                sCachedHerbFlavor = ChromeSwitches.HERB_FLAVOR_DISABLED;
-            } else {
-                // Allowing disk access for preferences while prototyping.
-                StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-                try {
-                    sCachedHerbFlavor =
-                            ChromePreferenceManager.getInstance(context).getCachedHerbFlavor();
-                } finally {
-                    StrictMode.setThreadPolicy(oldPolicy);
-                }
+            // Allowing disk access for preferences while prototyping.
+            StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+            try {
+                sCachedHerbFlavor =
+                        ChromePreferenceManager.getInstance(context).getCachedHerbFlavor();
+            } finally {
+                StrictMode.setThreadPolicy(oldPolicy);
             }
 
             sIsHerbFlavorCached = true;
@@ -221,6 +222,9 @@
      * Caches which flavor of Herb the user prefers from native.
      */
     public static void cacheHerbFlavor() {
+        Context context = ApplicationStatus.getApplicationContext();
+        if (isHerbDisallowed(context)) return;
+
         String oldFlavor = getHerbFlavor();
 
         // Check the experiment value before the command line to put the user in the correct group.
@@ -258,7 +262,6 @@
         sCachedHerbFlavor = newFlavor;
 
         if (!TextUtils.equals(oldFlavor, newFlavor)) {
-            Context context = ApplicationStatus.getApplicationContext();
             ChromePreferenceManager.getInstance(context).setCachedHerbFlavor(newFlavor);
         }
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/BluetoothChooserDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/BluetoothChooserDialogTest.java
new file mode 100644
index 0000000..5ab4b84d
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/BluetoothChooserDialogTest.java
@@ -0,0 +1,311 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser;
+
+import android.Manifest;
+import android.app.Dialog;
+import android.content.pm.PackageManager;
+import android.test.MoreAsserts;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ListView;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.chrome.R;
+import org.chromium.chrome.test.ChromeActivityTestCaseBase;
+import org.chromium.components.security_state.ConnectionSecurityLevel;
+import org.chromium.content.browser.test.util.Criteria;
+import org.chromium.content.browser.test.util.CriteriaHelper;
+import org.chromium.content.browser.test.util.TouchCommon;
+import org.chromium.ui.base.ActivityWindowAndroid;
+import org.chromium.ui.base.AndroidPermissionDelegate;
+import org.chromium.ui.base.WindowAndroid;
+import org.chromium.ui.base.WindowAndroid.PermissionCallback;
+import org.chromium.ui.widget.TextViewWithClickableSpans;
+
+import java.util.concurrent.Callable;
+
+/**
+ * Tests for the BluetoothChooserDialog class.
+ */
+public class BluetoothChooserDialogTest extends ChromeActivityTestCaseBase<ChromeActivity> {
+    /**
+     * Works like the BluetoothChooserDialog class, but records calls to native methods instead of
+     * calling back to C++.
+     */
+    static class BluetoothChooserDialogWithFakeNatives extends BluetoothChooserDialog {
+        int mFinishedEventType = -1;
+        String mFinishedDeviceId;
+
+        BluetoothChooserDialogWithFakeNatives(WindowAndroid windowAndroid, String origin,
+                int securityLevel, long nativeBluetoothChooserDialogPtr) {
+            super(windowAndroid, origin, securityLevel, nativeBluetoothChooserDialogPtr);
+        }
+
+        @Override
+        void nativeOnDialogFinished(
+                long nativeBluetoothChooserAndroid, int eventType, String deviceId) {
+            assertEquals(nativeBluetoothChooserAndroid, mNativeBluetoothChooserDialogPtr);
+            assertEquals(mFinishedEventType, -1);
+            mFinishedEventType = eventType;
+            mFinishedDeviceId = deviceId;
+        }
+
+        @Override
+        void nativeRestartSearch(long nativeBluetoothChooserAndroid) {}
+
+        @Override
+        void nativeShowBluetoothOverviewLink(long nativeBluetoothChooserAndroid) {}
+
+        @Override
+        void nativeShowBluetoothAdapterOffLink(long nativeBluetoothChooserAndroid) {}
+
+        @Override
+        void nativeShowNeedLocationPermissionLink(long nativeBluetoothChooserAndroid) {}
+    }
+
+    private ActivityWindowAndroid mWindowAndroid;
+    private BluetoothChooserDialogWithFakeNatives mChooserDialog;
+
+    public BluetoothChooserDialogTest() {
+        super(ChromeActivity.class);
+    }
+
+    // ChromeActivityTestCaseBase:
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mChooserDialog = createDialog();
+    }
+
+    @Override
+    public void startMainActivity() throws InterruptedException {
+        startMainActivityOnBlankPage();
+    }
+
+    private BluetoothChooserDialogWithFakeNatives createDialog() {
+        return ThreadUtils.runOnUiThreadBlockingNoException(
+                new Callable<BluetoothChooserDialogWithFakeNatives>() {
+                    @Override
+                    public BluetoothChooserDialogWithFakeNatives call() {
+                        mWindowAndroid = new ActivityWindowAndroid(getActivity());
+                        BluetoothChooserDialogWithFakeNatives dialog =
+                                new BluetoothChooserDialogWithFakeNatives(mWindowAndroid,
+                                        "https://origin.example.com/",
+                                        ConnectionSecurityLevel.SECURE, 42);
+                        dialog.show();
+                        return dialog;
+                    }
+                });
+    }
+
+    private static void selectItem(final BluetoothChooserDialogWithFakeNatives chooserDialog,
+            int position) throws InterruptedException {
+        final Dialog dialog = chooserDialog.mItemChooserDialog.getDialogForTesting();
+        final ListView items = (ListView) dialog.findViewById(R.id.items);
+        final Button button = (Button) dialog.findViewById(R.id.positive);
+
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                return items.getChildAt(0) != null;
+            }
+        });
+
+        assertEquals("Not all items have a view; positions may be incorrect.",
+                items.getChildCount(), items.getAdapter().getCount());
+
+        // Verify first item selected gets selected.
+        TouchCommon.singleClickView(items.getChildAt(position - 1));
+
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                return button.isEnabled();
+            }
+        });
+
+        TouchCommon.singleClickView(button);
+
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                return chooserDialog.mFinishedEventType != -1;
+            }
+        });
+    }
+
+    /**
+     * The messages include <link> ... </link> sections that are used to create
+     * clickable spans. For testing the messages, this function returns the raw
+     * string without the tags.
+     */
+    private static String removeLinkTags(String message) {
+        return message.replaceAll("</?link>", "");
+    }
+
+    @SmallTest
+    public void testCancel() throws InterruptedException {
+        ItemChooserDialog itemChooser = mChooserDialog.mItemChooserDialog;
+        Dialog dialog = itemChooser.getDialogForTesting();
+        assertTrue(dialog.isShowing());
+
+        TextViewWithClickableSpans statusView =
+                (TextViewWithClickableSpans) dialog.findViewById(R.id.status);
+        final ListView items = (ListView) dialog.findViewById(R.id.items);
+        final Button button = (Button) dialog.findViewById(R.id.positive);
+
+        // Before we add items to the dialog, the 'searching' message should be
+        // showing, the Commit button should be disabled and the list view hidden.
+        assertEquals(removeLinkTags(getActivity().getString(R.string.bluetooth_searching)),
+                statusView.getText().toString());
+        assertFalse(button.isEnabled());
+        assertEquals(View.GONE, items.getVisibility());
+
+        dialog.dismiss();
+
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                return mChooserDialog.mFinishedEventType != -1;
+            }
+        });
+
+        assertEquals(BluetoothChooserDialog.DIALOG_FINISHED_CANCELLED,
+                mChooserDialog.mFinishedEventType);
+        assertEquals("", mChooserDialog.mFinishedDeviceId);
+    }
+
+    @SmallTest
+    public void testSelectItem() throws InterruptedException {
+        Dialog dialog = mChooserDialog.mItemChooserDialog.getDialogForTesting();
+
+        TextViewWithClickableSpans statusView =
+                (TextViewWithClickableSpans) dialog.findViewById(R.id.status);
+        final View items = dialog.findViewById(R.id.items);
+        final Button button = (Button) dialog.findViewById(R.id.positive);
+        final View progress = dialog.findViewById(R.id.progress);
+
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mChooserDialog.addDevice("id-1", "Name 1");
+                mChooserDialog.addDevice("id-2", "Name 2");
+            }
+        });
+
+        // After adding items to the dialog, the help message should be showing,
+        // the progress spinner should disappear, the Commit button should still
+        // be disabled (since nothing's selected), and the list view should
+        // show.
+        assertEquals(removeLinkTags(getActivity().getString(R.string.bluetooth_not_seeing_it)),
+                statusView.getText().toString());
+        assertFalse(button.isEnabled());
+        assertEquals(View.VISIBLE, items.getVisibility());
+        assertEquals(View.GONE, progress.getVisibility());
+
+        selectItem(mChooserDialog, 2);
+
+        assertEquals(
+                BluetoothChooserDialog.DIALOG_FINISHED_SELECTED, mChooserDialog.mFinishedEventType);
+        assertEquals("id-2", mChooserDialog.mFinishedDeviceId);
+    }
+
+    @SmallTest
+    public void testNoLocationPermission() throws InterruptedException {
+        ItemChooserDialog itemChooser = mChooserDialog.mItemChooserDialog;
+        Dialog dialog = itemChooser.getDialogForTesting();
+        assertTrue(dialog.isShowing());
+
+        final TextViewWithClickableSpans statusView =
+                (TextViewWithClickableSpans) dialog.findViewById(R.id.status);
+        final TextViewWithClickableSpans errorView =
+                (TextViewWithClickableSpans) dialog.findViewById(R.id.not_found_message);
+        final View items = dialog.findViewById(R.id.items);
+        final Button button = (Button) dialog.findViewById(R.id.positive);
+        final View progress = dialog.findViewById(R.id.progress);
+
+        final TestAndroidPermissionDelegate permissionDelegate =
+                new TestAndroidPermissionDelegate();
+        mWindowAndroid.setAndroidPermissionDelegate(permissionDelegate);
+
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mChooserDialog.notifyDiscoveryState(
+                        BluetoothChooserDialog.DISCOVERY_FAILED_TO_START);
+            }
+        });
+
+        assertEquals(removeLinkTags(
+                             getActivity().getString(R.string.bluetooth_need_location_permission)),
+                errorView.getText().toString());
+        assertEquals(removeLinkTags(getActivity().getString(R.string.bluetooth_adapter_off_help)),
+                statusView.getText().toString());
+        assertFalse(button.isEnabled());
+        assertEquals(View.VISIBLE, errorView.getVisibility());
+        assertEquals(View.GONE, items.getVisibility());
+        assertEquals(View.GONE, progress.getVisibility());
+
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                errorView.getClickableSpans()[0].onClick(errorView);
+            }
+        });
+
+        // Permission was requested.
+        MoreAsserts.assertEquals(permissionDelegate.mPermissionsRequested,
+                new String[] {Manifest.permission.ACCESS_COARSE_LOCATION});
+        assertNotNull(permissionDelegate.mCallback);
+        // Grant permission.
+        permissionDelegate.mLocationGranted = true;
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                permissionDelegate.mCallback.onRequestPermissionsResult(
+                        new String[] {Manifest.permission.ACCESS_FINE_LOCATION},
+                        new int[] {PackageManager.PERMISSION_GRANTED});
+            }
+        });
+
+        assertEquals(removeLinkTags(getActivity().getString(R.string.bluetooth_adapter_off_help)),
+                statusView.getText().toString());
+
+        mChooserDialog.closeDialog();
+    }
+
+    // TODO(jyasskin): Test when the user denies Chrome the ability to ask for permission.
+
+    private static class TestAndroidPermissionDelegate implements AndroidPermissionDelegate {
+        boolean mLocationGranted = false;
+        PermissionCallback mCallback = null;
+        String[] mPermissionsRequested = null;
+
+        @Override
+        public boolean hasPermission(String permission) {
+            return permission.equals(Manifest.permission.ACCESS_COARSE_LOCATION)
+                    && mLocationGranted;
+        }
+        @Override
+        public boolean canRequestPermission(String permission) {
+            return true;
+        }
+        @Override
+        public boolean isPermissionRevokedByPolicy(String permission) {
+            return false;
+        }
+        @Override
+        public void requestPermissions(String[] permissions, PermissionCallback callback) {
+            mPermissionsRequested = permissions;
+            if (permissions.length == 1
+                    && permissions[0].equals(Manifest.permission.ACCESS_COARSE_LOCATION)) {
+                mCallback = callback;
+            }
+        }
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/UrlSchemeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/UrlSchemeTest.java
index e7b57bc..2eddc55 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/UrlSchemeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/UrlSchemeTest.java
@@ -10,6 +10,7 @@
 import android.test.suitebuilder.annotation.MediumTest;
 
 import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.TestFileUtil;
 import org.chromium.base.test.util.UrlUtils;
@@ -94,6 +95,7 @@
      */
     @MediumTest
     @Feature({"Navigation"})
+    @DisableIf.Build(sdk_is_greater_than = 22, message = "crbug.com/592642")
     public void testContentUrlFromFile() throws InterruptedException, IOException {
         final String target = "content_from_file";
         final File file = new File(Environment.getExternalStorageDirectory(), target + ".html");
@@ -113,6 +115,7 @@
      */
     @MediumTest
     @Feature({"Navigation"})
+    @DisableIf.Build(sdk_is_greater_than = 22, message = "crbug.com/592642")
     public void testFileUrlNavigation() throws InterruptedException, IOException {
         final File file = new File(Environment.getExternalStorageDirectory(),
                 "url_navigation_test.html");
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 8b3c691..5307661 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -998,6 +998,9 @@
   <message name="IDS_FILE_BROWSER_SORT_BUTTON_TOOLTIP" desc="Tooltip for the button which provides sort options in Files.app.">
     Sort options
   </message>
+  <message name="IDS_FILE_BROWSER_DETAIL_BUTTON_TOOLTIP" desc="Tooltip for the detals button to show the details panel which provides information of selected files in Files.app.">
+    View details
+  </message>
   <message name="IDS_FILE_BROWSER_GEAR_BUTTON_TOOLTIP" desc="Tooltip for the gear button in Files.app.">
     Settings
   </message>
@@ -6439,5 +6442,17 @@
   <message name="IDS_OPTIONS_ARC_ENABLE" desc="Label for the checkbox that enables Android apps.">
     Enable Android Apps to run on your Chromebook.
   </message>
+  <message name="IDS_ARC_NOTIFICATION_TITLE" desc="Title of the first-run notification that enables Android apps.">
+    Google Play Store
+  </message>
+  <message name="IDS_ARC_NOTIFICATION_MESSAGE" desc="Description message of the first-run notification that enables Android apps.">
+    Over a million apps and games now avaialble on your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>.
+  </message>
+  <message name="IDS_ARC_OPEN_PLAY_STORE_NOTIFICATION_BUTTON" desc="Label for the button in the first-run notification that enables Android apps.">
+    Open Play Store
+  </message>
+  <message name="IDS_ARC_CANCEL_NOTIFICATION_BUTTON" desc="Label for the button in the first-run notification that cancel running Android apps.">
+    Cancel
+  </message>
 
 </grit-part>
diff --git a/chrome/app/mash/mash_runner.cc b/chrome/app/mash/mash_runner.cc
index 11df4c05..2cde543 100644
--- a/chrome/app/mash/mash_runner.cc
+++ b/chrome/app/mash/mash_runner.cc
@@ -21,9 +21,9 @@
 #include "mash/wm/window_manager_application.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "mojo/shell/background/background_shell.h"
-#include "mojo/shell/identity.h"
 #include "mojo/shell/native_runner_delegate.h"
 #include "mojo/shell/public/cpp/connector.h"
+#include "mojo/shell/public/cpp/identity.h"
 #include "mojo/shell/public/cpp/shell_client.h"
 #include "mojo/shell/public/cpp/shell_connection.h"
 #include "mojo/shell/public/interfaces/shell_client_factory.mojom.h"
@@ -136,7 +136,7 @@
  private:
   // mojo::shell::NativeRunnerDelegate:
   void AdjustCommandLineArgumentsForTarget(
-      const mojo::shell::Identity& target,
+      const mojo::Identity& target,
       base::CommandLine* command_line) override {
     if (target.name() != "exe:chrome") {
       if (target.name() == "exe:chrome_mash")
diff --git a/chrome/app/theme/default_100_percent/cros/notification_play_store.png b/chrome/app/theme/default_100_percent/cros/notification_play_store.png
new file mode 100644
index 0000000..6c7b7f7c
--- /dev/null
+++ b/chrome/app/theme/default_100_percent/cros/notification_play_store.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/cros/notification_play_store.png b/chrome/app/theme/default_200_percent/cros/notification_play_store.png
new file mode 100644
index 0000000..03b4891
--- /dev/null
+++ b/chrome/app/theme/default_200_percent/cros/notification_play_store.png
Binary files differ
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd
index 22ca374..86d7131 100644
--- a/chrome/app/theme/theme_resources.grd
+++ b/chrome/app/theme/theme_resources.grd
@@ -450,6 +450,7 @@
         <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_DRIVE" file="cros/notification_drive.png" />
         <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_PERIPHERAL_BATTERY_LOW" file="cros/notification_peripheral_battery_low.png" />
         <structure type="chrome_scaled_image" name="IDR_PORTAL_DETECTION_ALERT" file="cros/captive_portal_icon.png" />
+        <structure type="chrome_scaled_image" name="IDR_ARC_PLAY_STORE_NOTIFICATION" file="cros/notification_play_store.png" />
       </if>
       <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_WELCOME_ICON" file="common/notification_welcome_icon.png" />
       <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_WELCOME_LEARN_MORE" file="common/notification_welcome_learn_more.png" />
diff --git a/chrome/browser/android/offline_pages/offline_page_tab_helper.cc b/chrome/browser/android/offline_pages/offline_page_tab_helper.cc
index c0e6e3b..713d241 100644
--- a/chrome/browser/android/offline_pages/offline_page_tab_helper.cc
+++ b/chrome/browser/android/offline_pages/offline_page_tab_helper.cc
@@ -61,18 +61,14 @@
                  online_url));
 }
 
-void OfflinePageTabHelper::DidFailProvisionalLoad(
-    content::RenderFrameHost* render_frame_host,
-    const GURL& validated_url,
-    int error_code,
-    const base::string16& error_description,
-    bool was_ignored_by_handler) {
+void OfflinePageTabHelper::DidFinishNavigation(
+    content::NavigationHandle* navigation_handle) {
   GURL last_redirect_from_url_copy = last_redirect_from_url_;
   last_redirect_from_url_ = GURL();
 
   // Skips non-main frame or load failure other than no network.
-  if (error_code != net::ERR_INTERNET_DISCONNECTED ||
-      render_frame_host->GetParent() != nullptr) {
+  if (navigation_handle->GetNetErrorCode() != net::ERR_INTERNET_DISCONNECTED ||
+      !navigation_handle->IsInMainFrame()) {
     return;
   }
 
@@ -83,14 +79,14 @@
 
   // Skips if not loading an online version of saved page.
   GURL offline_url = offline_pages::OfflinePageUtils::GetOfflineURLForOnlineURL(
-      web_contents()->GetBrowserContext(), validated_url);
+      web_contents()->GetBrowserContext(), navigation_handle->GetURL());
   if (!offline_url.is_valid())
     return;
 
   // Avoids looping between online and offline redirections.
   if (last_redirect_from_url_copy == offline_url)
     return;
-  last_redirect_from_url_ = validated_url;
+  last_redirect_from_url_ = navigation_handle->GetURL();
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
diff --git a/chrome/browser/android/offline_pages/offline_page_tab_helper.h b/chrome/browser/android/offline_pages/offline_page_tab_helper.h
index 2339197..041e510 100644
--- a/chrome/browser/android/offline_pages/offline_page_tab_helper.h
+++ b/chrome/browser/android/offline_pages/offline_page_tab_helper.h
@@ -33,12 +33,8 @@
   // Overridden from content::WebContentsObserver:
   void DidStartNavigation(
       content::NavigationHandle* navigation_handle) override;
-  void DidFailProvisionalLoad(
-      content::RenderFrameHost* render_frame_host,
-      const GURL& validated_url,
-      int error_code,
-      const base::string16& error_description,
-      bool was_ignored_by_handler) override;
+  void DidFinishNavigation(
+      content::NavigationHandle* navigation_handle) override;
 
   void RedirectFromOfflineToOnline(const GURL& online_url);
   void RedirectFromOnlineToOffline(const GURL& offline_url);
diff --git a/chrome/browser/android/offline_pages/offline_page_tab_helper_unittest.cc b/chrome/browser/android/offline_pages/offline_page_tab_helper_unittest.cc
index ec0a852..796b062 100644
--- a/chrome/browser/android/offline_pages/offline_page_tab_helper_unittest.cc
+++ b/chrome/browser/android/offline_pages/offline_page_tab_helper_unittest.cc
@@ -139,13 +139,17 @@
 
 void OfflinePageTabHelperTest::CommitLoad(const GURL& url) {
   int entry_id = controller().GetPendingEntry()->GetUniqueID();
-  content::RenderFrameHostTester::For(main_rfh())->SendNavigate(
-      0, entry_id, true, url);
+  content::RenderFrameHostTester::For(main_rfh())
+      ->SendNavigate(0, entry_id, true, url);
 }
 
 void OfflinePageTabHelperTest::FailLoad(const GURL& url) {
-  content::RenderFrameHostTester::For(main_rfh())->SimulateNavigationError(
-      url, net::ERR_INTERNET_DISCONNECTED);
+  content::RenderFrameHostTester::For(main_rfh())->SimulateNavigationStart(url);
+  // Set up the error code for the failed navigation.
+  content::RenderFrameHostTester::For(main_rfh())->
+      SimulateNavigationError(url, net::ERR_INTERNET_DISCONNECTED);
+  content::RenderFrameHostTester::For(main_rfh())->
+      SimulateNavigationErrorPageCommit();
   // Gives a chance to run delayed task to do redirection.
   RunUntilIdle();
 }
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index de94df9..9e57c22 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -195,6 +195,8 @@
 
       <if expr="not is_android and not is_ios">
         <include name="IDR_MD_HISTORY_HISTORY_HTML" file="resources\md_history\history.html" type="BINDATA" />
+        <include name="IDR_MD_HISTORY_CONSTANTS_HTML" file="resources\md_history\constants.html" type="BINDATA" />
+        <include name="IDR_MD_HISTORY_CONSTANTS_JS" file="resources\md_history\constants.js" type="BINDATA" />
         <include name="IDR_MD_HISTORY_HISTORY_ITEM_HTML" file="resources\md_history\history_item.html" type="BINDATA" />
         <include name="IDR_MD_HISTORY_HISTORY_ITEM_JS" file="resources\md_history\history_item.js" type="BINDATA" />
         <include name="IDR_MD_HISTORY_HISTORY_JS" file="resources\md_history\history.js" type="BINDATA" />
diff --git a/chrome/browser/chromeos/arc/arc_auth_notification.cc b/chrome/browser/chromeos/arc/arc_auth_notification.cc
new file mode 100644
index 0000000..366fdd76
--- /dev/null
+++ b/chrome/browser/chromeos/arc/arc_auth_notification.cc
@@ -0,0 +1,80 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/arc/arc_auth_notification.h"
+
+#include "ash/system/chromeos/devicetype_utils.h"
+#include "base/macros.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/chromeos/arc/arc_auth_service.h"
+#include "chrome/grit/generated_resources.h"
+#include "chrome/grit/theme_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/message_center/message_center.h"
+#include "ui/message_center/notification.h"
+#include "ui/message_center/notification_delegate.h"
+#include "url/gurl.h"
+
+namespace {
+
+// Ids of the notification shown on first run.
+const char kNotifierId[] = "arc_auth";
+const char kDisplaySoruce[] = "arc_auth_source";
+const char kFirstRunNotificationId[] = "arc_auth/first_run";
+
+class ArcAuthNotificationDelegate
+    : public message_center::NotificationDelegate {
+ public:
+  ArcAuthNotificationDelegate() {}
+
+  // message_center::NotificationDelegate
+  void ButtonClick(int button_index) override {
+    if (button_index == 0)
+      arc::ArcAuthService::Get()->EnableArc();
+    else
+      arc::ArcAuthService::Get()->DisableArc();
+  }
+
+ private:
+  ~ArcAuthNotificationDelegate() override {}
+
+  DISALLOW_COPY_AND_ASSIGN(ArcAuthNotificationDelegate);
+};
+
+}  // namespace
+
+namespace arc {
+
+// static
+void ArcAuthNotification::Show() {
+  message_center::NotifierId notifier_id(
+      message_center::NotifierId::SYSTEM_COMPONENT, kNotifierId);
+
+  message_center::RichNotificationData data;
+  data.buttons.push_back(message_center::ButtonInfo(
+      l10n_util::GetStringUTF16(IDS_ARC_OPEN_PLAY_STORE_NOTIFICATION_BUTTON)));
+  data.buttons.push_back(message_center::ButtonInfo(
+      l10n_util::GetStringUTF16(IDS_ARC_CANCEL_NOTIFICATION_BUTTON)));
+  ui::ResourceBundle& resource_bundle = ui::ResourceBundle::GetSharedInstance();
+  scoped_ptr<message_center::Notification> notification(
+      new message_center::Notification(
+          message_center::NOTIFICATION_TYPE_SIMPLE, kFirstRunNotificationId,
+          l10n_util::GetStringUTF16(IDS_ARC_NOTIFICATION_TITLE),
+          l10n_util::GetStringFUTF16(IDS_ARC_NOTIFICATION_MESSAGE,
+                                     ash::GetChromeOSDeviceName()),
+          resource_bundle.GetImageNamed(IDR_ARC_PLAY_STORE_NOTIFICATION),
+          base::UTF8ToUTF16(kDisplaySoruce), GURL(), notifier_id, data,
+          new ArcAuthNotificationDelegate()));
+  message_center::MessageCenter::Get()->AddNotification(
+      std::move(notification));
+}
+
+// static
+void ArcAuthNotification::Hide() {
+  message_center::MessageCenter::Get()->RemoveNotification(
+      kFirstRunNotificationId, false);
+}
+
+}  // namespace arc
diff --git a/chrome/browser/chromeos/arc/arc_auth_notification.h b/chrome/browser/chromeos/arc/arc_auth_notification.h
new file mode 100644
index 0000000..8128c5c
--- /dev/null
+++ b/chrome/browser/chromeos/arc/arc_auth_notification.h
@@ -0,0 +1,19 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_ARC_ARC_AUTH_NOTIFICATION_H_
+#define CHROME_BROWSER_CHROMEOS_ARC_ARC_AUTH_NOTIFICATION_H_
+
+namespace arc {
+
+// First run notification that can enable Arc.
+class ArcAuthNotification {
+ public:
+  static void Show();
+  static void Hide();
+};
+
+}  // namespace arc
+
+#endif  // CHROME_BROWSER_CHROMEOS_ARC_ARC_AUTH_NOTIFICATION_H_
diff --git a/chrome/browser/chromeos/arc/arc_auth_service.cc b/chrome/browser/chromeos/arc/arc_auth_service.cc
index 5085333a..ddb6e73 100644
--- a/chrome/browser/chromeos/arc/arc_auth_service.cc
+++ b/chrome/browser/chromeos/arc/arc_auth_service.cc
@@ -8,7 +8,9 @@
 
 #include "base/command_line.h"
 #include "base/strings/stringprintf.h"
+#include "chrome/browser/chromeos/arc/arc_auth_notification.h"
 #include "chrome/browser/extensions/extension_util.h"
+#include "chrome/browser/prefs/pref_service_syncable_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
@@ -21,6 +23,7 @@
 #include "components/prefs/pref_service.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
 #include "components/signin/core/browser/signin_manager_base.h"
+#include "components/syncable_prefs/pref_service_syncable.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/common/url_constants.h"
 #include "extensions/browser/extension_registry.h"
@@ -141,7 +144,14 @@
         prefs::kArcEnabled,
         base::Bind(&ArcAuthService::OnOptInPreferenceChanged,
                    base::Unretained(this)));
-    OnOptInPreferenceChanged();
+    if (profile_->GetPrefs()->GetBoolean(prefs::kArcEnabled)) {
+      OnOptInPreferenceChanged();
+    } else {
+      if (!disable_ui_for_testing && profile_->IsNewProfile()) {
+        PrefServiceSyncableFromProfile(profile_)->AddObserver(this);
+        OnIsSyncingChanged();
+      }
+    }
   } else {
     auth_code_.clear();
     ArcBridgeService::Get()->HandleStartup();
@@ -149,8 +159,21 @@
   }
 }
 
+void ArcAuthService::OnIsSyncingChanged() {
+  syncable_prefs::PrefServiceSyncable* const pref_service_syncable =
+      PrefServiceSyncableFromProfile(profile_);
+  if (!pref_service_syncable->IsSyncing())
+    return;
+
+  pref_service_syncable->RemoveObserver(this);
+  if (!profile_->GetPrefs()->HasPrefPath(prefs::kArcEnabled))
+    arc::ArcAuthNotification::Show();
+}
+
 void ArcAuthService::Shutdown() {
   ShutdownBridgeAndCloseUI();
+  if (profile_)
+    PrefServiceSyncableFromProfile(profile_)->RemoveObserver(this);
   profile_ = nullptr;
   pref_change_registrar_.RemoveAll();
 }
@@ -261,8 +284,16 @@
   if (state_ != State::FETCHING_CODE)
     return;
 
-  ShutdownBridgeAndCloseUI();
+  DisableArc();
+}
 
+void ArcAuthService::EnableArc() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  profile_->GetPrefs()->SetBoolean(prefs::kArcEnabled, true);
+}
+
+void ArcAuthService::DisableArc() {
+  DCHECK(thread_checker_.CalledOnValidThread());
   profile_->GetPrefs()->SetBoolean(prefs::kArcEnabled, false);
 }
 
diff --git a/chrome/browser/chromeos/arc/arc_auth_service.h b/chrome/browser/chromeos/arc/arc_auth_service.h
index 15d83b5..74d03b83 100644
--- a/chrome/browser/chromeos/arc/arc_auth_service.h
+++ b/chrome/browser/chromeos/arc/arc_auth_service.h
@@ -15,6 +15,7 @@
 #include "components/arc/auth/arc_auth_fetcher.h"
 #include "components/arc/common/auth.mojom.h"
 #include "components/prefs/pref_change_registrar.h"
+#include "components/syncable_prefs/pref_service_syncable_observer.h"
 #include "google_apis/gaia/gaia_auth_consumer.h"
 #include "google_apis/gaia/ubertoken_fetcher.h"
 #include "mojo/public/cpp/bindings/binding.h"
@@ -43,7 +44,8 @@
                        public ArcBridgeService::Observer,
                        public ArcAuthFetcher::Delegate,
                        public UbertokenConsumer,
-                       public GaiaAuthConsumer {
+                       public GaiaAuthConsumer,
+                       public syncable_prefs::PrefServiceSyncableObserver {
  public:
   enum class State {
     DISABLE,        // ARC is not allowed to run (default).
@@ -103,6 +105,9 @@
   // Called from Arc support platform app when user cancels signing.
   void CancelAuthCode();
 
+  void EnableArc();
+  void DisableArc();
+
   // ArcAuthFetcher::Delegate:
   void OnAuthCodeFetched(const std::string& auth_code) override;
   void OnAuthCodeNeedUI() override;
@@ -116,6 +121,9 @@
   void OnMergeSessionSuccess(const std::string& data) override;
   void OnMergeSessionFailure(const GoogleServiceAuthError& error) override;
 
+  // syncable_prefs::PrefServiceSyncableObserver
+  void OnIsSyncingChanged() override;
+
  private:
   void SetAuthCodeAndStartArc(const std::string& auth_code);
   void ShowUI();
diff --git a/chrome/browser/chromeos/arc/arc_auth_service_unittest.cc b/chrome/browser/chromeos/arc/arc_auth_service_unittest.cc
index b251001..42d8ee1 100644
--- a/chrome/browser/chromeos/arc/arc_auth_service_unittest.cc
+++ b/chrome/browser/chromeos/arc/arc_auth_service_unittest.cc
@@ -228,4 +228,19 @@
   auth_service()->Shutdown();
 }
 
+TEST_F(ArcAuthServiceTest, EnableDisablesArc) {
+  PrepareURLResponse(net::HTTP_OK, false);
+  PrefService* pref = profile()->GetPrefs();
+  auth_service()->OnPrimaryUserProfilePrepared(profile());
+
+  EXPECT_FALSE(pref->GetBoolean(prefs::kArcEnabled));
+  auth_service()->EnableArc();
+  EXPECT_TRUE(pref->GetBoolean(prefs::kArcEnabled));
+  auth_service()->DisableArc();
+  EXPECT_FALSE(pref->GetBoolean(prefs::kArcEnabled));
+
+  // Correctly stop service.
+  auth_service()->Shutdown();
+}
+
 }  // namespace arc
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
index 0dbfa19d2..4c7f171d 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
@@ -456,6 +456,7 @@
   SET_STRING("FORMAT_DEVICE_BUTTON_LABEL",
              IDS_FILE_BROWSER_FORMAT_DEVICE_BUTTON_LABEL);
   SET_STRING("SORT_BUTTON_TOOLTIP", IDS_FILE_BROWSER_SORT_BUTTON_TOOLTIP);
+  SET_STRING("DETAIL_BUTTON_TOOLTIP", IDS_FILE_BROWSER_DETAIL_BUTTON_TOOLTIP);
   SET_STRING("GEAR_BUTTON_TOOLTIP", IDS_FILE_BROWSER_GEAR_BUTTON_TOOLTIP);
   SET_STRING("HOSTED_OFFLINE_MESSAGE", IDS_FILE_BROWSER_HOSTED_OFFLINE_MESSAGE);
   SET_STRING("HOSTED_OFFLINE_MESSAGE_PLURAL",
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc
index decf10d..ae0c2e0 100644
--- a/chrome/browser/chromeos/login/chrome_restart_request.cc
+++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -106,7 +106,7 @@
     ::switches::kEnableImageColorProfiles,
     ::switches::kEnableLogging,
     ::switches::kEnableLowResTiling,
-    ::switches::kEnablePartialRaster,
+    ::switches::kDisablePartialRaster,
     ::switches::kEnablePinch,
     ::switches::kEnablePreferCompositingToLCDText,
     ::switches::kEnableRGBA4444Textures,
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc
index 6903f74..2173069 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -13,7 +13,7 @@
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
@@ -86,6 +86,19 @@
 
 namespace {
 
+// Enum types for Login.PasswordChangeFlow.
+// Don't change the existing values and update LoginPasswordChangeFlow in
+// histogram.xml when making changes here.
+enum LoginPasswordChangeFlow {
+  // User is sent to the password changed flow. This is the normal case.
+  LOGIN_PASSWORD_CHANGE_FLOW_PASSWORD_CHANGED = 0,
+  // User is sent to the unrecoverable cryptohome failure flow. This is the
+  // case when http://crbug.com/547857 happens.
+  LOGIN_PASSWORD_CHANGE_FLOW_CRYPTOHOME_FAILURE = 1,
+
+  LOGIN_PASSWORD_CHANGE_FLOW_COUNT,  // Must be the last entry.
+};
+
 // Delay for transferring the auth cache to the system profile.
 const long int kAuthCacheTransferDelayMs = 2000;
 
@@ -139,6 +152,11 @@
          !user_manager::UserManager::Get()->IsSessionStarted();
 }
 
+void RecordPasswordChangeFlow(LoginPasswordChangeFlow flow) {
+  UMA_HISTOGRAM_ENUMERATION("Login.PasswordChangeFlow", flow,
+                            LOGIN_PASSWORD_CHANGE_FLOW_COUNT);
+}
+
 }  // namespace
 
 // static
@@ -498,6 +516,8 @@
 }
 
 void ExistingUserController::ShowPasswordChangedDialog() {
+  RecordPasswordChangeFlow(LOGIN_PASSWORD_CHANGE_FLOW_PASSWORD_CHANGED);
+
   VLOG(1) << "Show password changed dialog"
           << ", count=" << login_performer_->password_changed_callback_count();
 
@@ -1244,6 +1264,7 @@
 
   // Otherwise, show the unrecoverable cryptohome error UI and ask user's
   // permission to collect a feedback.
+  RecordPasswordChangeFlow(LOGIN_PASSWORD_CHANGE_FLOW_CRYPTOHOME_FAILURE);
   VLOG(1) << "Show unrecoverable cryptohome error dialog.";
   login_display_->ShowUnrecoverableCrypthomeErrorDialog();
 }
diff --git a/chrome/browser/extensions/api/braille_display_private/braille_display_private_apitest.cc b/chrome/browser/extensions/api/braille_display_private/braille_display_private_apitest.cc
index f5f6b594..9aad594c 100644
--- a/chrome/browser/extensions/api/braille_display_private/braille_display_private_apitest.cc
+++ b/chrome/browser/extensions/api/braille_display_private/braille_display_private_apitest.cc
@@ -318,8 +318,14 @@
   }
 };
 
+// Flakily times out on ChromeOS MSAN bots. See https://crbug.com/592893.
+#if defined(MEMORY_SANITIZER)
+#define MAYBE_KeyEventOnLockScreen DISABLED_KeyEventOnLockScreen
+#else
+#define MAYBE_KeyEventOnLockScreen KeyEventOnLockScreen
+#endif
 IN_PROC_BROWSER_TEST_F(BrailleDisplayPrivateAPIUserTest,
-                       KeyEventOnLockScreen) {
+                       MAYBE_KeyEventOnLockScreen) {
   scoped_ptr<ScreenLockerTester> tester(ScreenLocker::GetTester());
   // Log in.
   user_manager::UserManager::Get()->UserLoggedIn(
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api_nonchromeos.cc b/chrome/browser/extensions/api/input_ime/input_ime_api_nonchromeos.cc
index 7390dd9..ce3ed72 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api_nonchromeos.cc
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api_nonchromeos.cc
@@ -239,4 +239,36 @@
   return RespondNow(OneArgument(std::move(result)));
 }
 
+ExtensionFunction::ResponseAction InputImeShowWindowFunction::Run() {
+  if (!IsInputImeEnabled())
+    return RespondNow(Error(kErrorAPIDisabled));
+
+  InputMethodEngine* engine =
+      GetActiveEngine(browser_context(), extension_id());
+  if (!engine)
+    return RespondNow(Error(kErrorNoActiveEngine));
+
+  scoped_ptr<api::input_ime::ShowWindow::Params> params(
+      api::input_ime::ShowWindow::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params.get());
+  engine->ShowImeWindow(params->window_id);
+  return RespondNow(NoArguments());
+}
+
+ExtensionFunction::ResponseAction InputImeHideWindowFunction::Run() {
+  if (!IsInputImeEnabled())
+    return RespondNow(Error(kErrorAPIDisabled));
+
+  InputMethodEngine* engine =
+      GetActiveEngine(browser_context(), extension_id());
+  if (!engine)
+    return RespondNow(Error(kErrorNoActiveEngine));
+
+  scoped_ptr<api::input_ime::HideWindow::Params> params(
+      api::input_ime::HideWindow::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params.get());
+  engine->HideImeWindow(params->window_id);
+  return RespondNow(NoArguments());
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api_nonchromeos.h b/chrome/browser/extensions/api/input_ime/input_ime_api_nonchromeos.h
index 7a1eac0..d575cff 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api_nonchromeos.h
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api_nonchromeos.h
@@ -53,6 +53,28 @@
   ExtensionFunction::ResponseAction Run() override;
 };
 
+class InputImeShowWindowFunction : public UIThreadExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("input.ime.showWindow", INPUT_IME_SHOWWINDOW)
+
+ protected:
+  ~InputImeShowWindowFunction() override {}
+
+  // ExtensionFunction:
+  ExtensionFunction::ResponseAction Run() override;
+};
+
+class InputImeHideWindowFunction : public UIThreadExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("input.ime.hideWindow", INPUT_IME_HIDEWINDOW)
+
+ protected:
+  ~InputImeHideWindowFunction() override {}
+
+  // ExtensionFunction:
+  ExtensionFunction::ResponseAction Run() override;
+};
+
 class InputImeActivateFunction : public UIThreadExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("input.ime.activate", INPUT_IME_ACTIVATE)
diff --git a/chrome/browser/push_messaging/push_messaging_browsertest.cc b/chrome/browser/push_messaging/push_messaging_browsertest.cc
index bcad2bc..03fb9294 100644
--- a/chrome/browser/push_messaging/push_messaging_browsertest.cc
+++ b/chrome/browser/push_messaging/push_messaging_browsertest.cc
@@ -44,7 +44,6 @@
 #include "components/gcm_driver/common/gcm_messages.h"
 #include "components/gcm_driver/gcm_client.h"
 #include "content/public/browser/web_contents.h"
-#include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
@@ -100,13 +99,6 @@
     InProcessBrowserTest::SetUp();
   }
 
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    // Enable experiemntal features for subscription restrictions.
-    command_line->AppendSwitch(
-        switches::kEnableExperimentalWebPlatformFeatures);
-    InProcessBrowserTest::SetUpCommandLine(command_line);
-  }
-
   // InProcessBrowserTest:
   void SetUpOnMainThread() override {
     gcm_service_ = static_cast<gcm::FakeGCMProfileService*>(
@@ -172,8 +164,7 @@
   void RequestAndDenyPermission();
 
   void TryToSubscribeSuccessfully(
-      const std::string& expected_push_subscription_info,
-      bool use_key = true);
+      const std::string& expected_push_subscription_id);
 
   std::string GetEndpointForSubscriptionId(const std::string& subscription_id) {
     return std::string(kPushMessagingEndpoint) + "/" + subscription_id;
@@ -255,8 +246,7 @@
 }
 
 void PushMessagingBrowserTest::TryToSubscribeSuccessfully(
-    const std::string& expected_push_subscription_info,
-    bool use_key) {
+    const std::string& expected_push_subscription_id) {
   std::string script_result;
 
   EXPECT_TRUE(RunScript("registerServiceWorker()", &script_result));
@@ -264,14 +254,8 @@
 
   RequestAndAcceptPermission();
 
-  if (use_key) {
-    EXPECT_TRUE(RunScript("subscribePush()", &script_result));
-  } else {
-    // Test backwards compatibility with old ID based subscriptions.
-    EXPECT_TRUE(RunScript("subscribePushWithoutKey()", &script_result));
-  }
-
-  EXPECT_EQ(GetEndpointForSubscriptionId(expected_push_subscription_info),
+  EXPECT_TRUE(RunScript("subscribePush()", &script_result));
+  EXPECT_EQ(GetEndpointForSubscriptionId(expected_push_subscription_id),
             script_result);
 }
 
@@ -296,16 +280,6 @@
 }
 
 IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
-                       SubscribeWithoutKeySuccessNotificationsGranted) {
-  TryToSubscribeSuccessfully("1-0" /* expected_push_subscription_id */, false);
-
-  PushMessagingAppIdentifier app_identifier =
-      GetAppIdentifierForServiceWorkerRegistration(0LL);
-  EXPECT_EQ(app_identifier.app_id(), gcm_service()->last_registered_app_id());
-  EXPECT_EQ("1234567890", gcm_service()->last_registered_sender_ids()[0]);
-}
-
-IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
                        SubscribeSuccessNotificationsGranted) {
   TryToSubscribeSuccessfully("1-0" /* expected_push_subscription_id */);
 
@@ -333,21 +307,6 @@
   EXPECT_EQ("1234567890", gcm_service()->last_registered_sender_ids()[0]);
 }
 
-IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, SubscribeFailureBadKey) {
-  std::string script_result;
-
-  ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result));
-  ASSERT_EQ("ok - service worker registered", script_result);
-
-  RequestAndAcceptPermission();
-
-  ASSERT_TRUE(RunScript("subscribePushBadKey()", &script_result));
-  EXPECT_EQ(
-      "InvalidAccessError - Failed to execute 'subscribe' on 'PushManager': "
-      "The provided applicationServerKey is not valid.",
-      script_result);
-}
-
 IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
                        SubscribeFailureNotificationsBlocked) {
   std::string script_result;
diff --git a/chrome/browser/push_messaging/push_messaging_service_impl.cc b/chrome/browser/push_messaging/push_messaging_service_impl.cc
index 48959071..b5f409e 100644
--- a/chrome/browser/push_messaging/push_messaging_service_impl.cc
+++ b/chrome/browser/push_messaging/push_messaging_service_impl.cc
@@ -44,7 +44,6 @@
 #include "content/public/common/child_process_host.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/push_messaging_status.h"
-#include "content/public/common/push_subscription_options.h"
 #include "ui/base/l10n/l10n_util.h"
 
 #if BUILDFLAG(ENABLE_BACKGROUND)
@@ -345,9 +344,10 @@
 void PushMessagingServiceImpl::SubscribeFromDocument(
     const GURL& requesting_origin,
     int64_t service_worker_registration_id,
+    const std::string& sender_id,
     int renderer_id,
     int render_frame_id,
-    const content::PushSubscriptionOptions& options,
+    bool user_visible,
     const content::PushMessagingService::RegisterCallback& callback) {
   PushMessagingAppIdentifier app_identifier =
       PushMessagingAppIdentifier::Generate(requesting_origin,
@@ -367,7 +367,7 @@
   if (!web_contents)
     return;
 
-  if (!options.user_visible_only) {
+  if (!user_visible) {
     web_contents->GetMainFrame()->AddMessageToConsole(
         content::CONSOLE_MESSAGE_LEVEL_ERROR, kSilentPushUnsupportedMessage);
 
@@ -381,14 +381,15 @@
       content::PermissionType::PUSH_MESSAGING, web_contents->GetMainFrame(),
       requesting_origin,
       base::Bind(&PushMessagingServiceImpl::DidRequestPermission,
-                 weak_factory_.GetWeakPtr(), app_identifier, options,
+                 weak_factory_.GetWeakPtr(), app_identifier, sender_id,
                  callback));
 }
 
 void PushMessagingServiceImpl::SubscribeFromWorker(
     const GURL& requesting_origin,
     int64_t service_worker_registration_id,
-    const content::PushSubscriptionOptions& options,
+    const std::string& sender_id,
+    bool user_visible,
     const content::PushMessagingService::RegisterCallback& register_callback) {
   PushMessagingAppIdentifier app_identifier =
       PushMessagingAppIdentifier::Generate(requesting_origin,
@@ -403,7 +404,7 @@
 
   blink::WebPushPermissionStatus permission_status =
       PushMessagingServiceImpl::GetPermissionStatus(requesting_origin,
-                                                    options.user_visible_only);
+                                                    user_visible);
 
   if (permission_status != blink::WebPushPermissionStatusGranted) {
     SubscribeEndWithError(register_callback,
@@ -412,7 +413,7 @@
   }
 
   IncreasePushSubscriptionCount(1, true /* is_pending */);
-  std::vector<std::string> sender_ids(1, options.sender_info);
+  std::vector<std::string> sender_ids(1, sender_id);
   GetGCMDriver()->Register(app_identifier.app_id(), sender_ids,
                            base::Bind(&PushMessagingServiceImpl::DidSubscribe,
                                       weak_factory_.GetWeakPtr(),
@@ -515,7 +516,7 @@
 
 void PushMessagingServiceImpl::DidRequestPermission(
     const PushMessagingAppIdentifier& app_identifier,
-    const content::PushSubscriptionOptions& options,
+    const std::string& sender_id,
     const content::PushMessagingService::RegisterCallback& register_callback,
     content::PermissionStatus permission_status) {
   if (permission_status != content::PermissionStatus::GRANTED) {
@@ -525,7 +526,7 @@
   }
 
   IncreasePushSubscriptionCount(1, true /* is_pending */);
-  std::vector<std::string> sender_ids(1, options.sender_info);
+  std::vector<std::string> sender_ids(1, sender_id);
   GetGCMDriver()->Register(app_identifier.app_id(), sender_ids,
                            base::Bind(&PushMessagingServiceImpl::DidSubscribe,
                                       weak_factory_.GetWeakPtr(),
diff --git a/chrome/browser/push_messaging/push_messaging_service_impl.h b/chrome/browser/push_messaging/push_messaging_service_impl.h
index a0b145a..3b95d2d5 100644
--- a/chrome/browser/push_messaging/push_messaging_service_impl.h
+++ b/chrome/browser/push_messaging/push_messaging_service_impl.h
@@ -35,7 +35,6 @@
 class Profile;
 class PushMessagingAppIdentifier;
 class PushMessagingServiceObserver;
-struct PushSubscriptionOptions;
 
 namespace gcm {
 class GCMDriver;
@@ -75,14 +74,16 @@
   void SubscribeFromDocument(
       const GURL& requesting_origin,
       int64_t service_worker_registration_id,
+      const std::string& sender_id,
       int renderer_id,
       int render_frame_id,
-      const content::PushSubscriptionOptions& options,
+      bool user_visible,
       const content::PushMessagingService::RegisterCallback& callback) override;
   void SubscribeFromWorker(
       const GURL& requesting_origin,
       int64_t service_worker_registration_id,
-      const content::PushSubscriptionOptions& options,
+      const std::string& sender_id,
+      bool user_visible,
       const content::PushMessagingService::RegisterCallback& callback) override;
   void GetEncryptionInfo(
       const GURL& origin,
@@ -164,7 +165,7 @@
 
   void DidRequestPermission(
       const PushMessagingAppIdentifier& app_identifier,
-      const content::PushSubscriptionOptions& options,
+      const std::string& sender_id,
       const content::PushMessagingService::RegisterCallback& callback,
       content::PermissionStatus permission_status);
 
diff --git a/chrome/browser/push_messaging/push_messaging_service_unittest.cc b/chrome/browser/push_messaging/push_messaging_service_unittest.cc
index 19167e4..a68e0d1 100644
--- a/chrome/browser/push_messaging/push_messaging_service_unittest.cc
+++ b/chrome/browser/push_messaging/push_messaging_service_unittest.cc
@@ -27,7 +27,6 @@
 #include "components/gcm_driver/fake_gcm_client_factory.h"
 #include "components/gcm_driver/gcm_profile_service.h"
 #include "content/public/common/push_event_payload.h"
-#include "content/public/common/push_subscription_options.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -154,11 +153,8 @@
 
   // (2) Subscribe for Push Messaging, and verify that we've got the required
   // information in order to be able to create encrypted messages.
-  content::PushSubscriptionOptions options;
-  options.user_visible_only = true;
-  options.sender_info = kTestSenderId;
   push_service->SubscribeFromWorker(
-      origin, kTestServiceWorkerId, options,
+      origin, kTestServiceWorkerId, kTestSenderId, true /* user_visible */,
       base::Bind(&PushMessagingServiceTest::DidRegister, base::Unretained(this),
                  &subscription_id, &p256dh, &auth));
 
diff --git a/chrome/browser/resources/md_history/compiled_resources2.gyp b/chrome/browser/resources/md_history/compiled_resources2.gyp
new file mode 100644
index 0000000..c8fc26b8
--- /dev/null
+++ b/chrome/browser/resources/md_history/compiled_resources2.gyp
@@ -0,0 +1,52 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'constants',
+      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+    {
+      'target_name': 'history_item',
+      'dependencies': [
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
+      ],
+      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+    {
+      'target_name': 'history_list',
+      'dependencies': [
+        '<(DEPTH)/ui/webui/resources/cr_elements/cr_shared_menu/compiled_resources2.gyp:cr_shared_menu',
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
+        'constants',
+        'history_item',
+        '../history/compiled_resources2.gyp:externs',
+      ],
+      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+    {
+      'target_name': 'history_toolbar',
+      'dependencies': [
+        '<(DEPTH)/ui/webui/resources/cr_elements/cr_search_field/compiled_resources2.gyp:cr_search_field',
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+      ],
+      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+    {
+      'target_name': 'history',
+      'dependencies': [
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
+        'constants',
+        'history_list',
+        'history_toolbar',
+        '<(EXTERNS_GYP):chrome_send',
+        '../history/compiled_resources2.gyp:externs',
+      ],
+      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+  ],
+}
diff --git a/chrome/browser/resources/md_history/constants.html b/chrome/browser/resources/md_history/constants.html
new file mode 100644
index 0000000..7d01ff31
--- /dev/null
+++ b/chrome/browser/resources/md_history/constants.html
@@ -0,0 +1 @@
+<script src="chrome://history/constants.js"></script>
diff --git a/chrome/browser/resources/md_history/constants.js b/chrome/browser/resources/md_history/constants.js
new file mode 100644
index 0000000..54202c3
--- /dev/null
+++ b/chrome/browser/resources/md_history/constants.js
@@ -0,0 +1,13 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Globals:
+/** @const */ var RESULTS_PER_PAGE = 150;
+
+/**
+ * Amount of time between pageviews that we consider a 'break' in browsing,
+ * measured in milliseconds.
+ * @const
+ */
+var BROWSING_GAP_TIME = 15 * 60 * 1000;
diff --git a/chrome/browser/resources/md_history/history.html b/chrome/browser/resources/md_history/history.html
index 182ac8f..44af7bee 100644
--- a/chrome/browser/resources/md_history/history.html
+++ b/chrome/browser/resources/md_history/history.html
@@ -40,6 +40,7 @@
   <link rel="import" href="chrome://resources/html/load_time_data.html">
   <script src="strings.js"></script>
 
+  <link rel="import" href="chrome://history/constants.html">
   <link rel="import" href="chrome://history/history_list.html">
   <link rel="import" href="chrome://history/history_toolbar.html">
 
diff --git a/chrome/browser/resources/md_history/history.js b/chrome/browser/resources/md_history/history.js
index dff27c6..8279522 100644
--- a/chrome/browser/resources/md_history/history.js
+++ b/chrome/browser/resources/md_history/history.js
@@ -2,16 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Globals:
-/** @const */ var RESULTS_PER_PAGE = 150;
-
-/**
- * Amount of time between pageviews that we consider a 'break' in browsing,
- * measured in milliseconds.
- * @const
- */
-var BROWSING_GAP_TIME = 15 * 60 * 1000;
-
 window.addEventListener('load', function() {
   chrome.send('queryHistory', ['', 0, 0, 0, RESULTS_PER_PAGE]);
 });
@@ -19,9 +9,11 @@
 /**
  * Listens for history-item being selected or deselected (through checkbox)
  * and changes the view of the top toolbar.
+ * @param {{detail: {countAddition: number}}} e
  */
 window.addEventListener('history-checkbox-select', function(e) {
-  $('toolbar').count += e.detail.countAddition;
+  var toolbar = /** @type {HistoryToolbarElement} */($('toolbar'));
+  toolbar.count += e.detail.countAddition;
 });
 
 /**
@@ -29,8 +21,10 @@
  * checkbox to be unselected.
  */
 window.addEventListener('unselect-all', function() {
-  $('history-list').unselectAllItems($('toolbar').count);
-  $('toolbar').count = 0;
+  var historyList = /** @type {HistoryListElement} */($('history-list'));
+  var toolbar = /** @type {HistoryToolbarElement} */($('toolbar'));
+  historyList.unselectAllItems(toolbar.count);
+  toolbar.count = 0;
 });
 
 /**
@@ -38,15 +32,15 @@
  * to determine which ones are selected and deletes these.
  */
 window.addEventListener('delete-selected', function() {
-  if (!loadTimeData.getBoolean('allowDeletingHistory')) {
+  if (!loadTimeData.getBoolean('allowDeletingHistory'))
     return;
-  }
 
   // TODO(hsampson): add a popup to check whether the user definitely wants to
   // delete the selected items.
 
-  var toBeRemoved =
-      $('history-list').getSelectedItems($('toolbar').count);
+  var historyList = /** @type {HistoryListElement} */($('history-list'));
+  var toolbar = /** @type {HistoryToolbarElement} */($('toolbar'));
+  var toBeRemoved = historyList.getSelectedItems(toolbar.count);
   chrome.send('removeVisits', toBeRemoved);
 });
 
@@ -55,7 +49,7 @@
  * When the search is changed refresh the results from the backend.
  */
 window.addEventListener('search-changed', function(e) {
-  $('history-list').setLoading();
+  /** @type {HistoryListElement} */($('history-list')).setLoading();
   chrome.send('queryHistory', [e.detail.search, 0, 0, 0, RESULTS_PER_PAGE]);
 });
 
@@ -64,20 +58,23 @@
 /**
  * Our history system calls this function with results from searches.
  * @param {HistoryQuery} info An object containing information about the query.
- * @param {Array<HistoryEntry>} results A list of results.
+ * @param {!Array<HistoryEntry>} results A list of results.
  */
 function historyResult(info, results) {
-  $('history-list').addNewResults(results, info.term);
+  var historyList = /** @type {HistoryListElement} */($('history-list'));
+  historyList.addNewResults(results, info.term);
   if (info.finished)
-    $('history-list').disableResultLoading();
+    historyList.disableResultLoading();
 }
 
 /**
  * Called by the history backend when deletion was succesful.
  */
 function deleteComplete() {
-  $('history-list').removeDeletedHistory($('toolbar').count);
-  $('toolbar').count = 0;
+  var historyList = /** @type {HistoryListElement} */($('history-list'));
+  var toolbar = /** @type {HistoryToolbarElement} */($('toolbar'));
+  historyList.removeDeletedHistory(toolbar.count);
+  toolbar.count = 0;
 }
 
 /**
diff --git a/chrome/browser/resources/md_history/history_list.html b/chrome/browser/resources/md_history/history_list.html
index 8bba131d..85b587e 100644
--- a/chrome/browser/resources/md_history/history_list.html
+++ b/chrome/browser/resources/md_history/history_list.html
@@ -2,6 +2,7 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-item.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_shared_menu/cr_shared_menu.html">
+<link rel="import" href="chrome://history/constants.html">
 <link rel="import" href="chrome://history/history_item.html">
 <link rel="import" href="chrome://history/shared_style.html">
 
diff --git a/chrome/browser/resources/md_history/history_list.js b/chrome/browser/resources/md_history/history_list.js
index 76caf44..8aaea2ec 100644
--- a/chrome/browser/resources/md_history/history_list.js
+++ b/chrome/browser/resources/md_history/history_list.js
@@ -46,7 +46,7 @@
    * @private
    */
   closeMenu_: function() {
-    this.$.sharedMenu.closeMenu();
+    /** @type {CrSharedMenuElement} */(this.$.sharedMenu).closeMenu();
   },
 
   /**
@@ -63,7 +63,8 @@
    * @private
    */
   toggleMenu_: function(e) {
-    this.$.sharedMenu.toggleMenu(e.detail.target);
+    var target = e.detail.target;
+    /** @type {CrSharedMenuElement} */(this.$.sharedMenu).toggleMenu(target);
   },
 
   /**
@@ -86,9 +87,8 @@
       this.searchTerm = searchTerm;
     }
 
-    if (historyResults.length == 0) {
+    if (historyResults.length == 0)
       return;
-    }
 
     // Creates a copy of historyResults to prevent accidentally modifying this
     // field.
diff --git a/chrome/browser/resources/settings/certificate_manager_page/certificates_browser_proxy.html b/chrome/browser/resources/settings/certificate_manager_page/certificates_browser_proxy.html
new file mode 100644
index 0000000..b3bccdf
--- /dev/null
+++ b/chrome/browser/resources/settings/certificate_manager_page/certificates_browser_proxy.html
@@ -0,0 +1 @@
+<script src="chrome://md-settings/certificate_manager_page/certificates_browser_proxy.js"></script>
diff --git a/chrome/browser/resources/settings/certificate_manager_page/certificates_browser_proxy.js b/chrome/browser/resources/settings/certificate_manager_page/certificates_browser_proxy.js
new file mode 100644
index 0000000..26d6749
--- /dev/null
+++ b/chrome/browser/resources/settings/certificate_manager_page/certificates_browser_proxy.js
@@ -0,0 +1,254 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview A helper object used from the "Manage certificates" section
+ * to interact with the browser.
+ */
+
+/**
+ * @typedef {{
+ *   extractable: boolean,
+ *   id: string,
+ *   name: string,
+ *   policy: boolean,
+ *   readonly: boolean,
+ *   untrusted: boolean,
+ *   urlLocked: boolean
+ * }}
+ * @see chrome/browser/ui/webui/settings/certificates_handler.cc
+ */
+var CertificateSubnode;
+
+/**
+ * @typedef {{
+ *   id: string,
+ *   name: string,
+ *   subnodes: !Array<!CertificateSubnode>
+ * }}
+ * @see chrome/browser/ui/webui/settings/certificates_handler.cc
+ */
+var Certificate;
+
+/**
+ * @typedef {{
+ *   ssl: boolean,
+ *   email: boolean,
+ *   objSign: boolean
+ * }}
+ */
+var CaTrustInfo;
+
+/**
+ * Generic error returned from C++ via a Promise reject callback.
+ * @typedef {{
+ *   title: string,
+ *   description: string
+ * }}
+ * @see chrome/browser/ui/webui/settings/certificates_handler.cc
+ */
+var CertificatesError;
+
+
+/**
+ * Error returned from C++ via a Promise reject callback, when some certificates
+ * fail to be imported.
+ * @typedef {{
+ *   title: string,
+ *   description: string
+ *   certificateErrors: !Array<{certificateName: string, error: string}>
+ * }}
+ * @see chrome/browser/ui/webui/settings/certificates_handler.cc
+ */
+var CertificatesImportError;
+
+cr.define('settings', function() {
+  /** @interface */
+  function CertificatesBrowserProxy() {}
+
+  CertificatesBrowserProxy.prototype = {
+    /**
+     * Triggers two events in the following order
+     * 1) 'certificates-model-ready' event.
+     * 2) 'certificates-changed' event.
+     */
+    refreshCertificates: function() {},
+
+    /** @param {string} id */
+    viewCertificate: function(id) {},
+
+    /** @param {string} id */
+    exportCertificate: function(id) {},
+
+    /**
+     * @param {string} id
+     * @return {!Promise}
+     */
+    deleteCertificate: function(id) {},
+
+    /**
+     * @param {string} id
+     * @return {!Promise<!CaTrustInfo>}
+     */
+    getCaCertificateTrust: function(id) {},
+
+    /**
+     * @param {string} id
+     * @param {boolean} ssl
+     * @param {boolean} email
+     * @param {boolean} objSign
+     * @return {!Promise}
+     */
+    editCaCertificateTrust: function(id, ssl, email, objSign) {},
+
+    cancelImportExportCertificate: function() {},
+
+    /**
+     * @param {string} id
+     * @return {!Promise} A promise firing once the user has selected
+     *     the export location. A prompt should be shown to asking for a
+     *     password to use for encrypting the file. The password should be
+     *     passed back via a call to
+     *     exportPersonalCertificatePasswordSelected().
+     */
+    exportPersonalCertificate: function(id) {},
+
+    /**
+     * @param {string} password
+     * @return {!Promise}
+     */
+    exportPersonalCertificatePasswordSelected: function(password) {},
+
+    /**
+     * @param {boolean} useHardwareBacked
+     * @return {!Promise<boolean>} A promise firing once the user has selected
+     *     the file to be imported. If true a password prompt should be shown to
+     *     the user, and the password should be passed back via a call to
+     *     importPersonalCertificatePasswordSelected().
+     */
+    importPersonalCertificate: function(useHardwareBacked) {},
+
+    /**
+     * @param {string} password
+     * @return {!Promise}
+     */
+    importPersonalCertificatePasswordSelected: function(password) {},
+
+    /**
+     * @return {!Promise} A promise firing once the user has selected
+     *     the file to be imported, or failing with CertificatesError.
+     *     Upon success, a prompt should be shown to the user to specify the
+     *     trust levels, and that information should be passed back via a call
+     *     to importCaCertificateTrustSelected().
+     */
+    importCaCertificate: function() {},
+
+    /**
+     * @param {boolean} ssl
+     * @param {boolean} email
+     * @param {boolean} objSign
+     * @return {!Promise} A promise firing once the trust level for the imported
+     *     certificate has been successfully set. The promise is rejected if an
+     *     error occurred with either a CertificatesError or
+     *     CertificatesImportError.
+     */
+    importCaCertificateTrustSelected: function(ssl, email, objSign) {},
+
+    /**
+     * @return {!Promise} A promise firing once the certificate has been
+     *     imported. The promise is rejected if an error occurred, with either
+     *     a CertificatesError or CertificatesImportError.
+     */
+    importServerCertificate: function() {},
+  };
+
+  /**
+   * @constructor
+   * @implements {settings.CertificatesBrowserProxy}
+   */
+  function CertificatesBrowserProxyImpl() {}
+  // The singleton instance_ is replaced with a test version of this wrapper
+  // during testing.
+  cr.addSingletonGetter(CertificatesBrowserProxyImpl);
+
+  CertificatesBrowserProxyImpl.prototype = {
+    /** @override */
+    refreshCertificates: function() {
+      chrome.send('refreshCertificates');
+    },
+
+    /** @override */
+    viewCertificate: function(id) {
+      chrome.send('viewCertificate', [id]);
+    },
+
+    /** @override */
+    exportCertificate: function(id) {
+      chrome.send('exportCertificate', [id]);
+    },
+
+    /** @override */
+    deleteCertificate: function(id) {
+      return cr.sendWithPromise('deleteCertificate', id);
+    },
+
+    /** @override */
+    exportPersonalCertificate: function(id) {
+      return cr.sendWithPromise('exportPersonalCertificate', id);
+    },
+
+    /** @override */
+    exportPersonalCertificatePasswordSelected: function(password) {
+      return cr.sendWithPromise(
+          'exportPersonalCertificatePasswordSelected', password);
+    },
+
+    /** @override */
+    importPersonalCertificate: function(useHardwareBacked) {
+      return cr.sendWithPromise('importPersonalCertificate', useHardwareBacked);
+    },
+
+    /** @override */
+    importPersonalCertificatePasswordSelected: function(password) {
+      return cr.sendWithPromise(
+          'importPersonalCertificatePasswordSelected', password);
+    },
+
+    /** @override */
+    getCaCertificateTrust: function(id) {
+      return cr.sendWithPromise('getCaCertificateTrust', id);
+    },
+
+    /** @override */
+    editCaCertificateTrust: function(id, ssl, email, objSign) {
+      return cr.sendWithPromise(
+          'editCaCertificateTrust', id, ssl, email, objSign);
+    },
+
+    /** @override */
+    importCaCertificateTrustSelected: function(ssl, email, objSign) {
+      return cr.sendWithPromise(
+          'importCaCertificateTrustSelected', ssl, email, objSign);
+    },
+
+    /** @override */
+    cancelImportExportCertificate: function() {
+      chrome.send('cancelImportExportCertificate');
+    },
+
+    /** @override */
+    importCaCertificate: function() {
+      return cr.sendWithPromise('importCaCertificate');
+    },
+
+    /** @override */
+    importServerCertificate: function() {
+      return cr.sendWithPromise('importServerCertificate');
+    },
+  };
+
+  return {
+    CertificatesBrowserProxyImpl: CertificatesBrowserProxyImpl,
+  };
+});
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index 8754c7bb..f0d587d0 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -171,6 +171,12 @@
       <structure name="IDR_SETTINGS_CERTIFICATE_MANAGER_PAGE_JS"
                  file="certificate_manager_page/certificate_manager_page.js"
                  type="chrome_html" />
+      <structure name="IDR_SETTINGS_CERTIFICATES_BROWSER_PROXY_HTML"
+                 file="certificate_manager_page/certificates_browser_proxy.html"
+                 type="chrome_html" />
+      <structure name="IDR_SETTINGS_CERTIFICATES_BROWSER_PROXY_JS"
+                 file="certificate_manager_page/certificates_browser_proxy.js"
+                 type="chrome_html" />
       <structure name="IDR_SETTINGS_CLEAR_BROWSING_DATA_PAGE_CSS"
                  file="clear_browsing_data_page/clear_browsing_data_page.css"
                  type="chrome_html" />
diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc
index e4d5461..208f11fd 100644
--- a/chrome/browser/themes/theme_service.cc
+++ b/chrome/browser/themes/theme_service.cc
@@ -54,10 +54,6 @@
 #include "chrome/browser/supervised_user/supervised_user_theme.h"
 #endif
 
-#if defined(OS_WIN)
-#include "ui/base/win/shell.h"
-#endif
-
 using base::UserMetricsAction;
 using content::BrowserThread;
 using extensions::Extension;
@@ -413,6 +409,79 @@
   return false;
 }
 
+SkColor ThemeService::GetDefaultColor(int id, bool incognito) const {
+  // For backward compat with older themes, some newer colors are generated from
+  // older ones if they are missing.
+  const int kNtpText = ThemeProperties::COLOR_NTP_TEXT;
+  const int kLabelBackground =
+      ThemeProperties::COLOR_SUPERVISED_USER_LABEL_BACKGROUND;
+  switch (id) {
+    case ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON:
+      return color_utils::HSLShift(
+          gfx::kChromeIconGrey,
+          GetTint(ThemeProperties::TINT_BUTTONS, incognito));
+    case ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON_INACTIVE:
+      // The active color is overridden in Gtk2UI.
+      return SkColorSetA(
+          GetColor(ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON, incognito),
+          0x33);
+    case ThemeProperties::COLOR_BACKGROUND_TAB: {
+      // The tints here serve a different purpose than TINT_BACKGROUND_TAB.
+      // That tint is used to create background tab images for custom themes by
+      // lightening the frame images.  The tints here create solid colors for
+      // background tabs by darkening the foreground tab (toolbar) color.
+      const color_utils::HSL kTint = {-1, -1, 0.4296875};
+      const color_utils::HSL kTintIncognito = {-1, -1, 0.34375};
+      return color_utils::HSLShift(
+          GetColor(ThemeProperties::COLOR_TOOLBAR, incognito),
+          incognito ? kTintIncognito : kTint);
+    }
+    case ThemeProperties::COLOR_DETACHED_BOOKMARK_BAR_BACKGROUND:
+      if (UsingDefaultTheme())
+        break;
+      return GetColor(ThemeProperties::COLOR_TOOLBAR, incognito);
+    case ThemeProperties::COLOR_DETACHED_BOOKMARK_BAR_SEPARATOR:
+      if (UsingDefaultTheme())
+        break;
+      // Use 50% of bookmark text color as separator color.
+      return SkColorSetA(
+          GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT, incognito), 128);
+    case ThemeProperties::COLOR_NTP_SECTION_HEADER_TEXT:
+      return IncreaseLightness(GetColor(kNtpText, incognito), 0.30);
+    case ThemeProperties::COLOR_NTP_SECTION_HEADER_TEXT_HOVER:
+      return GetColor(kNtpText, incognito);
+    case ThemeProperties::COLOR_NTP_SECTION_HEADER_RULE:
+      return IncreaseLightness(GetColor(kNtpText, incognito), 0.70);
+    case ThemeProperties::COLOR_NTP_SECTION_HEADER_RULE_LIGHT:
+      return IncreaseLightness(GetColor(kNtpText, incognito), 0.86);
+    case ThemeProperties::COLOR_NTP_TEXT_LIGHT:
+      return IncreaseLightness(GetColor(kNtpText, incognito), 0.40);
+    case ThemeProperties::COLOR_TAB_THROBBER_SPINNING:
+    case ThemeProperties::COLOR_TAB_THROBBER_WAITING: {
+      SkColor base_color =
+          ui::GetAuraColor(id == ThemeProperties::COLOR_TAB_THROBBER_SPINNING
+                               ? ui::NativeTheme::kColorId_ThrobberSpinningColor
+                               : ui::NativeTheme::kColorId_ThrobberWaitingColor,
+                           nullptr);
+      color_utils::HSL hsl = GetTint(ThemeProperties::TINT_BUTTONS, incognito);
+      return color_utils::HSLShift(base_color, hsl);
+    }
+#if defined(ENABLE_SUPERVISED_USERS)
+    case ThemeProperties::COLOR_SUPERVISED_USER_LABEL:
+      return color_utils::GetReadableColor(
+          SK_ColorWHITE, GetColor(kLabelBackground, incognito));
+    case ThemeProperties::COLOR_SUPERVISED_USER_LABEL_BACKGROUND:
+      return color_utils::BlendTowardOppositeLuma(
+          GetColor(ThemeProperties::COLOR_FRAME, incognito), 0x80);
+    case ThemeProperties::COLOR_SUPERVISED_USER_LABEL_BORDER:
+      return color_utils::AlphaBlend(GetColor(kLabelBackground, incognito),
+                                     SK_ColorBLACK, 230);
+#endif
+  }
+
+  return ThemeProperties::GetDefaultColor(id, incognito);
+}
+
 color_utils::HSL ThemeService::GetTint(int id, bool incognito) const {
   DCHECK(CalledOnValidThread());
 
@@ -513,6 +582,15 @@
 }
 #endif
 
+bool ThemeService::ShouldUseNativeFrame() const {
+  return false;
+}
+
+bool ThemeService::HasCustomImage(int id) const {
+  return BrowserThemePack::IsPersistentImageID(id) && theme_supplier_ &&
+         theme_supplier_->HasCustomImage(id);
+}
+
 gfx::ImageSkia* ThemeService::GetImageSkiaNamed(int id, bool incognito) const {
   gfx::Image image = GetImageNamed(id, incognito);
   if (image.IsEmpty())
@@ -539,76 +617,7 @@
   if (theme_supplier_ && theme_supplier_->GetColor(theme_supplier_id, &color))
     return color;
 
-  // For backward compat with older themes, some newer colors are generated from
-  // older ones if they are missing.
-  const int kNtpText = ThemeProperties::COLOR_NTP_TEXT;
-  const int kLabelBackground =
-      ThemeProperties::COLOR_SUPERVISED_USER_LABEL_BACKGROUND;
-  switch (id) {
-    case ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON:
-      return color_utils::HSLShift(
-          gfx::kChromeIconGrey,
-          GetTint(ThemeProperties::TINT_BUTTONS, incognito));
-    case ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON_INACTIVE:
-      // The active color is overridden in Gtk2UI.
-      return SkColorSetA(
-          GetColor(ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON, incognito),
-          0x33);
-    case ThemeProperties::COLOR_BACKGROUND_TAB: {
-      // The tints here serve a different purpose than TINT_BACKGROUND_TAB.
-      // That tint is used to create background tab images for custom themes by
-      // lightening the frame images.  The tints here create solid colors for
-      // background tabs by darkening the foreground tab (toolbar) color.
-      const color_utils::HSL kTint = {-1, -1, 0.4296875};
-      const color_utils::HSL kTintIncognito = {-1, -1, 0.34375};
-      return color_utils::HSLShift(
-          GetColor(ThemeProperties::COLOR_TOOLBAR, incognito),
-          incognito ? kTintIncognito : kTint);
-    }
-    case ThemeProperties::COLOR_DETACHED_BOOKMARK_BAR_BACKGROUND:
-      if (UsingDefaultTheme())
-        break;
-      return GetColor(ThemeProperties::COLOR_TOOLBAR, incognito);
-    case ThemeProperties::COLOR_DETACHED_BOOKMARK_BAR_SEPARATOR:
-      if (UsingDefaultTheme())
-        break;
-      // Use 50% of bookmark text color as separator color.
-      return SkColorSetA(
-          GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT, incognito), 128);
-    case ThemeProperties::COLOR_NTP_SECTION_HEADER_TEXT:
-      return IncreaseLightness(GetColor(kNtpText, incognito), 0.30);
-    case ThemeProperties::COLOR_NTP_SECTION_HEADER_TEXT_HOVER:
-      return GetColor(kNtpText, incognito);
-    case ThemeProperties::COLOR_NTP_SECTION_HEADER_RULE:
-      return IncreaseLightness(GetColor(kNtpText, incognito), 0.70);
-    case ThemeProperties::COLOR_NTP_SECTION_HEADER_RULE_LIGHT:
-      return IncreaseLightness(GetColor(kNtpText, incognito), 0.86);
-    case ThemeProperties::COLOR_NTP_TEXT_LIGHT:
-      return IncreaseLightness(GetColor(kNtpText, incognito), 0.40);
-    case ThemeProperties::COLOR_TAB_THROBBER_SPINNING:
-    case ThemeProperties::COLOR_TAB_THROBBER_WAITING: {
-      SkColor base_color =
-          ui::GetAuraColor(id == ThemeProperties::COLOR_TAB_THROBBER_SPINNING
-                               ? ui::NativeTheme::kColorId_ThrobberSpinningColor
-                               : ui::NativeTheme::kColorId_ThrobberWaitingColor,
-                           nullptr);
-      color_utils::HSL hsl = GetTint(ThemeProperties::TINT_BUTTONS, incognito);
-      return color_utils::HSLShift(base_color, hsl);
-    }
-#if defined(ENABLE_SUPERVISED_USERS)
-    case ThemeProperties::COLOR_SUPERVISED_USER_LABEL:
-      return color_utils::GetReadableColor(
-          SK_ColorWHITE, GetColor(kLabelBackground, incognito));
-    case ThemeProperties::COLOR_SUPERVISED_USER_LABEL_BACKGROUND:
-      return color_utils::BlendTowardOppositeLuma(
-          GetColor(ThemeProperties::COLOR_FRAME, incognito), 0x80);
-    case ThemeProperties::COLOR_SUPERVISED_USER_LABEL_BORDER:
-      return color_utils::AlphaBlend(GetColor(kLabelBackground, incognito),
-                                     SK_ColorBLACK, 230);
-#endif
-  }
-
-  return ThemeProperties::GetDefaultColor(id, incognito);
+  return GetDefaultColor(id, incognito);
 }
 
 int ThemeService::GetDisplayProperty(int id) const {
@@ -638,21 +647,6 @@
   }
 }
 
-bool ThemeService::ShouldUseNativeFrame() const {
-  if (HasCustomImage(IDR_THEME_FRAME))
-    return false;
-#if defined(OS_WIN)
-  return ui::win::IsAeroGlassEnabled();
-#else
-  return false;
-#endif
-}
-
-bool ThemeService::HasCustomImage(int id) const {
-  return BrowserThemePack::IsPersistentImageID(id) && theme_supplier_ &&
-         theme_supplier_->HasCustomImage(id);
-}
-
 base::RefCountedMemory* ThemeService::GetRawData(
     int id,
     ui::ScaleFactor scale_factor) const {
diff --git a/chrome/browser/themes/theme_service.h b/chrome/browser/themes/theme_service.h
index 9eea41a..7f4cf1e8 100644
--- a/chrome/browser/themes/theme_service.h
+++ b/chrome/browser/themes/theme_service.h
@@ -136,6 +136,10 @@
   // Returns true if the ThemeService should use the system theme on startup.
   virtual bool ShouldInitWithSystemTheme() const;
 
+  // Returns the color to use for |id| and |incognito| if the theme service does
+  // not provide an override.
+  virtual SkColor GetDefaultColor(int id, bool incognito) const;
+
   // Get the specified tint - |id| is one of the TINT_* enum values.
   color_utils::HSL GetTint(int id, bool incognito) const;
 
@@ -157,6 +161,11 @@
   // from ClearAllThemeData().
   virtual void FreePlatformCaches();
 
+  // Implementation for ui::ThemeProvider (see block of functions in private
+  // section).
+  virtual bool ShouldUseNativeFrame() const;
+  bool HasCustomImage(int id) const;
+
   Profile* profile() const { return profile_; }
 
   void set_ready() { ready_ = true; }
@@ -211,8 +220,6 @@
   gfx::ImageSkia* GetImageSkiaNamed(int id, bool incognito) const;
   SkColor GetColor(int id, bool incognito) const;
   int GetDisplayProperty(int id) const;
-  bool ShouldUseNativeFrame() const;
-  bool HasCustomImage(int id) const;
   base::RefCountedMemory* GetRawData(int id,
                                      ui::ScaleFactor scale_factor) const;
 #if defined(OS_MACOSX)
diff --git a/chrome/browser/themes/theme_service_factory.cc b/chrome/browser/themes/theme_service_factory.cc
index 9f7ebbd..3e72af0e 100644
--- a/chrome/browser/themes/theme_service_factory.cc
+++ b/chrome/browser/themes/theme_service_factory.cc
@@ -16,7 +16,9 @@
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_registry_factory.h"
 
-#if defined(USE_AURA) && defined(USE_X11) && !defined(OS_CHROMEOS)
+#if defined(OS_WIN)
+#include "chrome/browser/themes/theme_service_win.h"
+#elif defined(USE_AURA) && defined(USE_X11) && !defined(OS_CHROMEOS)
 #include "chrome/browser/themes/theme_service_aurax11.h"
 #include "ui/views/linux_ui/linux_ui.h"
 #endif
@@ -55,7 +57,9 @@
 KeyedService* ThemeServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* profile) const {
   ThemeService* provider = NULL;
-#if defined(USE_AURA) && defined(USE_X11) && !defined(OS_CHROMEOS)
+#if defined(OS_WIN)
+  provider = new ThemeServiceWin;
+#elif defined(USE_AURA) && defined(USE_X11) && !defined(OS_CHROMEOS)
   provider = new ThemeServiceAuraX11;
 #else
   provider = new ThemeService;
diff --git a/chrome/browser/themes/theme_service_win.cc b/chrome/browser/themes/theme_service_win.cc
new file mode 100644
index 0000000..6573ee8
--- /dev/null
+++ b/chrome/browser/themes/theme_service_win.cc
@@ -0,0 +1,67 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/themes/theme_service_win.h"
+
+#include "base/bind.h"
+#include "base/win/windows_version.h"
+#include "chrome/browser/themes/theme_properties.h"
+#include "grit/theme_resources.h"
+#include "skia/ext/skia_utils_win.h"
+#include "ui/base/win/shell.h"
+
+ThemeServiceWin::ThemeServiceWin() {
+  // This just checks for Windows 10 instead of calling ShouldUseDwmFrameColor()
+  // because we want to monitor the frame color even when a custom frame is in
+  // use, so that it will be correct if at any time the user switches to the
+  // native frame.
+  if (base::win::GetVersion() >= base::win::VERSION_WIN10) {
+    dwm_key_.reset(new base::win::RegKey(
+        HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\DWM", KEY_READ));
+    OnDwmKeyUpdated();
+  }
+}
+
+ThemeServiceWin::~ThemeServiceWin() {
+}
+
+bool ThemeServiceWin::ShouldUseNativeFrame() const {
+  return !HasCustomImage(IDR_THEME_FRAME) && ui::win::IsAeroGlassEnabled();
+}
+
+SkColor ThemeServiceWin::GetDefaultColor(int id, bool incognito) const {
+  if (ShouldUseDwmFrameColor()) {
+    // Active native windows on Windows 10 may have a custom frame color.
+    if (id == ThemeProperties::COLOR_FRAME)
+      return dwm_frame_color_;
+
+    // Inactive native windows on Windows 10 always have a white frame.
+    if (id == ThemeProperties::COLOR_FRAME_INACTIVE)
+        return SK_ColorWHITE;
+  }
+
+  return ThemeService::GetDefaultColor(id, incognito);
+}
+
+bool ThemeServiceWin::ShouldUseDwmFrameColor() const {
+  return ShouldUseNativeFrame() &&
+         (base::win::GetVersion() >= base::win::VERSION_WIN10);
+}
+
+void ThemeServiceWin::OnDwmKeyUpdated() {
+  // Attempt to read the accent color.
+  DWORD accent_color, color_prevalence;
+  dwm_frame_color_ =
+      ((dwm_key_->ReadValueDW(L"ColorPrevalence", &color_prevalence) ==
+        ERROR_SUCCESS) &&
+       (color_prevalence == 1) &&
+       (dwm_key_->ReadValueDW(L"AccentColor", &accent_color) == ERROR_SUCCESS))
+          ? skia::COLORREFToSkColor(accent_color)
+          : SK_ColorWHITE;
+
+  // Watch for future changes.
+  if (!dwm_key_->StartWatching(base::Bind(
+          &ThemeServiceWin::OnDwmKeyUpdated, base::Unretained(this))))
+    dwm_key_.reset();
+}
diff --git a/chrome/browser/themes/theme_service_win.h b/chrome/browser/themes/theme_service_win.h
new file mode 100644
index 0000000..0f0473d
--- /dev/null
+++ b/chrome/browser/themes/theme_service_win.h
@@ -0,0 +1,39 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_THEMES_THEME_SERVICE_WIN_H_
+#define CHROME_BROWSER_THEMES_THEME_SERVICE_WIN_H_
+
+#include "base/win/registry.h"
+#include "chrome/browser/themes/theme_service.h"
+
+class ThemeServiceWin : public ThemeService {
+ public:
+  ThemeServiceWin();
+  ~ThemeServiceWin() override;
+
+ private:
+  // ThemeService:
+  bool ShouldUseNativeFrame() const override;
+  SkColor GetDefaultColor(int id, bool incognito) const override;
+
+  // Returns true if the window frame color is determined by the DWM, i.e. this
+  // is a native frame on Windows 10.
+  bool ShouldUseDwmFrameColor() const;
+
+  // Callback executed when |dwm_key_| is updated.  This re-reads the active
+  // frame color and updates |dwm_frame_color_|.
+  void OnDwmKeyUpdated();
+
+  // Registry key containing the params that determine the DWM frame color.
+  // This is only initialized on Windows 10.
+  scoped_ptr<base::win::RegKey> dwm_key_;
+
+  // The DWM frame color, if available; white otherwise.
+  SkColor dwm_frame_color_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThemeServiceWin);
+};
+
+#endif  // CHROME_BROWSER_THEMES_THEME_SERVICE_WIN_H_
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h
index 9fcd262..27113dfc 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h
+++ b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_DIALOG_COCOA_H_
 
 #include "base/mac/scoped_nsobject.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_types.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_view.h"
@@ -64,7 +65,7 @@
   // Closes the sheet and ends the modal loop. Triggers cleanup sequence.
   void CloseNow();
 
-  std::unique_ptr<ConstrainedWindowMac> constrained_window_;
+  scoped_ptr<ConstrainedWindowMac> constrained_window_;
   base::scoped_nsobject<AutofillDialogWindowController> sheet_delegate_;
 
   // The delegate |this| queries for logic and state.
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm
index 1731bb3..4a80bbd 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm
@@ -38,8 +38,8 @@
   base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
       [[CustomConstrainedWindowSheet alloc]
           initWithCustomWindow:[sheet_delegate_ window]]);
-  constrained_window_ =
-      CreateAndShowWebModalDialogMac(this, delegate_->GetWebContents(), sheet);
+  constrained_window_.reset(
+      new ConstrainedWindowMac(this, delegate_->GetWebContents(), sheet));
   [sheet_delegate_ show];
 }
 
diff --git a/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.h b/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.h
index e9358d3..64faef1 100644
--- a/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.h
+++ b/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_UI_COCOA_AUTOFILL_CARD_UNMASK_PROMPT_VIEW_BRIDGE_H_
 
 #include "base/mac/scoped_nsobject.h"
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h"
 #include "components/autofill/core/browser/ui/card_unmask_prompt_view.h"
 
@@ -40,7 +41,7 @@
   void PerformClose();
 
  private:
-  std::unique_ptr<ConstrainedWindowMac> constrained_window_;
+  scoped_ptr<ConstrainedWindowMac> constrained_window_;
   base::scoped_nsobject<CardUnmaskPromptViewCocoa> view_controller_;
 
   // The controller |this| queries for logic and state.
diff --git a/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.mm b/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.mm
index b4f949e..2a9d770 100644
--- a/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.mm
+++ b/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.mm
@@ -87,8 +87,8 @@
   [window setContentView:[view_controller_ view]];
   base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
       [[CustomConstrainedWindowSheet alloc] initWithCustomWindow:window]);
-  constrained_window_ =
-      CreateAndShowWebModalDialogMac(this, web_contents_, sheet);
+  constrained_window_.reset(
+      new ConstrainedWindowMac(this, web_contents_, sheet));
 }
 
 void CardUnmaskPromptViewBridge::ControllerGone() {
diff --git a/chrome/browser/ui/cocoa/certificate_viewer_mac.h b/chrome/browser/ui/cocoa/certificate_viewer_mac.h
index 7990758..f33bef2d 100644
--- a/chrome/browser/ui/cocoa/certificate_viewer_mac.h
+++ b/chrome/browser/ui/cocoa/certificate_viewer_mac.h
@@ -24,7 +24,7 @@
   base::scoped_nsobject<NSArray> certificates_;
   scoped_ptr<SSLCertificateViewerCocoaBridge> observer_;
   base::scoped_nsobject<SFCertificatePanel> panel_;
-  std::unique_ptr<ConstrainedWindowMac> constrainedWindow_;
+  scoped_ptr<ConstrainedWindowMac> constrainedWindow_;
   base::scoped_nsobject<NSWindow> overlayWindow_;
   BOOL closePending_;
   // A copy of the sheet's frame used to restore on show.
diff --git a/chrome/browser/ui/cocoa/certificate_viewer_mac.mm b/chrome/browser/ui/cocoa/certificate_viewer_mac.mm
index 1adb0f1..5c41b94f 100644
--- a/chrome/browser/ui/cocoa/certificate_viewer_mac.mm
+++ b/chrome/browser/ui/cocoa/certificate_viewer_mac.mm
@@ -134,8 +134,8 @@
   panel_.reset([[SFCertificatePanel alloc] init]);
   [panel_ setPolicies:(id) policies.get()];
 
-  constrainedWindow_ =
-      CreateAndShowWebModalDialogMac(observer_.get(), webContents, self);
+  constrainedWindow_.reset(
+      new ConstrainedWindowMac(observer_.get(), webContents, self));
 }
 
 - (NSWindow*)overlayWindow {
@@ -189,10 +189,6 @@
   // NOOP
 }
 
-- (void)resizeWithNewSize:(NSSize)preferredSize {
-  // NOOP
-}
-
 - (NSWindow*)sheetWindow {
   return panel_;
 }
diff --git a/chrome/browser/ui/cocoa/constrained_web_dialog_delegate_mac.mm b/chrome/browser/ui/cocoa/constrained_web_dialog_delegate_mac.mm
index 5dc49ab..0ce4df8d 100644
--- a/chrome/browser/ui/cocoa/constrained_web_dialog_delegate_mac.mm
+++ b/chrome/browser/ui/cocoa/constrained_web_dialog_delegate_mac.mm
@@ -11,11 +11,7 @@
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.h"
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h"
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_web_dialog_sheet.h"
-#include "chrome/browser/ui/webui/chrome_web_contents_handler.h"
-#include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "ui/base/cocoa/window_size_constants.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/web_dialogs/web_dialog_delegate.h"
 #include "ui/web_dialogs/web_dialog_ui.h"
@@ -27,61 +23,19 @@
 
 namespace {
 
-class ConstrainedWebDialogDelegateMac;
-
-// This class is to trigger a resize to the dialog window when
-// ResizeDueToAutoResize() is invoked.
-class WebDialogWebContentsDelegateMac
-    : public ui::WebDialogWebContentsDelegate {
- public:
-  WebDialogWebContentsDelegateMac(content::BrowserContext* browser_context,
-                                  content::WebContentsObserver* observer,
-                                  ConstrainedWebDialogDelegateBase* delegate)
-      : ui::WebDialogWebContentsDelegate(browser_context,
-                                         new ChromeWebContentsHandler()),
-        observer_(observer),
-        delegate_(delegate) {
-  }
-  ~WebDialogWebContentsDelegateMac() override {}
-
-  void ResizeDueToAutoResize(content::WebContents* source,
-                             const gfx::Size& preferred_size) override {
-    if (!observer_->web_contents())
-      return;
-    delegate_->ResizeToGivenSize(preferred_size);
-  }
-
- private:
-  // These members must outlive the instance.
-  content::WebContentsObserver* const observer_;
-  ConstrainedWebDialogDelegateBase* delegate_;
-
-  DISALLOW_COPY_AND_ASSIGN(WebDialogWebContentsDelegateMac);
-};
-
 class ConstrainedWebDialogDelegateMac
     : public ConstrainedWebDialogDelegateBase {
  public:
   ConstrainedWebDialogDelegateMac(
       content::BrowserContext* browser_context,
-      WebDialogDelegate* delegate,
-      content::WebContentsObserver* observer)
-      : ConstrainedWebDialogDelegateBase(browser_context, delegate,
-          new WebDialogWebContentsDelegateMac(browser_context, observer,
-                                              this)) {}
+      WebDialogDelegate* delegate)
+      : ConstrainedWebDialogDelegateBase(browser_context, delegate, NULL) {}
 
   // WebDialogWebContentsDelegate interface.
   void CloseContents(WebContents* source) override {
     window_->CloseWebContentsModalDialog();
   }
 
-  // ConstrainedWebDialogDelegateBase:
-  void ResizeToGivenSize(const gfx::Size size) override {
-    NSSize updated_preferred_size = NSMakeSize(size.width(),
-                                               size.height());
-    [window_->sheet() resizeWithNewSize:updated_preferred_size];
-  }
-
   void set_window(ConstrainedWindowMac* window) { window_ = window; }
   ConstrainedWindowMac* window() const { return window_; }
 
@@ -96,16 +50,13 @@
 
 class ConstrainedWebDialogDelegateViewMac :
     public ConstrainedWindowMacDelegate,
-    public ConstrainedWebDialogDelegate,
-    public content::WebContentsObserver {
+    public ConstrainedWebDialogDelegate {
 
  public:
   ConstrainedWebDialogDelegateViewMac(
       content::BrowserContext* browser_context,
       WebDialogDelegate* delegate,
-      content::WebContents* web_contents,
-      const gfx::Size& min_size,
-      const gfx::Size& max_size);
+      content::WebContents* web_contents);
   ~ConstrainedWebDialogDelegateViewMac() override {}
 
   // ConstrainedWebDialogDelegate interface
@@ -124,37 +75,16 @@
   gfx::NativeWindow GetNativeDialog() override { return window_; }
   WebContents* GetWebContents() override { return impl_->GetWebContents(); }
   gfx::Size GetMinimumSize() const override {
-    return min_size_;
+    NOTIMPLEMENTED();
+    return gfx::Size();
   }
   gfx::Size GetMaximumSize() const override {
-    return max_size_;
+    NOTIMPLEMENTED();
+    return gfx::Size();
   }
   gfx::Size GetPreferredSize() const override {
-    gfx::Size size;
-    if (!impl_->closed_via_webui()) {
-      NSRect frame = [window_ frame];
-      size = gfx::Size(frame.size.width, frame.size.height);
-    }
-    return size;
-  }
-
-  // content::WebContentsObserver:
-  void RenderViewCreated(content::RenderViewHost* render_view_host) override {
-    if (IsDialogAutoResizable())
-      EnableAutoResize();
-  }
-  void RenderViewHostChanged(content::RenderViewHost* old_host,
-                             content::RenderViewHost* new_host) override {
-    if (IsDialogAutoResizable())
-      EnableAutoResize();
-  }
-  void DocumentOnLoadCompletedInMainFrame() override {
-    if (!IsDialogAutoResizable())
-      return;
-
-    EnableAutoResize();
-    if (GetWebContents())
-      constrained_window_->ShowWebContentsModalDialog();
+    NOTIMPLEMENTED();
+    return gfx::Size();
   }
 
   // ConstrainedWindowMacDelegate interface
@@ -165,53 +95,25 @@
   }
 
  private:
-  void EnableAutoResize() {
-    if (!GetWebContents())
-      return;
-
-    content::RenderViewHost* render_view_host =
-        GetWebContents()->GetRenderViewHost();
-    render_view_host->EnableAutoResize(min_size_, max_size_);
-  }
-
-  // Whether or not the dialog is autoresizable is determined based on whether
-  // |max_size_| was specified.
-  bool IsDialogAutoResizable() {
-    return !max_size_.IsEmpty();
-  }
-
   scoped_ptr<ConstrainedWebDialogDelegateMac> impl_;
-  std::unique_ptr<ConstrainedWindowMac> constrained_window_;
+  scoped_ptr<ConstrainedWindowMac> constrained_window_;
   base::scoped_nsobject<NSWindow> window_;
 
-  // Minimum and maximum sizes to determine dialog bounds for auto-resizing.
-  const gfx::Size min_size_;
-  const gfx::Size max_size_;
-
   DISALLOW_COPY_AND_ASSIGN(ConstrainedWebDialogDelegateViewMac);
 };
 
 ConstrainedWebDialogDelegateViewMac::ConstrainedWebDialogDelegateViewMac(
     content::BrowserContext* browser_context,
     WebDialogDelegate* delegate,
-    content::WebContents* web_contents,
-    const gfx::Size& min_size,
-    const gfx::Size& max_size)
-    : content::WebContentsObserver(web_contents),
-      impl_(new ConstrainedWebDialogDelegateMac(browser_context, delegate,
-            this)),
-      min_size_(min_size),
-      max_size_(max_size) {
-  if (IsDialogAutoResizable())
-    Observe(GetWebContents());
-
+    content::WebContents* web_contents)
+    : impl_(new ConstrainedWebDialogDelegateMac(browser_context, delegate)) {
   // Create a window to hold web_contents in the constrained sheet:
   gfx::Size size;
   delegate->GetDialogSize(&size);
   NSRect frame = NSMakeRect(0, 0, size.width(), size.height());
 
-  window_.reset([[ConstrainedWindowCustomWindow alloc]
-                initWithContentRect:ui::kWindowSizeDeterminedLater]);
+  window_.reset(
+      [[ConstrainedWindowCustomWindow alloc] initWithContentRect:frame]);
   [GetWebContents()->GetNativeView() setFrame:frame];
   [GetWebContents()->GetNativeView() setAutoresizingMask:
       NSViewWidthSizable|NSViewHeightSizable];
@@ -220,14 +122,8 @@
   base::scoped_nsobject<WebDialogConstrainedWindowSheet> sheet(
       [[WebDialogConstrainedWindowSheet alloc] initWithCustomWindow:window_
                                                   webDialogDelegate:delegate]);
-
-  if (IsDialogAutoResizable()) {
-    constrained_window_ = CreateWebModalDialogMac(
-          this, web_contents, sheet);
-  } else {
-    constrained_window_ = CreateAndShowWebModalDialogMac(
-          this, web_contents, sheet);
-  }
+  constrained_window_.reset(new ConstrainedWindowMac(
+      this, web_contents, sheet));
 
   impl_->set_window(constrained_window_.get());
 }
@@ -239,23 +135,6 @@
   // Deleted when the dialog closes.
   ConstrainedWebDialogDelegateViewMac* constrained_delegate =
       new ConstrainedWebDialogDelegateViewMac(
-          browser_context, delegate, web_contents,
-          gfx::Size(), gfx::Size());
-  return constrained_delegate;
-}
-
-ConstrainedWebDialogDelegate* ShowConstrainedWebDialogWithAutoResize(
-    content::BrowserContext* browser_context,
-    WebDialogDelegate* delegate,
-    content::WebContents* web_contents,
-    const gfx::Size& min_size,
-    const gfx::Size& max_size) {
-  DCHECK(!min_size.IsEmpty());
-  DCHECK(!max_size.IsEmpty());
-  // Deleted when the dialog closes.
-  ConstrainedWebDialogDelegateViewMac* constrained_delegate =
-      new ConstrainedWebDialogDelegateViewMac(
-          browser_context, delegate, web_contents,
-          min_size, max_size);
+          browser_context, delegate, web_contents);
   return constrained_delegate;
 }
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.mm
index ab67fc6..aac59467 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.mm
@@ -73,10 +73,6 @@
   [customWindow_ setFrameOrigin:origin];
 }
 
-- (void)resizeWithNewSize:(NSSize)size {
-  // NOOP
-}
-
 - (NSWindow*)sheetWindow {
   return customWindow_;
 }
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h
index 3b60a39..e3d981e 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h
@@ -7,9 +7,6 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/mac/scoped_nsobject.h"
-#include "components/web_modal/web_contents_modal_dialog_manager.h"
-
 namespace content {
 class WebContents;
 }
@@ -24,18 +21,6 @@
   virtual void OnConstrainedWindowClosed(ConstrainedWindowMac* window) = 0;
 };
 
-// Creates a ConstrainedWindowMac, shows the dialog, and returns it.
-std::unique_ptr<ConstrainedWindowMac> CreateAndShowWebModalDialogMac(
-    ConstrainedWindowMacDelegate* delegate,
-    content::WebContents* web_contents,
-    id<ConstrainedWindowSheet> sheet);
-
-// Creates a ConstrainedWindowMac and returns it.
-std::unique_ptr<ConstrainedWindowMac> CreateWebModalDialogMac(
-    ConstrainedWindowMacDelegate* delegate,
-    content::WebContents* web_contents,
-    id<ConstrainedWindowSheet> sheet);
-
 // Constrained window implementation for Mac.
 // Normally an instance of this class is owned by the delegate. The delegate
 // should delete the instance when the window is closed.
@@ -46,9 +31,6 @@
                        id<ConstrainedWindowSheet> sheet);
   ~ConstrainedWindowMac();
 
-  // Shows the constrained window.
-  void ShowWebContentsModalDialog();
-
   // Closes the constrained window.
   void CloseWebContentsModalDialog();
 
@@ -56,24 +38,13 @@
   void set_manager(SingleWebContentsDialogManagerCocoa* manager) {
     manager_ = manager;
   }
-  id<ConstrainedWindowSheet> sheet() const { return sheet_.get(); }
 
   // Called by |manager_| when the dialog is closing.
   void OnDialogClosing();
 
-  // Whether or not the dialog was shown. If the dialog is auto-resizable, it
-  // is hidden until its WebContents initially loads.
-  bool DialogWasShown();
-
-  // Gets the dialog manager for |web_contents_|.
-  web_modal::WebContentsModalDialogManager* GetDialogManager();
-
  private:
   ConstrainedWindowMacDelegate* delegate_;  // weak, owns us.
   SingleWebContentsDialogManagerCocoa* manager_;  // weak, owned by WCMDM.
-  content::WebContents* web_contents_;  // weak, owned by dialog initiator.
-  base::scoped_nsprotocol<id<ConstrainedWindowSheet>> sheet_;
-  scoped_ptr<SingleWebContentsDialogManagerCocoa> native_manager_;
 };
 
 #endif  // CHROME_BROWSER_UI_COCOA_CONSTRAINED_WINDOW_CONSTRAINED_WINDOW_MAC_
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.mm
index 510402e8..16f755c 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.mm
@@ -11,59 +11,35 @@
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet.h"
 #import "chrome/browser/ui/cocoa/single_web_contents_dialog_manager_cocoa.h"
 #include "components/guest_view/browser/guest_view_base.h"
+#include "components/web_modal/web_contents_modal_dialog_manager.h"
 #include "content/public/browser/browser_thread.h"
 
 using web_modal::WebContentsModalDialogManager;
 
-std::unique_ptr<ConstrainedWindowMac> CreateAndShowWebModalDialogMac(
-    ConstrainedWindowMacDelegate* delegate,
-    content::WebContents* web_contents,
-    id<ConstrainedWindowSheet> sheet) {
-  ConstrainedWindowMac* window =
-      new ConstrainedWindowMac(delegate, web_contents, sheet);
-  window->ShowWebContentsModalDialog();
-  return std::unique_ptr<ConstrainedWindowMac>(window);
-}
-
-std::unique_ptr<ConstrainedWindowMac> CreateWebModalDialogMac(
-    ConstrainedWindowMacDelegate* delegate,
-    content::WebContents* web_contents,
-    id<ConstrainedWindowSheet> sheet) {
-  return std::unique_ptr<ConstrainedWindowMac>(
-      new ConstrainedWindowMac(delegate, web_contents, sheet));
-}
-
 ConstrainedWindowMac::ConstrainedWindowMac(
     ConstrainedWindowMacDelegate* delegate,
     content::WebContents* web_contents,
     id<ConstrainedWindowSheet> sheet)
-    : delegate_(delegate),
-      sheet_([sheet retain]) {
+    : delegate_(delegate) {
   DCHECK(sheet);
 
   // |web_contents| may be embedded within a chain of nested GuestViews. If it
   // is, follow the chain of embedders to the outermost WebContents and use it.
-  web_contents_ =
+  web_contents =
       guest_view::GuestViewBase::GetTopLevelWebContents(web_contents);
 
-  native_manager_.reset(
-      new SingleWebContentsDialogManagerCocoa(this, sheet_.get(),
-                                              GetDialogManager()));
+  auto manager = WebContentsModalDialogManager::FromWebContents(web_contents);
+  scoped_ptr<SingleWebContentsDialogManagerCocoa> native_manager(
+      new SingleWebContentsDialogManagerCocoa(this, sheet, manager));
+  manager->ShowDialogWithManager([sheet sheetWindow],
+                                 std::move(native_manager));
 }
 
 ConstrainedWindowMac::~ConstrainedWindowMac() {
   CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-  native_manager_.reset();
   DCHECK(!manager_);
 }
 
-void ConstrainedWindowMac::ShowWebContentsModalDialog() {
-  scoped_ptr<SingleWebContentsDialogManagerCocoa> dialog_manager;
-  dialog_manager.reset(native_manager_.release());
-  GetDialogManager()->ShowDialogWithManager(
-      [sheet_.get() sheetWindow], std::move(dialog_manager));
-}
-
 void ConstrainedWindowMac::CloseWebContentsModalDialog() {
   if (manager_)
     manager_->Close();
@@ -73,13 +49,3 @@
   if (delegate_)
     delegate_->OnConstrainedWindowClosed(this);
 }
-
-bool ConstrainedWindowMac::DialogWasShown() {
-  // If the dialog was shown, |native_manager_| would have been released.
-  return !native_manager_;
-}
-
-WebContentsModalDialogManager* ConstrainedWindowMac::GetDialogManager() {
-  DCHECK(web_contents_);
-  return WebContentsModalDialogManager::FromWebContents(web_contents_);
-}
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac_browsertest.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac_browsertest.mm
index d8ffb1e..8e6ceda 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac_browsertest.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac_browsertest.mm
@@ -79,15 +79,14 @@
 IN_PROC_BROWSER_TEST_F(ConstrainedWindowMacTest, ShowInInactiveTab) {
   // Show dialog in non active tab.
   NiceMock<ConstrainedWindowDelegateMock> delegate;
-  std::unique_ptr<ConstrainedWindowMac> dialog(
-      CreateAndShowWebModalDialogMac(&delegate, tab0_, sheet_));
+  ConstrainedWindowMac dialog(&delegate, tab0_, sheet_);
   EXPECT_EQ(0.0, [sheet_window_ alphaValue]);
 
   // Switch to inactive tab.
   browser()->tab_strip_model()->ActivateTabAt(0, true);
   EXPECT_EQ(1.0, [sheet_window_ alphaValue]);
 
-  dialog->CloseWebContentsModalDialog();
+  dialog.CloseWebContentsModalDialog();
 }
 
 // If a tab has never been shown then the associated tab view for the web
@@ -106,8 +105,7 @@
 
   // Show dialog and verify that it's not visible yet.
   NiceMock<ConstrainedWindowDelegateMock> delegate;
-  std::unique_ptr<ConstrainedWindowMac> dialog(
-      CreateAndShowWebModalDialogMac(&delegate, tab2, sheet_));
+  ConstrainedWindowMac dialog(&delegate, tab2, sheet_);
   EXPECT_FALSE([sheet_window_ isVisible]);
 
   // Activate the tab and verify that the constrained window is shown.
@@ -116,27 +114,25 @@
   EXPECT_TRUE([sheet_window_ isVisible]);
   EXPECT_EQ(1.0, [sheet_window_ alphaValue]);
 
-  dialog->CloseWebContentsModalDialog();
+  dialog.CloseWebContentsModalDialog();
 }
 
 // Test that adding a sheet disables tab dragging.
 IN_PROC_BROWSER_TEST_F(ConstrainedWindowMacTest, TabDragging) {
   NiceMock<ConstrainedWindowDelegateMock> delegate;
-  std::unique_ptr<ConstrainedWindowMac> dialog(
-      CreateAndShowWebModalDialogMac(&delegate, tab1_, sheet_));
+  ConstrainedWindowMac dialog(&delegate, tab1_, sheet_);
 
   // Verify that the dialog disables dragging.
   EXPECT_TRUE([controller_ isTabDraggable:tab_view0_]);
   EXPECT_FALSE([controller_ isTabDraggable:tab_view1_]);
 
-  dialog->CloseWebContentsModalDialog();
+  dialog.CloseWebContentsModalDialog();
 }
 
 // Test that closing a browser window with a sheet works.
 IN_PROC_BROWSER_TEST_F(ConstrainedWindowMacTest, BrowserWindowClose) {
   NiceMock<ConstrainedWindowDelegateMock> delegate;
-  std::unique_ptr<ConstrainedWindowMac> dialog(
-      CreateAndShowWebModalDialogMac(&delegate, tab1_, sheet_));
+  ConstrainedWindowMac dialog(&delegate, tab1_, sheet_);
   EXPECT_EQ(1.0, [sheet_window_ alphaValue]);
 
   // Close the browser window.
@@ -150,8 +146,7 @@
 // Test that closing a tab with a sheet works.
 IN_PROC_BROWSER_TEST_F(ConstrainedWindowMacTest, TabClose) {
   NiceMock<ConstrainedWindowDelegateMock> delegate;
-  std::unique_ptr<ConstrainedWindowMac> dialog(
-      CreateAndShowWebModalDialogMac(&delegate, tab1_, sheet_));
+  ConstrainedWindowMac dialog(&delegate, tab1_, sheet_);
   EXPECT_EQ(1.0, [sheet_window_ alphaValue]);
 
   // Close the tab.
@@ -165,8 +160,7 @@
 // Test that the sheet is still visible after entering and exiting fullscreen.
 IN_PROC_BROWSER_TEST_F(ConstrainedWindowMacTest, BrowserWindowFullscreen) {
   NiceMock<ConstrainedWindowDelegateMock> delegate;
-  std::unique_ptr<ConstrainedWindowMac> dialog(
-      CreateAndShowWebModalDialogMac(&delegate, tab1_, sheet_));
+  ConstrainedWindowMac dialog(&delegate, tab1_, sheet_);
   EXPECT_EQ(1.0, [sheet_window_ alphaValue]);
 
   // Toggle fullscreen twice: one for entering and one for exiting.
@@ -186,5 +180,5 @@
     EXPECT_EQ(1.0, [sheet_window_ alphaValue]);
   }
 
-  dialog->CloseWebContentsModalDialog();
+  dialog.CloseWebContentsModalDialog();
 }
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet.h b/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet.h
index cf24f7d..4549556 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet.h
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet.h
@@ -24,8 +24,6 @@
 
 - (void)updateSheetPosition;
 
-- (void)resizeWithNewSize:(NSSize)size;
-
 @property(readonly, nonatomic) NSWindow* sheetWindow;
 
 @end
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller_unittest.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller_unittest.mm
index 6566d21..05038cf 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller_unittest.mm
@@ -59,10 +59,6 @@
 - (void)updateSheetPosition {
 }
 
-- (void)resizeWithNewSize:(NSSize)size {
-  // NOOP
-}
-
 - (NSWindow*)sheetWindow {
   return [alert_ window];
 }
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_web_dialog_sheet.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_web_dialog_sheet.mm
index 6e7d3f19..3c71f00 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_web_dialog_sheet.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_web_dialog_sheet.mm
@@ -27,14 +27,4 @@
   [super updateSheetPosition];
 }
 
-- (void)resizeWithNewSize:(NSSize)size {
-  [customWindow_ setContentSize:size];
-
-  // self's updateSheetPosition() sets |customWindow_|'s contentSize to a
-  // fixed dialog size. Here, we want to resize to |size| instead. Use
-  // super rather than self to bypass the setContentSize() call for the fixed
-  // size.
-  [super updateSheetPosition];
-}
-
 @end
diff --git a/chrome/browser/ui/cocoa/content_settings/collected_cookies_mac.h b/chrome/browser/ui/cocoa/content_settings/collected_cookies_mac.h
index 55b55c9..e895491e 100644
--- a/chrome/browser/ui/cocoa/content_settings/collected_cookies_mac.h
+++ b/chrome/browser/ui/cocoa/content_settings/collected_cookies_mac.h
@@ -47,7 +47,7 @@
 
   content::NotificationRegistrar registrar_;
 
-  std::unique_ptr<ConstrainedWindowMac> window_;
+  scoped_ptr<ConstrainedWindowMac> window_;
 
   base::scoped_nsobject<CollectedCookiesWindowController> sheet_controller_;
 
diff --git a/chrome/browser/ui/cocoa/content_settings/collected_cookies_mac.mm b/chrome/browser/ui/cocoa/content_settings/collected_cookies_mac.mm
index 7c85ffe8..679c212 100644
--- a/chrome/browser/ui/cocoa/content_settings/collected_cookies_mac.mm
+++ b/chrome/browser/ui/cocoa/content_settings/collected_cookies_mac.mm
@@ -66,7 +66,8 @@
   base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
       [[CustomConstrainedWindowSheet alloc]
           initWithCustomWindow:[sheet_controller_ window]]);
-  window_ = CreateAndShowWebModalDialogMac(this, web_contents, sheet);
+  window_.reset(new ConstrainedWindowMac(
+      this, web_contents, sheet));
 }
 
 CollectedCookiesMac::~CollectedCookiesMac() {
diff --git a/chrome/browser/ui/cocoa/extensions/device_permissions_dialog_controller.h b/chrome/browser/ui/cocoa/extensions/device_permissions_dialog_controller.h
index 19e5f3c..73e04f7 100644
--- a/chrome/browser/ui/cocoa/extensions/device_permissions_dialog_controller.h
+++ b/chrome/browser/ui/cocoa/extensions/device_permissions_dialog_controller.h
@@ -39,7 +39,7 @@
  private:
   scoped_refptr<extensions::DevicePermissionsPrompt::Prompt> prompt_;
   base::scoped_nsobject<DevicePermissionsViewController> view_controller_;
-  std::unique_ptr<ConstrainedWindowMac> constrained_window_;
+  scoped_ptr<ConstrainedWindowMac> constrained_window_;
 };
 
 #endif  // CHROME_BROWSER_UI_COCOA_EXTENSIONS_DEVICE_PERMISSIONS_DIALOG_CONTROLER_H_
diff --git a/chrome/browser/ui/cocoa/extensions/device_permissions_dialog_controller.mm b/chrome/browser/ui/cocoa/extensions/device_permissions_dialog_controller.mm
index 881aff0..6babaf28 100644
--- a/chrome/browser/ui/cocoa/extensions/device_permissions_dialog_controller.mm
+++ b/chrome/browser/ui/cocoa/extensions/device_permissions_dialog_controller.mm
@@ -33,8 +33,8 @@
 
   base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
       [[CustomConstrainedWindowSheet alloc] initWithCustomWindow:window]);
-  constrained_window_ =
-      CreateAndShowWebModalDialogMac(this, web_contents, sheet);
+  constrained_window_.reset(
+      new ConstrainedWindowMac(this, web_contents, sheet));
 }
 
 DevicePermissionsDialogController::~DevicePermissionsDialogController() {
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.h b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.h
index 455062c6..26143ea 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.h
+++ b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.h
@@ -57,7 +57,7 @@
 
   ExtensionInstallPrompt::DoneCallback done_callback_;
   base::scoped_nsobject<ExtensionInstallViewController> view_controller_;
-  std::unique_ptr<ConstrainedWindowMac> constrained_window_;
+  scoped_ptr<ConstrainedWindowMac> constrained_window_;
   scoped_ptr<extensions::ExperienceSamplingEvent> sampling_event_;
 
   DISALLOW_COPY_AND_ASSIGN(ExtensionInstallDialogController);
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm
index 4685a25b..826a3bc 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm
@@ -60,8 +60,8 @@
 
   base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
       [[CustomConstrainedWindowSheet alloc] initWithCustomWindow:window]);
-  constrained_window_ = CreateAndShowWebModalDialogMac(
-      this, show_params->GetParentWebContents(), sheet);
+  constrained_window_.reset(new ConstrainedWindowMac(
+      this, show_params->GetParentWebContents(), sheet));
 
   std::string event_name = ExperienceSamplingEvent::kExtensionInstallDialog;
   event_name.append(
diff --git a/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa.h b/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa.h
index 6faeff65..9b3553a 100644
--- a/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa.h
+++ b/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa.h
@@ -69,7 +69,7 @@
   CGFloat CreateCheckboxSeparator(CGFloat y_pos, NSString* header);
 
   MediaGalleriesDialogController* controller_;  // weak
-  std::unique_ptr<ConstrainedWindowMac> window_;
+  scoped_ptr<ConstrainedWindowMac> window_;
 
   // The alert that the dialog is being displayed as.
   base::scoped_nsobject<ConstrainedWindowAlert> alert_;
diff --git a/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa.mm b/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa.mm
index e3fe7a8..01cf67c0 100644
--- a/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa.mm
+++ b/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa.mm
@@ -102,8 +102,8 @@
     base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
         [[CustomConstrainedWindowSheet alloc]
             initWithCustomWindow:[alert_ window]]);
-    window_ = CreateAndShowWebModalDialogMac(
-        this, controller->WebContents(), sheet);
+    window_.reset(new ConstrainedWindowMac(
+        this, controller->WebContents(), sheet));
   }
 }
 
diff --git a/chrome/browser/ui/cocoa/login_prompt_cocoa.mm b/chrome/browser/ui/cocoa/login_prompt_cocoa.mm
index 4d72782..2c24253b 100644
--- a/chrome/browser/ui/cocoa/login_prompt_cocoa.mm
+++ b/chrome/browser/ui/cocoa/login_prompt_cocoa.mm
@@ -80,8 +80,8 @@
     base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
         [[CustomConstrainedWindowSheet alloc]
             initWithCustomWindow:[sheet_controller_ window]]);
-    constrained_window_ = CreateAndShowWebModalDialogMac(
-        this, requesting_contents, sheet);
+    constrained_window_.reset(new ConstrainedWindowMac(
+        this, requesting_contents, sheet));
 
     NotifyAuthNeeded();
   }
@@ -126,7 +126,7 @@
   // The Cocoa controller of the GUI.
   base::scoped_nsobject<LoginHandlerSheet> sheet_controller_;
 
-  std::unique_ptr<ConstrainedWindowMac> constrained_window_;
+  scoped_ptr<ConstrainedWindowMac> constrained_window_;
 
   DISALLOW_COPY_AND_ASSIGN(LoginHandlerMac);
 };
diff --git a/chrome/browser/ui/cocoa/one_click_signin_dialog_controller.h b/chrome/browser/ui/cocoa/one_click_signin_dialog_controller.h
index b4f82d4..d56dfdd 100644
--- a/chrome/browser/ui/cocoa/one_click_signin_dialog_controller.h
+++ b/chrome/browser/ui/cocoa/one_click_signin_dialog_controller.h
@@ -8,6 +8,7 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/mac/scoped_nsobject.h"
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h"
 
@@ -41,7 +42,7 @@
  private:
   void PerformClose();
 
-  std::unique_ptr<ConstrainedWindowMac> constrained_window_;
+  scoped_ptr<ConstrainedWindowMac> constrained_window_;
   base::scoped_nsobject<OneClickSigninViewController> view_controller_;
 };
 
diff --git a/chrome/browser/ui/cocoa/one_click_signin_dialog_controller.mm b/chrome/browser/ui/cocoa/one_click_signin_dialog_controller.mm
index a8f9a84..f0156f2 100644
--- a/chrome/browser/ui/cocoa/one_click_signin_dialog_controller.mm
+++ b/chrome/browser/ui/cocoa/one_click_signin_dialog_controller.mm
@@ -30,15 +30,15 @@
 
   base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
       [[CustomConstrainedWindowSheet alloc] initWithCustomWindow:window]);
-  constrained_window_ =
-      CreateAndShowWebModalDialogMac(this, web_contents, sheet);
+  constrained_window_.reset(new ConstrainedWindowMac(
+      this, web_contents, sheet));
 }
 
 OneClickSigninDialogController::~OneClickSigninDialogController() {
 }
 
 void OneClickSigninDialogController::OnConstrainedWindowClosed(
-  ConstrainedWindowMac* window) {
+    ConstrainedWindowMac* window) {
   [view_controller_ viewWillClose];
   base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
 }
diff --git a/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_dialog_cocoa.h b/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_dialog_cocoa.h
index 192f6ce0..6f27470 100644
--- a/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_dialog_cocoa.h
+++ b/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_dialog_cocoa.h
@@ -13,6 +13,7 @@
 #include "base/compiler_specific.h"
 #include "base/mac/scoped_nsobject.h"
 #include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h"
 #include "chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller.h"
@@ -59,7 +60,7 @@
   base::scoped_nsobject<ProfileSigninConfirmationViewController> controller_;
 
   // The constrained window that contains the dialog view.
-  std::unique_ptr<ConstrainedWindowMac> window_;
+  scoped_ptr<ConstrainedWindowMac> window_;
 
   DISALLOW_COPY_AND_ASSIGN(ProfileSigninConfirmationDialogCocoa);
 };
diff --git a/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_dialog_cocoa.mm b/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_dialog_cocoa.mm
index e600717..a46b4eb 100644
--- a/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_dialog_cocoa.mm
+++ b/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_dialog_cocoa.mm
@@ -59,7 +59,7 @@
   [[window contentView] addSubview:[controller_ view]];
   base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
       [[CustomConstrainedWindowSheet alloc] initWithCustomWindow:window]);
-  window_ = CreateAndShowWebModalDialogMac(this, web_contents, sheet);
+  window_.reset(new ConstrainedWindowMac(this, web_contents, sheet));
 }
 
 ProfileSigninConfirmationDialogCocoa::~ProfileSigninConfirmationDialogCocoa() {
diff --git a/chrome/browser/ui/cocoa/profiles/user_manager_mac.h b/chrome/browser/ui/cocoa/profiles/user_manager_mac.h
index d8346b8..dd1c1c6c 100644
--- a/chrome/browser/ui/cocoa/profiles/user_manager_mac.h
+++ b/chrome/browser/ui/cocoa/profiles/user_manager_mac.h
@@ -9,6 +9,7 @@
 
 #include "base/mac/scoped_nsobject.h"
 #include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_window.h"
 
diff --git a/chrome/browser/ui/cocoa/profiles/user_manager_mac.mm b/chrome/browser/ui/cocoa/profiles/user_manager_mac.mm
index cdae282..48a02249 100644
--- a/chrome/browser/ui/cocoa/profiles/user_manager_mac.mm
+++ b/chrome/browser/ui/cocoa/profiles/user_manager_mac.mm
@@ -167,7 +167,7 @@
   std::string emailAddress_;
   content::WebContents* webContents_;
   scoped_ptr<ReauthDialogDelegate> webContentsDelegate_;
-  std::unique_ptr<ConstrainedWindowMac> constrained_window_;
+  scoped_ptr<ConstrainedWindowMac> constrained_window_;
   scoped_ptr<content::WebContents> reauthWebContents_;
 }
 - (id)initWithProfile:(Profile*)profile
@@ -203,9 +203,9 @@
     base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
        [[CustomConstrainedWindowSheet alloc]
            initWithCustomWindow:[self window]]);
-    constrained_window_ =
-        CreateAndShowWebModalDialogMac(
-            webContentsDelegate_.get(), webContents_, sheet);
+    constrained_window_.reset(
+       new ConstrainedWindowMac(
+          webContentsDelegate_.get(), webContents_, sheet));
 
     // The close button needs to call CloseWebContentsModalDialog() on the
     // constrained window isntead of just [window close] so grab a reference to
diff --git a/chrome/browser/ui/cocoa/single_web_contents_dialog_manager_cocoa.mm b/chrome/browser/ui/cocoa/single_web_contents_dialog_manager_cocoa.mm
index 1cbaec8..6b1d507 100644
--- a/chrome/browser/ui/cocoa/single_web_contents_dialog_manager_cocoa.mm
+++ b/chrome/browser/ui/cocoa/single_web_contents_dialog_manager_cocoa.mm
@@ -58,12 +58,8 @@
   [[ConstrainedWindowSheetController controllerForSheet:sheet_]
       closeSheet:sheet_];
   client_->set_manager(nullptr);
-
-  bool dialog_was_open = client_->DialogWasShown();
   client_->OnDialogClosing();      // |client_| might delete itself here.
-
-  if (dialog_was_open)
-    delegate_->WillClose(dialog());  // Deletes |this|.
+  delegate_->WillClose(dialog());  // Deletes |this|.
 }
 
 void SingleWebContentsDialogManagerCocoa::Focus() {
diff --git a/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.h b/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.h
index 4e3b307b..f1fe2e3 100644
--- a/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.h
+++ b/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.h
@@ -35,7 +35,7 @@
   // A C++ object to bridge SSLClientAuthObserver notifications to us.
   scoped_ptr<SSLClientAuthObserverCocoaBridge> observer_;
   base::scoped_nsobject<SFChooseIdentityPanel> panel_;
-  std::unique_ptr<ConstrainedWindowMac> constrainedWindow_;
+  scoped_ptr<ConstrainedWindowMac> constrainedWindow_;
   base::scoped_nsobject<NSWindow> overlayWindow_;
   BOOL closePending_;
   // A copy of the sheet's frame used to restore on show.
diff --git a/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.mm b/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.mm
index 4a06708..8c7d66d 100644
--- a/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.mm
+++ b/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.mm
@@ -179,8 +179,8 @@
     CFRelease(sslPolicy);
   }
 
-  constrainedWindow_ =
-      CreateAndShowWebModalDialogMac(observer_.get(), webContents, self);
+  constrainedWindow_.reset(
+      new ConstrainedWindowMac(observer_.get(), webContents, self));
   observer_->StartObserving();
 }
 
@@ -260,10 +260,6 @@
   // NOOP
 }
 
-- (void)resizeWithNewSize:(NSSize)size {
-  // NOOP
-}
-
 - (NSWindow*)sheetWindow {
   return panel_;
 }
diff --git a/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.h b/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.h
index c7e32951..1eed74f 100644
--- a/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.h
+++ b/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.h
@@ -48,7 +48,7 @@
 
   bool closing_;
 
-  std::unique_ptr<ConstrainedWindowMac> window_;
+  scoped_ptr<ConstrainedWindowMac> window_;
   scoped_ptr<TabModalConfirmDialogDelegate> delegate_;
   base::scoped_nsobject<ConstrainedWindowAlert> alert_;
   base::scoped_nsobject<TabModalConfirmDialogMacBridge> bridge_;
diff --git a/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.mm b/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.mm
index e0e7f547..6935ce1 100644
--- a/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.mm
+++ b/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.mm
@@ -94,7 +94,7 @@
   base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
       [[CustomConstrainedWindowSheet alloc]
           initWithCustomWindow:[alert_ window]]);
-  window_ = CreateAndShowWebModalDialogMac(this, web_contents, sheet);
+  window_.reset(new ConstrainedWindowMac(this, web_contents, sheet));
   delegate_->set_close_delegate(this);
 }
 
diff --git a/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac.mm b/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac.mm
index 31f057fa..1eefbd15 100644
--- a/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac.mm
+++ b/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac.mm
@@ -96,10 +96,6 @@
   [customWindow_ setFrameOrigin:origin];
 }
 
-- (void)resizeWithNewSize:(NSSize)size {
-  // NOOP
-}
-
 - (NSWindow*)sheetWindow {
   return customWindow_;
 }
diff --git a/chrome/browser/ui/input_method/input_method_engine.cc b/chrome/browser/ui/input_method/input_method_engine.cc
index 6d5a1595..11d44282c 100644
--- a/chrome/browser/ui/input_method/input_method_engine.cc
+++ b/chrome/browser/ui/input_method/input_method_engine.cc
@@ -84,6 +84,18 @@
   return ime_window->GetFrameId();
 }
 
+void InputMethodEngine::ShowImeWindow(int window_id) {
+  ui::ImeWindow* ime_window = FindWindowById(window_id);
+  if (ime_window)
+    ime_window->Show();
+}
+
+void InputMethodEngine::HideImeWindow(int window_id) {
+  ui::ImeWindow* ime_window = FindWindowById(window_id);
+  if (ime_window)
+    ime_window->Hide();
+}
+
 void InputMethodEngine::CloseImeWindows() {
   if (follow_cursor_window_)
     follow_cursor_window_->Close();
@@ -166,4 +178,16 @@
   }
 }
 
+ui::ImeWindow* InputMethodEngine::FindWindowById(int window_id) const {
+  if (follow_cursor_window_ &&
+      follow_cursor_window_->GetFrameId() == window_id) {
+    return follow_cursor_window_;
+  }
+  for (auto ime_window : normal_windows_) {
+    if (ime_window->GetFrameId() == window_id)
+      return ime_window;
+  }
+  return nullptr;
+}
+
 }  // namespace input_method
diff --git a/chrome/browser/ui/input_method/input_method_engine.h b/chrome/browser/ui/input_method/input_method_engine.h
index 14e5ac5e..9710ced 100644
--- a/chrome/browser/ui/input_method/input_method_engine.h
+++ b/chrome/browser/ui/input_method/input_method_engine.h
@@ -39,7 +39,8 @@
                       ui::ImeWindow::Mode mode,
                       const gfx::Rect& bounds,
                       std::string* error);
-
+  void ShowImeWindow(int window_id);
+  void HideImeWindow(int window_id);
   void CloseImeWindows();
 
  private:
@@ -57,6 +58,8 @@
   // ui::ImeWindowObserver:
   void OnWindowDestroyed(ui::ImeWindow* ime_window) override;
 
+  ui::ImeWindow* FindWindowById(int window_id) const;
+
   // Holds the IME window instances for properly closing in the destructor.
   // The follow-cursor window is singleton.
   // The normal windows cannot exceed the max count.
diff --git a/chrome/browser/ui/views/bar_control_button.cc b/chrome/browser/ui/views/bar_control_button.cc
index 9d472bf1..eecd5186 100644
--- a/chrome/browser/ui/views/bar_control_button.cc
+++ b/chrome/browser/ui/views/bar_control_button.cc
@@ -23,6 +23,8 @@
       ink_drop_delegate_(new views::ButtonInkDropDelegate(this, this)) {
   set_ink_drop_delegate(ink_drop_delegate_.get());
   set_has_ink_drop_action_on_click(true);
+  SetImageAlignment(views::ImageButton::ALIGN_CENTER,
+                    views::ImageButton::ALIGN_MIDDLE);
 }
 
 BarControlButton::~BarControlButton() {}
@@ -33,11 +35,11 @@
   id_ = id;
   get_text_color_callback_ = get_text_color_callback;
 
-  SetBorder(views::Border::CreateEmptyBorder(
-      kButtonExtraTouchSize, kButtonExtraTouchSize, kButtonExtraTouchSize,
-      kButtonExtraTouchSize));
-  SetImageAlignment(views::ImageButton::ALIGN_CENTER,
-                    views::ImageButton::ALIGN_MIDDLE);
+  if (!border()) {
+    SetBorder(views::Border::CreateEmptyBorder(
+        kButtonExtraTouchSize, kButtonExtraTouchSize, kButtonExtraTouchSize,
+        kButtonExtraTouchSize));
+  }
 }
 
 void BarControlButton::OnThemeChanged() {
diff --git a/chrome/browser/ui/views/download/download_item_view_md.cc b/chrome/browser/ui/views/download/download_item_view_md.cc
index 359bf407..ef6837cb 100644
--- a/chrome/browser/ui/views/download/download_item_view_md.cc
+++ b/chrome/browser/ui/views/download/download_item_view_md.cc
@@ -57,6 +57,7 @@
 #include "ui/gfx/text_elider.h"
 #include "ui/gfx/text_utils.h"
 #include "ui/gfx/vector_icons_public.h"
+#include "ui/views/animation/ink_drop_delegate.h"
 #include "ui/views/border.h"
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/controls/button/label_button.h"
@@ -92,7 +93,7 @@
 
 // Padding before the icon and at end of the item.
 const int kStartPadding = 12;
-const int kEndPadding = 19;
+const int kEndPadding = 6;
 
 // Horizontal padding between progress indicator and filename/status text.
 const int kProgressTextPadding = 8;
@@ -101,7 +102,10 @@
 // download.
 const int kButtonPadding = 5;
 
-// The space on the left and right side of the dangerous download label.
+// The touchable space around the dropdown button's icon.
+const int kDropdownBorderWidth = 10;
+
+// The space on the right side of the dangerous download label.
 const int kLabelPadding = 8;
 
 // Height/width of the warning icon, also in dp.
@@ -167,6 +171,9 @@
   download()->AddObserver(this);
   set_context_menu_controller(this);
 
+  dropdown_button_->SetBorder(
+      views::Border::CreateEmptyBorder(gfx::Insets(kDropdownBorderWidth)));
+  dropdown_button_->set_ink_drop_size(gfx::Size(32, 32));
   AddChildView(dropdown_button_);
 
   LoadIcon();
@@ -317,53 +324,55 @@
   UpdateColorsFromTheme();
 
   if (IsShowingWarningDialog()) {
-    int x = kStartPadding + kWarningIconSize + kStartPadding;
-    int y = (height() - dangerous_download_label_->height()) / 2;
-    dangerous_download_label_->SetBounds(x, y,
-                                         dangerous_download_label_->width(),
-                                         dangerous_download_label_->height());
+    gfx::Point child_origin(
+        kStartPadding + kWarningIconSize + kStartPadding,
+        (height() - dangerous_download_label_->height()) / 2);
+    dangerous_download_label_->SetPosition(child_origin);
+
+    child_origin.Offset(dangerous_download_label_->width() + kLabelPadding, 0);
     gfx::Size button_size = GetButtonSize();
-    x += dangerous_download_label_->width() + kLabelPadding;
-    y = (height() - button_size.height()) / 2;
+    child_origin.set_y((height() - button_size.height()) / 2);
     if (save_button_) {
-      save_button_->SetBounds(x, y, button_size.width(), button_size.height());
-      x += button_size.width() + kButtonPadding;
+      save_button_->SetBoundsRect(gfx::Rect(child_origin, button_size));
+      child_origin.Offset(button_size.width() + kButtonPadding, 0);
     }
-    discard_button_->SetBounds(x, y, button_size.width(), button_size.height());
+    discard_button_->SetBoundsRect(gfx::Rect(child_origin, button_size));
+    DCHECK_EQ(GetPreferredSize().width(),
+              discard_button_->bounds().right() + kEndPadding);
   } else {
     dropdown_button_->SizeToPreferredSize();
     dropdown_button_->SetPosition(
-        gfx::Point(width() - dropdown_button_->width(),
+        gfx::Point(width() - dropdown_button_->width() - kEndPadding,
                    (height() - dropdown_button_->height()) / 2));
   }
 }
 
 gfx::Size DownloadItemViewMd::GetPreferredSize() const {
-  int width, height;
-
-  // First, we set the height to the height of two rows or text plus margins.
-  height = std::max(kDefaultHeight,
-                    2 * kMinimumVerticalPadding + font_list_.GetBaseline() +
-                        kVerticalTextPadding + status_font_list_.GetHeight());
+  int width = 0;
+  // We set the height to the height of two rows or text plus margins.
+  int child_height = font_list_.GetBaseline() + kVerticalTextPadding +
+                     status_font_list_.GetHeight();
 
   if (IsShowingWarningDialog()) {
-    width = kStartPadding + kWarningIconSize + kLabelPadding +
+    // Width.
+    width = kStartPadding + kWarningIconSize + kStartPadding +
             dangerous_download_label_->width() + kLabelPadding;
     gfx::Size button_size = GetButtonSize();
-    // Make sure the button fits.
-    height = std::max<int>(height,
-                           2 * kMinimumVerticalPadding + button_size.height());
-    // Then we make sure the warning icon fits.
-    height = std::max<int>(
-        height, 2 * kMinimumVerticalPadding + kWarningIconSize);
     if (save_button_)
       width += button_size.width() + kButtonPadding;
     width += button_size.width() + kEndPadding;
+
+    // Height: make sure the button fits and the warning icon fits.
+    child_height =
+        std::max({child_height, button_size.height(), kWarningIconSize});
   } else {
     width = kStartPadding + DownloadShelf::kProgressIndicatorSize +
-            kProgressTextPadding + kTextWidth + kEndPadding;
+            kProgressTextPadding + kTextWidth +
+            dropdown_button_->GetPreferredSize().width() + kEndPadding;
   }
-  return gfx::Size(width, height);
+
+  return gfx::Size(width, std::max(kDefaultHeight,
+                                   2 * kMinimumVerticalPadding + child_height));
 }
 
 // Handle a mouse click and open the context menu if the mouse is
@@ -815,6 +824,9 @@
       new_state == PUSHED ? gfx::VectorIconId::FIND_NEXT
                           : gfx::VectorIconId::FIND_PREV,
       base::Bind(&DownloadItemViewMd::GetTextColor, base::Unretained(this)));
+  dropdown_button_->ink_drop_delegate()->OnAction(
+      new_state == PUSHED ? views::InkDropState::ACTIVATED
+                          : views::InkDropState::DEACTIVATED);
   dropdown_button_->OnThemeChanged();
   dropdown_state_ = new_state;
   SchedulePaint();
@@ -1010,7 +1022,7 @@
     prev_text = current_text;
   }
 
-  dangerous_download_label_->SetBounds(0, 0, size.width(), size.height());
+  dangerous_download_label_->SetSize(size);
   dangerous_download_label_sized_ = true;
 }
 
diff --git a/chrome/browser/ui/views/location_bar/content_setting_image_view.cc b/chrome/browser/ui/views/location_bar/content_setting_image_view.cc
index e88ab5c..a3b7640c 100644
--- a/chrome/browser/ui/views/location_bar/content_setting_image_view.cc
+++ b/chrome/browser/ui/views/location_bar/content_setting_image_view.cc
@@ -259,9 +259,12 @@
     views::Widget* bubble_widget =
         parent_->delegate()->CreateViewsBubble(bubble_view_);
     bubble_widget->AddObserver(this);
-    // This is triggered by an input event, the icon will be in an active state
-    // so the bubble doesn't need an arrow.
-    if (ui::MaterialDesignController::IsModeMaterial())
+    // This is triggered by an input event. If the user clicks the icon while
+    // it's not animating, the icon will be placed in an active state, so the
+    // bubble doesn't need an arrow. If the user clicks during an animation,
+    // the animation simply pauses and no other visible state change occurs, so
+    // show the arrow in this case.
+    if (ui::MaterialDesignController::IsModeMaterial() && !pause_animation_)
       bubble_view_->SetArrowPaintType(views::BubbleBorder::PAINT_TRANSPARENT);
     bubble_widget->Show();
   }
diff --git a/chrome/browser/ui/webui/constrained_web_dialog_delegate_base.cc b/chrome/browser/ui/webui/constrained_web_dialog_delegate_base.cc
index db4c547..fd60a4b 100644
--- a/chrome/browser/ui/webui/constrained_web_dialog_delegate_base.cc
+++ b/chrome/browser/ui/webui/constrained_web_dialog_delegate_base.cc
@@ -113,8 +113,3 @@
   NOTREACHED();
   return gfx::Size();
 }
-
-void ConstrainedWebDialogDelegateBase::ResizeToGivenSize(
-    const gfx::Size size) {
-  NOTREACHED();
-}
diff --git a/chrome/browser/ui/webui/constrained_web_dialog_delegate_base.h b/chrome/browser/ui/webui/constrained_web_dialog_delegate_base.h
index a43814a..fee4931 100644
--- a/chrome/browser/ui/webui/constrained_web_dialog_delegate_base.h
+++ b/chrome/browser/ui/webui/constrained_web_dialog_delegate_base.h
@@ -24,8 +24,6 @@
     : public ConstrainedWebDialogDelegate,
       public ui::WebDialogWebContentsDelegate {
  public:
-  // |browser_context| and |delegate| must outlive |this| instance, whereas
-  // |this| will take ownership of |tab_delegate|.
   ConstrainedWebDialogDelegateBase(content::BrowserContext* browser_context,
                                    ui::WebDialogDelegate* delegate,
                                    WebDialogWebContentsDelegate* tab_delegate);
@@ -49,9 +47,6 @@
       content::WebContents* source,
       const content::NativeWebKeyboardEvent& event) override;
 
-  // Resize the dialog to the given size.
-  virtual void ResizeToGivenSize(const gfx::Size size);
-
  private:
   scoped_ptr<ui::WebDialogDelegate> web_dialog_delegate_;
 
diff --git a/chrome/browser/ui/webui/constrained_web_dialog_ui.h b/chrome/browser/ui/webui/constrained_web_dialog_ui.h
index 39cc74b..4f7159e5 100644
--- a/chrome/browser/ui/webui/constrained_web_dialog_ui.h
+++ b/chrome/browser/ui/webui/constrained_web_dialog_ui.h
@@ -51,8 +51,6 @@
   // Returns the maximum size for the dialog.
   virtual gfx::Size GetMaximumSize() const = 0;
 
-  // Returns the preferred size for the dialog, or an empty size if
-  // the dialog has been closed.
   virtual gfx::Size GetPreferredSize() const = 0;
 
  protected:
diff --git a/chrome/browser/ui/webui/constrained_web_dialog_ui_browsertest.cc b/chrome/browser/ui/webui/constrained_web_dialog_ui_browsertest.cc
index f7d39e55..fbdf04f8 100644
--- a/chrome/browser/ui/webui/constrained_web_dialog_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/constrained_web_dialog_ui_browsertest.cc
@@ -26,6 +26,7 @@
 
 namespace {
 
+#if !defined(OS_MACOSX)
 static const char kTestDataURL[] = "data:text/html,<!doctype html>"
     "<body></body>"
     "<style>"
@@ -41,6 +42,7 @@
   return base::StringPrintf("window.document.body.style.width = %d + 'px';"
       "window.document.body.style.height = %d + 'px';", dimension, dimension);
 }
+#endif
 
 class ConstrainedWebDialogBrowserTestObserver
     : public content::WebContentsObserver {
@@ -145,6 +147,7 @@
   EXPECT_TRUE(observer.contents_destroyed());
 }
 
+#if !defined(OS_MACOSX)
 // Tests that dialog autoresizes based on web contents when autoresizing
 // is enabled.
 IN_PROC_BROWSER_TEST_F(ConstrainedWebDialogBrowserTest,
@@ -170,12 +173,6 @@
   gfx::Size min_size = gfx::Size(100, 100);
   gfx::Size max_size = gfx::Size(200, 200);
   gfx::Size initial_dialog_size;
-// OSX windows are initially created with non-empty dimensions. The
-// autoresizeable dialog's window dimensions are determined after initial
-// creation.
-#if defined(OS_MACOSX)
-  initial_dialog_size = gfx::Size(1, 1);
-#endif
   delegate->GetDialogSize(&initial_dialog_size);
 
   ConstrainedWebDialogDelegate* dialog_delegate =
@@ -189,6 +186,7 @@
   EXPECT_EQ(max_size, dialog_delegate->GetMaximumSize());
 
   // Check for initial sizing. Dialog was created as a 400x400 dialog.
+  EXPECT_EQ(gfx::Size(), web_contents->GetPreferredSize());
   ASSERT_EQ(initial_dialog_size, dialog_delegate->GetPreferredSize());
 
   observer.Wait();
@@ -252,6 +250,7 @@
   delegate->GetDialogSize(&initial_dialog_size);
 
   // Check for initial sizing. Dialog was created as a 400x400 dialog.
+  EXPECT_EQ(gfx::Size(), web_contents->GetPreferredSize());
   ASSERT_EQ(initial_dialog_size, dialog_delegate->GetPreferredSize());
 
   // Resize <body> to dimension smaller than dialog.
@@ -270,3 +269,4 @@
       initial_dialog_size,
       dialog_delegate)));
 }
+#endif  // !OS_MACOSX
diff --git a/chrome/browser/ui/webui/md_history_ui.cc b/chrome/browser/ui/webui/md_history_ui.cc
index e0f82545..d52d1e6 100644
--- a/chrome/browser/ui/webui/md_history_ui.cc
+++ b/chrome/browser/ui/webui/md_history_ui.cc
@@ -52,6 +52,8 @@
   bool allow_deleting_history =
       prefs->GetBoolean(prefs::kAllowDeletingBrowserHistory);
   source->AddBoolean("allowDeletingHistory", allow_deleting_history);
+  source->AddResourcePath("constants.html", IDR_MD_HISTORY_CONSTANTS_HTML);
+  source->AddResourcePath("constants.js", IDR_MD_HISTORY_CONSTANTS_JS);
   source->AddResourcePath("history_item.html",
                           IDR_MD_HISTORY_HISTORY_ITEM_HTML);
   source->AddResourcePath("history_item.js", IDR_MD_HISTORY_HISTORY_ITEM_JS);
diff --git a/chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl.cc b/chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl.cc
index ebf57fde..bf57e82 100644
--- a/chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl.cc
+++ b/chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl.cc
@@ -41,8 +41,12 @@
 using ui::WebDialogDelegate;
 
 namespace {
+#if defined(OS_MACOSX)
+const int kFixedHeight = 350;
+#else
 const int kMaxHeight = 2000;
 const int kMinHeight = 80;
+#endif
 const int kWidth = 340;
 }
 
@@ -110,10 +114,15 @@
 
 void MediaRouterDialogDelegate::GetDialogSize(gfx::Size* size) const {
   DCHECK(size);
+  // TODO(apacible): Remove after autoresizing is implemented for OSX.
+#if defined(OS_MACOSX)
+  *size = gfx::Size(kWidth, kFixedHeight);
+#else
   // GetDialogSize() is called when the browser window resizes. We may want to
   // update the maximum height of the dialog and scale the WebUI to the new
   // height. |size| is not set because the dialog is auto-resizeable.
   controller_->UpdateMaxDialogSize();
+#endif
 }
 
 }  // namespace
@@ -234,21 +243,29 @@
       Profile::FromBrowserContext(initiator()->GetBrowserContext());
   DCHECK(profile);
 
-  // |web_dialog_delegate|'s owner is |constrained_delegate|.
-  // |constrained_delegate| is owned by the parent |views::View|.
   WebDialogDelegate* web_dialog_delegate =
       new MediaRouterDialogDelegate(action_, weak_ptr_factory_.GetWeakPtr());
+  // |web_dialog_delegate|'s owner is |constrained_delegate|.
+  // |constrained_delegate| is owned by the parent |views::View|.
+  // TODO(apacible): Remove after autoresizing is implemented for OSX.
+#if defined(OS_MACOSX)
+  ConstrainedWebDialogDelegate* constrained_delegate =
+      ShowConstrainedWebDialog(profile, web_dialog_delegate, initiator());
+#else
+  // TODO(apacible): Adjust min and max sizes based on new WebUI design.
+  gfx::Size min_size = gfx::Size(kWidth, kMinHeight);
+  gfx::Size max_size = gfx::Size(kWidth, kMaxHeight);
 
   // |ShowConstrainedWebDialogWithAutoResize()| will end up creating
   // ConstrainedWebDialogDelegateViewViews containing a WebContents containing
   // the MediaRouterUI, using the provided |web_dialog_delegate|. Then, the
   // view is shown as a modal dialog constrained to the |initiator| WebContents.
-  // The dialog will resize between the given minimum and maximum size bounds
-  // based on the currently rendered contents.
+  // The dialog will resize between the |min_size| and |max_size| bounds based
+  // on the currently rendered contents.
   ConstrainedWebDialogDelegate* constrained_delegate =
       ShowConstrainedWebDialogWithAutoResize(
-          profile, web_dialog_delegate, initiator(),
-              gfx::Size(kWidth, kMinHeight), gfx::Size(kWidth, kMaxHeight));
+          profile, web_dialog_delegate, initiator(), min_size, max_size);
+#endif
 
   WebContents* media_router_dialog = constrained_delegate->GetWebContents();
   TRACE_EVENT_NESTABLE_ASYNC_INSTANT1("media_router", "UI", initiator(),
diff --git a/chrome/browser/ui/webui/settings/certificates_handler.cc b/chrome/browser/ui/webui/settings/certificates_handler.cc
new file mode 100644
index 0000000..66883412c
--- /dev/null
+++ b/chrome/browser/ui/webui/settings/certificates_handler.cc
@@ -0,0 +1,1146 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/settings/certificates_handler.h"
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <algorithm>
+#include <map>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/files/file_util.h"  // for FileAccessProvider
+#include "base/i18n/string_compare.h"
+#include "base/id_map.h"
+#include "base/macros.h"
+#include "base/memory/scoped_vector.h"
+#include "base/posix/safe_strerror.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "build/build_config.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/certificate_viewer.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/certificate_dialogs.h"
+#include "chrome/browser/ui/chrome_select_file_policy.h"
+#include "chrome/browser/ui/crypto_module_password_dialog_nss.h"
+#include "chrome/browser/ui/webui/certificate_viewer_webui.h"
+#include "chrome/grit/generated_resources.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/web_contents.h"
+#include "grit/components_strings.h"
+#include "net/base/crypto_module.h"
+#include "net/base/net_errors.h"
+#include "net/cert/x509_certificate.h"
+#include "net/der/input.h"
+#include "net/der/parser.h"
+#include "ui/base/l10n/l10n_util.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/policy/user_network_configuration_updater.h"
+#include "chrome/browser/chromeos/policy/user_network_configuration_updater_factory.h"
+#endif
+
+using base::UTF8ToUTF16;
+using content::BrowserThread;
+
+namespace {
+
+// Field names for communicating certificate info to JS.
+static const char kEmailField[] = "email";
+static const char kExtractableField[] = "extractable";
+static const char kKeyField[] = "id";
+static const char kNameField[] = "name";
+static const char kObjSignField[] = "objSign";
+static const char kPolicyField[] = "policy";
+static const char kReadonlyField[] = "readonly";
+static const char kSslField[] = "ssl";
+static const char kSubnodesField[] = "subnodes";
+static const char kUntrustedField[] = "untrusted";
+
+// Field names for communicating erros to JS.
+static const char kCertificateErrors[] = "certificateErrors";
+static const char kErrorDescription[] = "description";
+static const char kErrorField[] = "error";
+static const char kErrorTitle[] = "title";
+
+// Enumeration of different callers of SelectFile.  (Start counting at 1 so
+// if SelectFile is accidentally called with params=NULL it won't match any.)
+enum {
+  EXPORT_PERSONAL_FILE_SELECTED = 1,
+  IMPORT_PERSONAL_FILE_SELECTED,
+  IMPORT_SERVER_FILE_SELECTED,
+  IMPORT_CA_FILE_SELECTED,
+};
+
+std::string OrgNameToId(const std::string& org) {
+  return "org-" + org;
+}
+
+struct DictionaryIdComparator {
+  explicit DictionaryIdComparator(icu::Collator* collator)
+      : collator_(collator) {
+  }
+
+  bool operator()(const base::Value* a,
+                  const base::Value* b) const {
+    DCHECK(a->GetType() == base::Value::TYPE_DICTIONARY);
+    DCHECK(b->GetType() == base::Value::TYPE_DICTIONARY);
+    const base::DictionaryValue* a_dict =
+        reinterpret_cast<const base::DictionaryValue*>(a);
+    const base::DictionaryValue* b_dict =
+        reinterpret_cast<const base::DictionaryValue*>(b);
+    base::string16 a_str;
+    base::string16 b_str;
+    a_dict->GetString(kNameField, &a_str);
+    b_dict->GetString(kNameField, &b_str);
+    if (collator_ == NULL)
+      return a_str < b_str;
+    return base::i18n::CompareString16WithCollator(*collator_, a_str, b_str) ==
+           UCOL_LESS;
+  }
+
+  icu::Collator* collator_;
+};
+
+std::string NetErrorToString(int net_error) {
+  switch (net_error) {
+    // TODO(mattm): handle more cases.
+    case net::ERR_IMPORT_CA_CERT_NOT_CA:
+      return l10n_util::GetStringUTF8(IDS_CERT_MANAGER_ERROR_NOT_CA);
+    case net::ERR_IMPORT_CERT_ALREADY_EXISTS:
+      return l10n_util::GetStringUTF8(
+          IDS_CERT_MANAGER_ERROR_CERT_ALREADY_EXISTS);
+    default:
+      return l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR);
+  }
+}
+
+// Struct to bind the Equals member function to an object for use in find_if.
+struct CertEquals {
+  explicit CertEquals(const net::X509Certificate* cert) : cert_(cert) {}
+  bool operator()(const scoped_refptr<net::X509Certificate> cert) const {
+    return cert_->Equals(cert.get());
+  }
+  const net::X509Certificate* cert_;
+};
+
+// Determine whether a certificate was stored with web trust by a policy.
+bool IsPolicyInstalledWithWebTrust(
+    const net::CertificateList& web_trust_certs,
+    net::X509Certificate* cert) {
+  return std::find_if(web_trust_certs.begin(), web_trust_certs.end(),
+                      CertEquals(cert)) != web_trust_certs.end();
+}
+
+#if defined(OS_CHROMEOS)
+void ShowCertificateViewerModalDialog(content::WebContents* web_contents,
+                                      gfx::NativeWindow parent,
+                                      net::X509Certificate* cert) {
+  CertificateViewerModalDialog* dialog = new CertificateViewerModalDialog(cert);
+  dialog->Show(web_contents, parent);
+}
+#endif
+
+// Determine if |data| could be a PFX Protocol Data Unit.
+// This only does the minimum parsing necessary to distinguish a PFX file from a
+// DER encoded Certificate.
+//
+// From RFC 7292 section 4:
+//   PFX ::= SEQUENCE {
+//       version     INTEGER {v3(3)}(v3,...),
+//       authSafe    ContentInfo,
+//       macData     MacData OPTIONAL
+//   }
+// From RFC 5280 section 4.1:
+//   Certificate  ::=  SEQUENCE  {
+//       tbsCertificate       TBSCertificate,
+//       signatureAlgorithm   AlgorithmIdentifier,
+//       signatureValue       BIT STRING  }
+//
+//  Certificate must be DER encoded, while PFX may be BER encoded.
+//  Therefore PFX can be distingushed by checking if the file starts with an
+//  indefinite SEQUENCE, or a definite SEQUENCE { INTEGER,  ... }.
+bool CouldBePFX(const std::string& data) {
+  if (data.size() < 4)
+    return false;
+
+  // Indefinite length SEQUENCE.
+  if (data[0] == 0x30 && static_cast<uint8_t>(data[1]) == 0x80)
+    return true;
+
+  // If the SEQUENCE is definite length, it can be parsed through the version
+  // tag using DER parser, since INTEGER must be definite length, even in BER.
+  net::der::Parser parser((net::der::Input(&data)));
+  net::der::Parser sequence_parser;
+  if (!parser.ReadSequence(&sequence_parser))
+    return false;
+  if (!sequence_parser.SkipTag(net::der::kInteger))
+    return false;
+  return true;
+}
+
+}  // namespace
+
+namespace settings {
+
+///////////////////////////////////////////////////////////////////////////////
+//  CertIdMap
+
+class CertIdMap {
+ public:
+  CertIdMap() {}
+  ~CertIdMap() {}
+
+  std::string CertToId(net::X509Certificate* cert);
+  net::X509Certificate* IdToCert(const std::string& id);
+  net::X509Certificate* CallbackArgsToCert(const base::ListValue* args);
+
+ private:
+  typedef std::map<net::X509Certificate*, int32_t> CertMap;
+
+  // Creates an ID for cert and looks up the cert for an ID.
+  IDMap<net::X509Certificate>id_map_;
+
+  // Finds the ID for a cert.
+  CertMap cert_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(CertIdMap);
+};
+
+std::string CertIdMap::CertToId(net::X509Certificate* cert) {
+  CertMap::const_iterator iter = cert_map_.find(cert);
+  if (iter != cert_map_.end())
+    return base::IntToString(iter->second);
+
+  int32_t new_id = id_map_.Add(cert);
+  cert_map_[cert] = new_id;
+  return base::IntToString(new_id);
+}
+
+net::X509Certificate* CertIdMap::IdToCert(const std::string& id) {
+  int32_t cert_id = 0;
+  if (!base::StringToInt(id, &cert_id))
+    return NULL;
+
+  return id_map_.Lookup(cert_id);
+}
+
+net::X509Certificate* CertIdMap::CallbackArgsToCert(
+    const base::ListValue* args) {
+  std::string node_id;
+  if (!args->GetString(0, &node_id))
+    return NULL;
+
+  net::X509Certificate* cert = IdToCert(node_id);
+  if (!cert) {
+    NOTREACHED();
+    return NULL;
+  }
+
+  return cert;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//  FileAccessProvider
+
+// TODO(mattm): Move to some shared location?
+class FileAccessProvider
+    : public base::RefCountedThreadSafe<FileAccessProvider> {
+ public:
+  // The first parameter is 0 on success or errno on failure. The second
+  // parameter is read result.
+  typedef base::Callback<void(const int*, const std::string*)> ReadCallback;
+
+  // The first parameter is 0 on success or errno on failure. The second
+  // parameter is the number of bytes written on success.
+  typedef base::Callback<void(const int*, const int*)> WriteCallback;
+
+  base::CancelableTaskTracker::TaskId StartRead(
+      const base::FilePath& path,
+      const ReadCallback& callback,
+      base::CancelableTaskTracker* tracker);
+  base::CancelableTaskTracker::TaskId StartWrite(
+      const base::FilePath& path,
+      const std::string& data,
+      const WriteCallback& callback,
+      base::CancelableTaskTracker* tracker);
+
+ private:
+  friend class base::RefCountedThreadSafe<FileAccessProvider>;
+  virtual ~FileAccessProvider() {}
+
+  // Reads file at |path|. |saved_errno| is 0 on success or errno on failure.
+  // When success, |data| has file content.
+  void DoRead(const base::FilePath& path,
+              int* saved_errno,
+              std::string* data);
+  // Writes data to file at |path|. |saved_errno| is 0 on success or errno on
+  // failure. When success, |bytes_written| has number of bytes written.
+  void DoWrite(const base::FilePath& path,
+               const std::string& data,
+               int* saved_errno,
+               int* bytes_written);
+};
+
+base::CancelableTaskTracker::TaskId FileAccessProvider::StartRead(
+    const base::FilePath& path,
+    const ReadCallback& callback,
+    base::CancelableTaskTracker* tracker) {
+  // Owned by reply callback posted below.
+  int* saved_errno = new int(0);
+  std::string* data = new std::string();
+
+  // Post task to file thread to read file.
+  return tracker->PostTaskAndReply(
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE).get(),
+      FROM_HERE,
+      base::Bind(&FileAccessProvider::DoRead, this, path, saved_errno, data),
+      base::Bind(callback, base::Owned(saved_errno), base::Owned(data)));
+}
+
+base::CancelableTaskTracker::TaskId FileAccessProvider::StartWrite(
+    const base::FilePath& path,
+    const std::string& data,
+    const WriteCallback& callback,
+    base::CancelableTaskTracker* tracker) {
+  // Owned by reply callback posted below.
+  int* saved_errno = new int(0);
+  int* bytes_written = new int(0);
+
+  // Post task to file thread to write file.
+  return tracker->PostTaskAndReply(
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE).get(),
+      FROM_HERE,
+      base::Bind(&FileAccessProvider::DoWrite,
+                 this,
+                 path,
+                 data,
+                 saved_errno,
+                 bytes_written),
+      base::Bind(
+          callback, base::Owned(saved_errno), base::Owned(bytes_written)));
+}
+
+void FileAccessProvider::DoRead(const base::FilePath& path,
+                                int* saved_errno,
+                                std::string* data) {
+  bool success = base::ReadFileToString(path, data);
+  *saved_errno = success ? 0 : errno;
+}
+
+void FileAccessProvider::DoWrite(const base::FilePath& path,
+                                 const std::string& data,
+                                 int* saved_errno,
+                                 int* bytes_written) {
+  *bytes_written = base::WriteFile(path, data.data(), data.size());
+  *saved_errno = *bytes_written >= 0 ? 0 : errno;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//  CertificatesHandler
+
+CertificatesHandler::CertificatesHandler(
+    bool show_certs_in_modal_dialog)
+    : show_certs_in_modal_dialog_(show_certs_in_modal_dialog),
+      requested_certificate_manager_model_(false),
+      use_hardware_backed_(false),
+      file_access_provider_(new FileAccessProvider()),
+      cert_id_map_(new CertIdMap),
+      weak_ptr_factory_(this) {}
+
+CertificatesHandler::~CertificatesHandler() {
+}
+
+void CertificatesHandler::RegisterMessages() {
+  web_ui()->RegisterMessageCallback(
+      "viewCertificate",
+      base::Bind(&CertificatesHandler::HandleViewCertificate,
+                 base::Unretained(this)));
+
+  web_ui()->RegisterMessageCallback(
+      "getCaCertificateTrust",
+      base::Bind(&CertificatesHandler::HandleGetCATrust,
+                 base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "editCaCertificateTrust",
+      base::Bind(&CertificatesHandler::HandleEditCATrust,
+                 base::Unretained(this)));
+
+  web_ui()->RegisterMessageCallback(
+      "cancelImportExportCertificate",
+      base::Bind(&CertificatesHandler::HandleCancelImportExportProcess,
+                 base::Unretained(this)));
+
+  web_ui()->RegisterMessageCallback(
+      "exportPersonalCertificate",
+      base::Bind(&CertificatesHandler::HandleExportPersonal,
+                 base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "exportPersonalCertificatePasswordSelected",
+      base::Bind(&CertificatesHandler::HandleExportPersonalPasswordSelected,
+                 base::Unretained(this)));
+
+  web_ui()->RegisterMessageCallback(
+      "importPersonalCertificate",
+      base::Bind(&CertificatesHandler::HandleImportPersonal,
+                 base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "importPersonalCertificatePasswordSelected",
+      base::Bind(&CertificatesHandler::HandleImportPersonalPasswordSelected,
+                 base::Unretained(this)));
+
+  web_ui()->RegisterMessageCallback(
+      "importCaCertificate",
+      base::Bind(&CertificatesHandler::HandleImportCA,
+                 base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "importCaCertificateTrustSelected",
+      base::Bind(&CertificatesHandler::HandleImportCATrustSelected,
+                 base::Unretained(this)));
+
+  web_ui()->RegisterMessageCallback(
+      "importServerCertificate",
+      base::Bind(&CertificatesHandler::HandleImportServer,
+                 base::Unretained(this)));
+
+  web_ui()->RegisterMessageCallback(
+      "exportCertificate",
+      base::Bind(&CertificatesHandler::HandleExportCertificate,
+                 base::Unretained(this)));
+
+  web_ui()->RegisterMessageCallback(
+      "deleteCertificate",
+      base::Bind(&CertificatesHandler::HandleDeleteCertificate,
+                 base::Unretained(this)));
+
+  web_ui()->RegisterMessageCallback(
+      "refreshCertificates",
+      base::Bind(&CertificatesHandler::HandleRefreshCertificates,
+                 base::Unretained(this)));
+}
+
+void CertificatesHandler::CertificatesRefreshed() {
+  net::CertificateList web_trusted_certs;
+#if defined(OS_CHROMEOS)
+  policy::UserNetworkConfigurationUpdater* service =
+      policy::UserNetworkConfigurationUpdaterFactory::GetForProfile(
+          Profile::FromWebUI(web_ui()));
+  if (service)
+    service->GetWebTrustedCertificates(&web_trusted_certs);
+#endif
+  PopulateTree("personalCerts", net::USER_CERT, web_trusted_certs);
+  PopulateTree("serverCerts", net::SERVER_CERT, web_trusted_certs);
+  PopulateTree("caCerts", net::CA_CERT, web_trusted_certs);
+  PopulateTree("otherCerts", net::OTHER_CERT, web_trusted_certs);
+}
+
+void CertificatesHandler::FileSelected(const base::FilePath& path,
+                                             int index,
+                                             void* params) {
+  switch (reinterpret_cast<intptr_t>(params)) {
+    case EXPORT_PERSONAL_FILE_SELECTED:
+      ExportPersonalFileSelected(path);
+      break;
+    case IMPORT_PERSONAL_FILE_SELECTED:
+      ImportPersonalFileSelected(path);
+      break;
+    case IMPORT_SERVER_FILE_SELECTED:
+      ImportServerFileSelected(path);
+      break;
+    case IMPORT_CA_FILE_SELECTED:
+      ImportCAFileSelected(path);
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
+void CertificatesHandler::FileSelectionCanceled(void* params) {
+  switch (reinterpret_cast<intptr_t>(params)) {
+    case EXPORT_PERSONAL_FILE_SELECTED:
+    case IMPORT_PERSONAL_FILE_SELECTED:
+    case IMPORT_SERVER_FILE_SELECTED:
+    case IMPORT_CA_FILE_SELECTED:
+      ImportExportCleanup();
+      RejectCallback(*base::Value::CreateNullValue());
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
+void CertificatesHandler::HandleViewCertificate(const base::ListValue* args) {
+  net::X509Certificate* cert = cert_id_map_->CallbackArgsToCert(args);
+  if (!cert)
+    return;
+#if defined(OS_CHROMEOS)
+  if (show_certs_in_modal_dialog_) {
+    ShowCertificateViewerModalDialog(web_ui()->GetWebContents(),
+                                     GetParentWindow(),
+                                     cert);
+    return;
+  }
+#endif
+  ShowCertificateViewer(web_ui()->GetWebContents(), GetParentWindow(), cert);
+}
+
+void CertificatesHandler::AssignWebUICallbackId(const base::ListValue* args) {
+  CHECK_LE(1U, args->GetSize());
+  CHECK(webui_callback_id_.empty());
+  CHECK(args->GetString(0, &webui_callback_id_));
+}
+
+void CertificatesHandler::HandleGetCATrust(const base::ListValue* args) {
+  CHECK_EQ(2U, args->GetSize());
+  AssignWebUICallbackId(args);
+  std::string node_id;
+  CHECK(args->GetString(1, &node_id));
+
+  net::X509Certificate* cert = cert_id_map_->IdToCert(node_id);
+  CHECK(cert);
+
+  net::NSSCertDatabase::TrustBits trust_bits =
+      certificate_manager_model_->cert_db()->GetCertTrust(cert, net::CA_CERT);
+  scoped_ptr<base::DictionaryValue> ca_trust_info(new base::DictionaryValue);
+  ca_trust_info->SetBoolean(
+      kSslField,
+      static_cast<bool>(trust_bits & net::NSSCertDatabase::TRUSTED_SSL));
+  ca_trust_info->SetBoolean(
+      kEmailField,
+      static_cast<bool>(trust_bits & net::NSSCertDatabase::TRUSTED_EMAIL));
+  ca_trust_info->SetBoolean(
+      kObjSignField,
+      static_cast<bool>(trust_bits & net::NSSCertDatabase::TRUSTED_OBJ_SIGN));
+  ResolveCallback(*ca_trust_info);
+}
+
+void CertificatesHandler::HandleEditCATrust(const base::ListValue* args) {
+  CHECK_EQ(5U, args->GetSize());
+  AssignWebUICallbackId(args);
+  std::string node_id;
+  CHECK(args->GetString(1, &node_id));
+
+  net::X509Certificate* cert = cert_id_map_->IdToCert(node_id);
+  CHECK(cert);
+
+  bool trust_ssl = false;
+  bool trust_email = false;
+  bool trust_obj_sign = false;
+  CHECK(args->GetBoolean(2, &trust_ssl));
+  CHECK(args->GetBoolean(3, &trust_email));
+  CHECK(args->GetBoolean(4, &trust_obj_sign));
+
+  bool result = certificate_manager_model_->SetCertTrust(
+      cert,
+      net::CA_CERT,
+      trust_ssl * net::NSSCertDatabase::TRUSTED_SSL +
+          trust_email * net::NSSCertDatabase::TRUSTED_EMAIL +
+          trust_obj_sign * net::NSSCertDatabase::TRUSTED_OBJ_SIGN);
+  if (!result) {
+    // TODO(mattm): better error messages?
+    RejectCallbackWithError(
+        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SET_TRUST_ERROR_TITLE),
+        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
+  } else {
+    ResolveCallback(*base::Value::CreateNullValue());
+  }
+}
+
+void CertificatesHandler::HandleExportPersonal(const base::ListValue* args) {
+  CHECK_EQ(2U, args->GetSize());
+  AssignWebUICallbackId(args);
+  std::string node_id;
+  CHECK(args->GetString(1, &node_id));
+
+  net::X509Certificate* cert = cert_id_map_->IdToCert(node_id);
+  CHECK(cert);
+  selected_cert_list_.push_back(cert);
+
+  ui::SelectFileDialog::FileTypeInfo file_type_info;
+  file_type_info.extensions.resize(1);
+  file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("p12"));
+  file_type_info.extension_description_overrides.push_back(
+      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PKCS12_FILES));
+  file_type_info.include_all_files = true;
+  select_file_dialog_ = ui::SelectFileDialog::Create(
+      this, new ChromeSelectFilePolicy(web_ui()->GetWebContents()));
+  select_file_dialog_->SelectFile(
+      ui::SelectFileDialog::SELECT_SAVEAS_FILE, base::string16(),
+      base::FilePath(), &file_type_info, 1, FILE_PATH_LITERAL("p12"),
+      GetParentWindow(),
+      reinterpret_cast<void*>(EXPORT_PERSONAL_FILE_SELECTED));
+}
+
+void CertificatesHandler::ExportPersonalFileSelected(
+    const base::FilePath& path) {
+  file_path_ = path;
+  ResolveCallback(*base::Value::CreateNullValue());
+}
+
+void CertificatesHandler::HandleExportPersonalPasswordSelected(
+    const base::ListValue* args) {
+  CHECK_EQ(2U, args->GetSize());
+  AssignWebUICallbackId(args);
+  CHECK(args->GetString(1, &password_));
+
+  // Currently, we don't support exporting more than one at a time.  If we do,
+  // this would need to either change this to use UnlockSlotsIfNecessary or
+  // change UnlockCertSlotIfNecessary to take a CertificateList.
+  DCHECK_EQ(selected_cert_list_.size(), 1U);
+
+  // TODO(mattm): do something smarter about non-extractable keys
+  chrome::UnlockCertSlotIfNecessary(
+      selected_cert_list_[0].get(),
+      chrome::kCryptoModulePasswordCertExport,
+      net::HostPortPair(),  // unused.
+      GetParentWindow(),
+      base::Bind(&CertificatesHandler::ExportPersonalSlotsUnlocked,
+                 base::Unretained(this)));
+}
+
+void CertificatesHandler::ExportPersonalSlotsUnlocked() {
+  std::string output;
+  int num_exported = certificate_manager_model_->cert_db()->ExportToPKCS12(
+      selected_cert_list_,
+      password_,
+      &output);
+  if (!num_exported) {
+    RejectCallbackWithError(
+        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_EXPORT_ERROR_TITLE),
+        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
+    ImportExportCleanup();
+    return;
+  }
+  file_access_provider_->StartWrite(
+      file_path_,
+      output,
+      base::Bind(&CertificatesHandler::ExportPersonalFileWritten,
+                 base::Unretained(this)),
+      &tracker_);
+}
+
+void CertificatesHandler::ExportPersonalFileWritten(
+    const int* write_errno, const int* bytes_written) {
+  ImportExportCleanup();
+  if (*write_errno) {
+    RejectCallbackWithError(
+        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_EXPORT_ERROR_TITLE),
+        l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_WRITE_ERROR_FORMAT,
+                                  UTF8ToUTF16(
+                                      base::safe_strerror(*write_errno))));
+  } else {
+    ResolveCallback(*base::Value::CreateNullValue());
+  }
+}
+
+void CertificatesHandler::HandleImportPersonal(const base::ListValue* args) {
+  CHECK_EQ(2U, args->GetSize());
+  AssignWebUICallbackId(args);
+  CHECK(args->GetBoolean(1, &use_hardware_backed_));
+
+  ui::SelectFileDialog::FileTypeInfo file_type_info;
+  file_type_info.extensions.resize(1);
+  file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("p12"));
+  file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("pfx"));
+  file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("crt"));
+  file_type_info.extension_description_overrides.push_back(
+      l10n_util::GetStringUTF16(IDS_CERT_USAGE_SSL_CLIENT));
+  file_type_info.include_all_files = true;
+  select_file_dialog_ = ui::SelectFileDialog::Create(
+      this, new ChromeSelectFilePolicy(web_ui()->GetWebContents()));
+  select_file_dialog_->SelectFile(
+      ui::SelectFileDialog::SELECT_OPEN_FILE, base::string16(),
+      base::FilePath(), &file_type_info, 1, FILE_PATH_LITERAL("p12"),
+      GetParentWindow(),
+      reinterpret_cast<void*>(IMPORT_PERSONAL_FILE_SELECTED));
+}
+
+void CertificatesHandler::ImportPersonalFileSelected(
+    const base::FilePath& path) {
+  file_access_provider_->StartRead(
+      path, base::Bind(&CertificatesHandler::ImportPersonalFileRead,
+                       base::Unretained(this)),
+      &tracker_);
+}
+
+void CertificatesHandler::ImportPersonalFileRead(
+    const int* read_errno, const std::string* data) {
+  if (*read_errno) {
+    ImportExportCleanup();
+    RejectCallbackWithError(
+        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_IMPORT_ERROR_TITLE),
+        l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_READ_ERROR_FORMAT,
+                                  UTF8ToUTF16(
+                                      base::safe_strerror(*read_errno))));
+    return;
+  }
+
+  file_data_ = *data;
+
+  if (CouldBePFX(file_data_)) {
+    ResolveCallback(base::FundamentalValue(true));
+    return;
+  }
+
+  // Non .p12/.pfx files are assumed to be single/chain certificates without
+  // private key data. The default extension according to spec is '.crt',
+  // however other extensions are also used in some places to represent these
+  // certificates.
+  int result = certificate_manager_model_->ImportUserCert(file_data_);
+  ImportExportCleanup();
+  int string_id;
+  switch (result) {
+    case net::OK:
+      ResolveCallback(base::FundamentalValue(false));
+      return;
+    case net::ERR_NO_PRIVATE_KEY_FOR_CERT:
+      string_id = IDS_CERT_MANAGER_IMPORT_MISSING_KEY;
+      break;
+    case net::ERR_CERT_INVALID:
+      string_id = IDS_CERT_MANAGER_IMPORT_INVALID_FILE;
+      break;
+    default:
+      string_id = IDS_CERT_MANAGER_UNKNOWN_ERROR;
+      break;
+  }
+  RejectCallbackWithError(
+      l10n_util::GetStringUTF8(IDS_CERT_MANAGER_IMPORT_ERROR_TITLE),
+      l10n_util::GetStringUTF8(string_id));
+}
+
+void CertificatesHandler::HandleImportPersonalPasswordSelected(
+    const base::ListValue* args) {
+  CHECK_EQ(2U, args->GetSize());
+  AssignWebUICallbackId(args);
+  CHECK(args->GetString(1, &password_));
+
+  if (use_hardware_backed_) {
+    module_ = certificate_manager_model_->cert_db()->GetPrivateModule();
+  } else {
+    module_ = certificate_manager_model_->cert_db()->GetPublicModule();
+  }
+
+  net::CryptoModuleList modules;
+  modules.push_back(module_);
+  chrome::UnlockSlotsIfNecessary(
+      modules,
+      chrome::kCryptoModulePasswordCertImport,
+      net::HostPortPair(),  // unused.
+      GetParentWindow(),
+      base::Bind(&CertificatesHandler::ImportPersonalSlotUnlocked,
+                 base::Unretained(this)));
+}
+
+void CertificatesHandler::ImportPersonalSlotUnlocked() {
+  // Determine if the private key should be unextractable after the import.
+  // We do this by checking the value of |use_hardware_backed_| which is set
+  // to true if importing into a hardware module. Currently, this only happens
+  // for Chrome OS when the "Import and Bind" option is chosen.
+  bool is_extractable = !use_hardware_backed_;
+  int result = certificate_manager_model_->ImportFromPKCS12(
+      module_.get(), file_data_, password_, is_extractable);
+  ImportExportCleanup();
+  int string_id;
+  switch (result) {
+    case net::OK:
+      ResolveCallback(*base::Value::CreateNullValue());
+      return;
+    case net::ERR_PKCS12_IMPORT_BAD_PASSWORD:
+      // TODO(mattm): if the error was a bad password, we should reshow the
+      // password dialog after the user dismisses the error dialog.
+      string_id = IDS_CERT_MANAGER_BAD_PASSWORD;
+      break;
+    case net::ERR_PKCS12_IMPORT_INVALID_MAC:
+      string_id = IDS_CERT_MANAGER_IMPORT_INVALID_MAC;
+      break;
+    case net::ERR_PKCS12_IMPORT_INVALID_FILE:
+      string_id = IDS_CERT_MANAGER_IMPORT_INVALID_FILE;
+      break;
+    case net::ERR_PKCS12_IMPORT_UNSUPPORTED:
+      string_id = IDS_CERT_MANAGER_IMPORT_UNSUPPORTED;
+      break;
+    default:
+      string_id = IDS_CERT_MANAGER_UNKNOWN_ERROR;
+      break;
+  }
+  RejectCallbackWithError(
+      l10n_util::GetStringUTF8(IDS_CERT_MANAGER_IMPORT_ERROR_TITLE),
+      l10n_util::GetStringUTF8(string_id));
+}
+
+void CertificatesHandler::HandleCancelImportExportProcess(
+    const base::ListValue* args) {
+  ImportExportCleanup();
+}
+
+void CertificatesHandler::ImportExportCleanup() {
+  file_path_.clear();
+  password_.clear();
+  file_data_.clear();
+  use_hardware_backed_ = false;
+  selected_cert_list_.clear();
+  module_ = NULL;
+  tracker_.TryCancelAll();
+
+  // There may be pending file dialogs, we need to tell them that we've gone
+  // away so they don't try and call back to us.
+  if (select_file_dialog_.get())
+    select_file_dialog_->ListenerDestroyed();
+  select_file_dialog_ = NULL;
+}
+
+void CertificatesHandler::HandleImportServer(const base::ListValue* args) {
+  CHECK_EQ(1U, args->GetSize());
+  AssignWebUICallbackId(args);
+
+  select_file_dialog_ = ui::SelectFileDialog::Create(
+      this, new ChromeSelectFilePolicy(web_ui()->GetWebContents()));
+  ShowCertSelectFileDialog(
+      select_file_dialog_.get(),
+      ui::SelectFileDialog::SELECT_OPEN_FILE,
+      base::FilePath(),
+      GetParentWindow(),
+      reinterpret_cast<void*>(IMPORT_SERVER_FILE_SELECTED));
+}
+
+void CertificatesHandler::ImportServerFileSelected(
+    const base::FilePath& path) {
+  file_access_provider_->StartRead(
+      path, base::Bind(&CertificatesHandler::ImportServerFileRead,
+                       base::Unretained(this)),
+      &tracker_);
+}
+
+void CertificatesHandler::ImportServerFileRead(const int* read_errno,
+                                               const std::string* data) {
+  if (*read_errno) {
+    ImportExportCleanup();
+    RejectCallbackWithError(
+        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE),
+        l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_READ_ERROR_FORMAT,
+                                  UTF8ToUTF16(
+                                      base::safe_strerror(*read_errno))));
+    return;
+  }
+
+  selected_cert_list_ = net::X509Certificate::CreateCertificateListFromBytes(
+          data->data(), data->size(), net::X509Certificate::FORMAT_AUTO);
+  if (selected_cert_list_.empty()) {
+    ImportExportCleanup();
+    RejectCallbackWithError(
+        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE),
+        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CERT_PARSE_ERROR));
+    return;
+  }
+
+  net::NSSCertDatabase::ImportCertFailureList not_imported;
+  // TODO(mattm): Add UI for trust. http://crbug.com/76274
+  bool result = certificate_manager_model_->ImportServerCert(
+      selected_cert_list_,
+      net::NSSCertDatabase::TRUST_DEFAULT,
+      &not_imported);
+  if (!result) {
+    RejectCallbackWithError(
+        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE),
+        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
+  } else if (!not_imported.empty()) {
+    RejectCallbackWithImportError(
+        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE),
+        not_imported);
+  } else {
+    ResolveCallback(*base::Value::CreateNullValue());
+  }
+  ImportExportCleanup();
+}
+
+void CertificatesHandler::HandleImportCA(const base::ListValue* args) {
+  CHECK_EQ(1U, args->GetSize());
+  AssignWebUICallbackId(args);
+
+  select_file_dialog_ = ui::SelectFileDialog::Create(
+      this, new ChromeSelectFilePolicy(web_ui()->GetWebContents()));
+  ShowCertSelectFileDialog(select_file_dialog_.get(),
+                           ui::SelectFileDialog::SELECT_OPEN_FILE,
+                           base::FilePath(),
+                           GetParentWindow(),
+                           reinterpret_cast<void*>(IMPORT_CA_FILE_SELECTED));
+}
+
+void CertificatesHandler::ImportCAFileSelected(
+    const base::FilePath& path) {
+  file_access_provider_->StartRead(
+      path, base::Bind(&CertificatesHandler::ImportCAFileRead,
+                       base::Unretained(this)),
+      &tracker_);
+}
+
+void CertificatesHandler::ImportCAFileRead(const int* read_errno,
+                                           const std::string* data) {
+  if (*read_errno) {
+    ImportExportCleanup();
+    RejectCallbackWithError(
+        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE),
+        l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_READ_ERROR_FORMAT,
+                                  UTF8ToUTF16(
+                                      base::safe_strerror(*read_errno))));
+    return;
+  }
+
+  selected_cert_list_ = net::X509Certificate::CreateCertificateListFromBytes(
+          data->data(), data->size(), net::X509Certificate::FORMAT_AUTO);
+  if (selected_cert_list_.empty()) {
+    ImportExportCleanup();
+    RejectCallbackWithError(
+        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE),
+        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CERT_PARSE_ERROR));
+    return;
+  }
+
+  scoped_refptr<net::X509Certificate> root_cert =
+      certificate_manager_model_->cert_db()->FindRootInList(
+          selected_cert_list_);
+
+  // TODO(mattm): check here if root_cert is not a CA cert and show error.
+
+  base::StringValue cert_name(root_cert->subject().GetDisplayName());
+  ResolveCallback(cert_name);
+}
+
+void CertificatesHandler::HandleImportCATrustSelected(
+    const base::ListValue* args) {
+  CHECK_EQ(4U, args->GetSize());
+  AssignWebUICallbackId(args);
+
+  bool trust_ssl = false;
+  bool trust_email = false;
+  bool trust_obj_sign = false;
+  CHECK(args->GetBoolean(1, &trust_ssl));
+  CHECK(args->GetBoolean(2, &trust_email));
+  CHECK(args->GetBoolean(3, &trust_obj_sign));
+
+  // TODO(mattm): add UI for setting explicit distrust, too.
+  // http://crbug.com/128411
+  net::NSSCertDatabase::ImportCertFailureList not_imported;
+  bool result = certificate_manager_model_->ImportCACerts(
+      selected_cert_list_,
+      trust_ssl * net::NSSCertDatabase::TRUSTED_SSL +
+          trust_email * net::NSSCertDatabase::TRUSTED_EMAIL +
+          trust_obj_sign * net::NSSCertDatabase::TRUSTED_OBJ_SIGN,
+      &not_imported);
+  if (!result) {
+    RejectCallbackWithError(
+        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE),
+        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
+  } else if (!not_imported.empty()) {
+    RejectCallbackWithImportError(
+        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE),
+        not_imported);
+  } else {
+    ResolveCallback(*base::Value::CreateNullValue());
+  }
+  ImportExportCleanup();
+}
+
+void CertificatesHandler::HandleExportCertificate(const base::ListValue* args) {
+  net::X509Certificate* cert = cert_id_map_->CallbackArgsToCert(args);
+  if (!cert)
+    return;
+  ShowCertExportDialog(web_ui()->GetWebContents(), GetParentWindow(), cert);
+}
+
+void CertificatesHandler::HandleDeleteCertificate(const base::ListValue* args) {
+  CHECK_EQ(2U, args->GetSize());
+  AssignWebUICallbackId(args);
+  std::string node_id;
+  CHECK(args->GetString(1, &node_id));
+
+  net::X509Certificate* cert = cert_id_map_->IdToCert(node_id);
+  CHECK(cert);
+
+  bool result = certificate_manager_model_->Delete(cert);
+  if (!result) {
+    // TODO(mattm): better error messages?
+    RejectCallbackWithError(
+        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_DELETE_CERT_ERROR_TITLE),
+        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
+  } else {
+    ResolveCallback(*base::Value::CreateNullValue());
+  }
+}
+
+void CertificatesHandler::OnCertificateManagerModelCreated(
+    scoped_ptr<CertificateManagerModel> model) {
+  certificate_manager_model_ = std::move(model);
+  CertificateManagerModelReady();
+}
+
+void CertificatesHandler::CertificateManagerModelReady() {
+  base::FundamentalValue user_db_available_value(
+      certificate_manager_model_->is_user_db_available());
+  base::FundamentalValue tpm_available_value(
+      certificate_manager_model_->is_tpm_available());
+  web_ui()->CallJavascriptFunction(
+      "cr.webUIListenerCallback",
+      base::StringValue("certificates-model-ready"),
+      user_db_available_value,
+      tpm_available_value);
+  certificate_manager_model_->Refresh();
+}
+
+void CertificatesHandler::HandleRefreshCertificates(
+    const base::ListValue* args) {
+  if (certificate_manager_model_) {
+    // Already have a model, the webui must be re-loading.  Just re-run the
+    // webui initialization.
+    CertificateManagerModelReady();
+    return;
+  }
+
+  if (!requested_certificate_manager_model_) {
+    // Request that a model be created.
+    CertificateManagerModel::Create(
+        Profile::FromWebUI(web_ui()),
+        this,
+        base::Bind(&CertificatesHandler::OnCertificateManagerModelCreated,
+                   weak_ptr_factory_.GetWeakPtr()));
+    requested_certificate_manager_model_ = true;
+    return;
+  }
+
+  // We are already waiting for a CertificateManagerModel to be created, no need
+  // to do anything.
+}
+
+void CertificatesHandler::PopulateTree(
+    const std::string& tab_name,
+    net::CertType type,
+    const net::CertificateList& web_trust_certs) {
+  scoped_ptr<icu::Collator> collator;
+  UErrorCode error = U_ZERO_ERROR;
+  collator.reset(
+      icu::Collator::createInstance(
+          icu::Locale(g_browser_process->GetApplicationLocale().c_str()),
+          error));
+  if (U_FAILURE(error))
+    collator.reset(NULL);
+  DictionaryIdComparator comparator(collator.get());
+  CertificateManagerModel::OrgGroupingMap map;
+
+  certificate_manager_model_->FilterAndBuildOrgGroupingMap(type, &map);
+
+  {
+    scoped_ptr<base::ListValue> nodes = make_scoped_ptr(new base::ListValue());
+    for (CertificateManagerModel::OrgGroupingMap::iterator i = map.begin();
+         i != map.end(); ++i) {
+      // Populate first level (org name).
+      base::DictionaryValue* dict = new base::DictionaryValue;
+      dict->SetString(kKeyField, OrgNameToId(i->first));
+      dict->SetString(kNameField, i->first);
+
+      // Populate second level (certs).
+      base::ListValue* subnodes = new base::ListValue;
+      for (net::CertificateList::const_iterator org_cert_it = i->second.begin();
+           org_cert_it != i->second.end(); ++org_cert_it) {
+        base::DictionaryValue* cert_dict = new base::DictionaryValue;
+        net::X509Certificate* cert = org_cert_it->get();
+        cert_dict->SetString(kKeyField, cert_id_map_->CertToId(cert));
+        cert_dict->SetString(
+            kNameField, certificate_manager_model_->GetColumnText(
+                *cert, CertificateManagerModel::COL_SUBJECT_NAME));
+        cert_dict->SetBoolean(
+            kReadonlyField,
+            certificate_manager_model_->cert_db()->IsReadOnly(cert));
+        // Policy-installed certificates with web trust are trusted.
+        bool policy_trusted =
+            IsPolicyInstalledWithWebTrust(web_trust_certs, cert);
+        cert_dict->SetBoolean(
+            kUntrustedField,
+            !policy_trusted &&
+                certificate_manager_model_->cert_db()->IsUntrusted(cert));
+        cert_dict->SetBoolean(kPolicyField, policy_trusted);
+        // TODO(hshi): This should be determined by testing for PKCS #11
+        // CKA_EXTRACTABLE attribute. We may need to use the NSS function
+        // PK11_ReadRawAttribute to do that.
+        cert_dict->SetBoolean(
+            kExtractableField,
+            !certificate_manager_model_->IsHardwareBacked(cert));
+        // TODO(mattm): Other columns.
+        subnodes->Append(cert_dict);
+      }
+      std::sort(subnodes->begin(), subnodes->end(), comparator);
+
+      dict->Set(kSubnodesField, subnodes);
+      nodes->Append(dict);
+    }
+    std::sort(nodes->begin(), nodes->end(), comparator);
+
+    web_ui()->CallJavascriptFunction("cr.webUIListenerCallback",
+                                     base::StringValue("certificates-changed"),
+                                     base::StringValue(tab_name),
+                                     *nodes);
+  }
+}
+
+void CertificatesHandler::ResolveCallback(const base::Value& response) {
+  DCHECK(!webui_callback_id_.empty());
+  ResolveJavascriptCallback(base::StringValue(webui_callback_id_), response);
+  webui_callback_id_.clear();
+}
+
+void CertificatesHandler::RejectCallback(const base::Value& response) {
+  DCHECK(!webui_callback_id_.empty());
+  RejectJavascriptCallback(base::StringValue(webui_callback_id_), response);
+  webui_callback_id_.clear();
+}
+
+void CertificatesHandler::RejectCallbackWithError(
+    const std::string& title,
+    const std::string& error) {
+  scoped_ptr<base::DictionaryValue> error_info(new base::DictionaryValue);
+  error_info->SetString(kErrorTitle, title);
+  error_info->SetString(kErrorDescription, error);
+  RejectCallback(*error_info);
+}
+
+void CertificatesHandler::RejectCallbackWithImportError(
+    const std::string& title,
+    const net::NSSCertDatabase::ImportCertFailureList& not_imported) {
+  std::string error;
+  if (selected_cert_list_.size() == 1)
+    error = l10n_util::GetStringUTF8(
+        IDS_CERT_MANAGER_IMPORT_SINGLE_NOT_IMPORTED);
+  else if (not_imported.size() == selected_cert_list_.size())
+    error = l10n_util::GetStringUTF8(IDS_CERT_MANAGER_IMPORT_ALL_NOT_IMPORTED);
+  else
+    error = l10n_util::GetStringUTF8(IDS_CERT_MANAGER_IMPORT_SOME_NOT_IMPORTED);
+
+  scoped_ptr<base::ListValue> cert_error_list =
+      make_scoped_ptr(new base::ListValue());
+  for (size_t i = 0; i < not_imported.size(); ++i) {
+    const net::NSSCertDatabase::ImportCertFailure& failure = not_imported[i];
+    base::DictionaryValue* dict = new base::DictionaryValue;
+    dict->SetString(
+        kNameField, failure.certificate->subject().GetDisplayName());
+    dict->SetString(kErrorField, NetErrorToString(failure.net_error));
+    cert_error_list->Append(dict);
+  }
+
+  scoped_ptr<base::DictionaryValue> error_info(new base::DictionaryValue);
+  error_info->SetString(kErrorTitle, title);
+  error_info->SetString(kErrorDescription, error);
+  error_info->Set(
+      kCertificateErrors, make_scoped_ptr(cert_error_list.release()));
+  RejectCallback(*error_info);
+}
+
+gfx::NativeWindow CertificatesHandler::GetParentWindow() const {
+  return web_ui()->GetWebContents()->GetTopLevelNativeWindow();
+}
+
+}  // namespace settings
diff --git a/chrome/browser/ui/webui/settings/certificates_handler.h b/chrome/browser/ui/webui/settings/certificates_handler.h
new file mode 100644
index 0000000..99607f2
--- /dev/null
+++ b/chrome/browser/ui/webui/settings/certificates_handler.h
@@ -0,0 +1,201 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_CERTIFICATES_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_SETTINGS_CERTIFICATES_HANDLER_H_
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/task/cancelable_task_tracker.h"
+#include "chrome/browser/certificate_manager_model.h"
+#include "chrome/browser/ui/webui/settings/md_settings_ui.h"
+#include "net/cert/nss_cert_database.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/shell_dialogs/select_file_dialog.h"
+
+namespace settings {
+
+class CertIdMap;
+class FileAccessProvider;
+
+class CertificatesHandler
+    : public SettingsPageUIHandler,
+      public CertificateManagerModel::Observer,
+      public ui::SelectFileDialog::Listener {
+ public:
+  explicit CertificatesHandler(bool show_certs_in_modal_dialog);
+  ~CertificatesHandler() override;
+
+  // SettingsPageUIHandler implementation.
+  void RegisterMessages() override;
+
+  // CertificateManagerModel::Observer implementation.
+  void CertificatesRefreshed() override;
+
+  // SelectFileDialog::Listener implementation.
+  void FileSelected(const base::FilePath& path,
+                    int index,
+                    void* params) override;
+  void FileSelectionCanceled(void* params) override;
+
+ private:
+  // View certificate.
+  void HandleViewCertificate(const base::ListValue* args);
+
+  // Edit certificate authority trust values.  The sequence goes like:
+  //  1. user clicks edit button -> Edit dialog is shown ->
+  //  HandleGetCATrust -> Edit dialog is populated.
+  //  2. User checks/unchecks boxes, and clicks ok -> HandleEditCATrust ->
+  //  edit dialog is dismissed upon success.
+  void HandleGetCATrust(const base::ListValue* args);
+  void HandleEditCATrust(const base::ListValue* args);
+
+  // Cleanup state stored during import or export process.
+  void HandleCancelImportExportProcess(const base::ListValue* args);
+  void ImportExportCleanup();
+
+  // Export to PKCS #12 file.  The sequence goes like:
+  //  1. user click on export button -> HandleExportPersonal -> launches file
+  //  selector
+  //  2. user selects file -> ExportPersonalFileSelected -> launches password
+  //  dialog
+  //  3. user enters password -> HandleExportPersonalPasswordSelected ->
+  //  unlock slots
+  //  4. slots unlocked -> ExportPersonalSlotsUnlocked -> exports to memory
+  //  buffer -> starts async write operation
+  //  5. write finishes (or fails) -> ExportPersonalFileWritten
+  void HandleExportPersonal(const base::ListValue* args);
+  void ExportPersonalFileSelected(const base::FilePath& path);
+  void HandleExportPersonalPasswordSelected(const base::ListValue* args);
+  void ExportPersonalSlotsUnlocked();
+  void ExportPersonalFileWritten(const int* write_errno,
+                                 const int* bytes_written);
+
+  // Import from PKCS #12 or cert file.  The sequence goes like:
+  //  1. user click on import button -> HandleImportPersonal ->
+  //  launches file selector
+  //  2. user selects file -> ImportPersonalFileSelected -> starts async
+  //  read operation
+  //  3. read operation completes -> ImportPersonalFileRead ->
+  //    If file is PFX -> launches password dialog, goto step 4
+  //    Else -> import as certificate, goto step 6
+  //  4. user enters password -> HandleImportPersonalPasswordSelected ->
+  //  unlock slot
+  //  5. slot unlocked -> ImportPersonalSlotUnlocked attempts to
+  //  import with previously entered password
+  //  6a. if import succeeds -> ImportExportCleanup
+  //  6b. if import fails -> show error, ImportExportCleanup
+  //  TODO(mattm): allow retrying with different password
+  void HandleImportPersonal(const base::ListValue* args);
+  void ImportPersonalFileSelected(const base::FilePath& path);
+  void ImportPersonalFileRead(const int* read_errno, const std::string* data);
+  void HandleImportPersonalPasswordSelected(const base::ListValue* args);
+  void ImportPersonalSlotUnlocked();
+
+  // Import Server certificates from file.  Sequence goes like:
+  //  1. user clicks on import button -> HandleImportServer -> launches file
+  //  selector
+  //  2. user selects file -> ImportServerFileSelected -> starts async read
+  //  3. read completes -> ImportServerFileRead -> parse certs -> attempt import
+  //  4a. if import succeeds -> ImportExportCleanup
+  //  4b. if import fails -> show error, ImportExportCleanup
+  void HandleImportServer(const base::ListValue* args);
+  void ImportServerFileSelected(const base::FilePath& path);
+  void ImportServerFileRead(const int* read_errno, const std::string* data);
+
+  // Import Certificate Authorities from file.  Sequence goes like:
+  //  1. user clicks on import button -> HandleImportCA -> launches file
+  //  selector
+  //  2. user selects file -> ImportCAFileSelected -> starts async read
+  //  3. read completes -> ImportCAFileRead -> parse certs -> Certificate trust
+  //  level dialog is shown.
+  //  4. user clicks ok -> HandleImportCATrustSelected -> attempt import
+  //  5a. if import succeeds -> ImportExportCleanup
+  //  5b. if import fails -> show error, ImportExportCleanup
+  void HandleImportCA(const base::ListValue* args);
+  void ImportCAFileSelected(const base::FilePath& path);
+  void ImportCAFileRead(const int* read_errno, const std::string* data);
+  void HandleImportCATrustSelected(const base::ListValue* args);
+
+  // Export a certificate.
+  void HandleExportCertificate(const base::ListValue* args);
+
+  // Delete certificate and private key (if any).
+  void HandleDeleteCertificate(const base::ListValue* args);
+
+  // Model initialization methods.
+  void OnCertificateManagerModelCreated(
+      scoped_ptr<CertificateManagerModel> model);
+  void CertificateManagerModelReady();
+
+  // Populate the trees in all the tabs.
+  void HandleRefreshCertificates(const base::ListValue* args);
+
+  // Populate the given tab's tree.
+  void PopulateTree(const std::string& tab_name,
+                    net::CertType type,
+                    const net::CertificateList& web_trust_certs);
+
+  // Populate the tree after retrieving the list of policy-installed
+  // web-trusted certificates.
+  void OnPolicyWebTrustCertsRetrieved(
+      const net::CertificateList& web_trust_certs);
+
+  void ResolveCallback(const base::Value& response);
+  void RejectCallback(const base::Value& response);
+
+  // Reject the pending JS callback with a generic error.
+  void RejectCallbackWithError(
+      const std::string& title, const std::string& error);
+
+  // Reject the pending JS callback with a certificate import error.
+  void RejectCallbackWithImportError(
+      const std::string& title,
+      const net::NSSCertDatabase::ImportCertFailureList& not_imported);
+
+  // Assigns a new |webui_callback_id_|. Ensures that previous in-flight request
+  // has been fulfilled.
+  void AssignWebUICallbackId(const base::ListValue* args);
+
+  gfx::NativeWindow GetParentWindow() const;
+
+  // True if certificate viewer should be shown in modal instead of constrianed
+  // dialog.
+  bool show_certs_in_modal_dialog_;
+  // The Certificates Manager model
+  bool requested_certificate_manager_model_;
+  scoped_ptr<CertificateManagerModel> certificate_manager_model_;
+
+  // For multi-step import or export processes, we need to store the path,
+  // password, etc the user chose while we wait for them to enter a password,
+  // wait for file to be read, etc.
+  base::FilePath file_path_;
+  base::string16 password_;
+  // The WebUI callback ID of the last in-flight async request. There is always
+  // only one in-flight such request.
+  std::string webui_callback_id_;
+  bool use_hardware_backed_;
+  std::string file_data_;
+  net::CertificateList selected_cert_list_;
+  scoped_refptr<ui::SelectFileDialog> select_file_dialog_;
+  scoped_refptr<net::CryptoModule> module_;
+
+  // Used in reading and writing certificate files.
+  base::CancelableTaskTracker tracker_;
+  scoped_refptr<FileAccessProvider> file_access_provider_;
+
+  scoped_ptr<CertIdMap> cert_id_map_;
+
+  base::WeakPtrFactory<CertificatesHandler> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(CertificatesHandler);
+};
+
+}  // namespace settings
+
+#endif  // CHROME_BROWSER_UI_WEBUI_SETTINGS_CERTIFICATES_HANDLER_H_
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui.cc b/chrome/browser/ui/webui/settings/md_settings_ui.cc
index 2c8dae88..592759e 100644
--- a/chrome/browser/ui/webui/settings/md_settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_ui.cc
@@ -37,6 +37,10 @@
 #include "chrome/browser/ui/webui/settings/settings_manage_profile_handler.h"
 #endif  // defined(OS_CHROMEOS)
 
+#if defined(USE_NSS_CERTS)
+#include "chrome/browser/ui/webui/settings/certificates_handler.h"
+#endif  // defined(USE_NSS_CERTS)
+
 namespace settings {
 
 SettingsPageUIHandler::SettingsPageUIHandler() {
@@ -68,6 +72,11 @@
       WebContentsObserver(web_ui->GetWebContents()) {
   Profile* profile = Profile::FromWebUI(web_ui);
   AddSettingsPageUIHandler(new AppearanceHandler(web_ui));
+
+#if defined(USE_NSS_CERTS)
+  AddSettingsPageUIHandler(new CertificatesHandler(false));
+#endif  // defined(USE_NSS_CERTS)
+
   AddSettingsPageUIHandler(new ClearBrowsingDataHandler(web_ui));
   AddSettingsPageUIHandler(new DownloadsHandler());
   AddSettingsPageUIHandler(new FontHandler(web_ui));
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 81e4906..01b4820 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -1402,6 +1402,8 @@
       'browser/hang_monitor/hung_window_detector.h',
       'browser/password_manager/password_manager_util_win.cc',
       'browser/password_manager/password_manager_util_win.h',
+      'browser/themes/theme_service_win.cc',
+      'browser/themes/theme_service_win.h',
     ],
     'chrome_browser_non_win_sources': [
       'browser/profile_resetter/triggered_profile_resetter_stub.cc',
diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi
index 9d170c5..d407c6c 100644
--- a/chrome/chrome_browser_chromeos.gypi
+++ b/chrome/chrome_browser_chromeos.gypi
@@ -52,6 +52,8 @@
         'browser/chromeos/app_mode/kiosk_session_plugin_handler_delegate.h',
         'browser/chromeos/app_mode/startup_app_launcher.cc',
         'browser/chromeos/app_mode/startup_app_launcher.h',
+        'browser/chromeos/arc/arc_auth_notification.cc',
+        'browser/chromeos/arc/arc_auth_notification.h',
         'browser/chromeos/arc/arc_auth_service.cc',
         'browser/chromeos/arc/arc_auth_service.h',
         'browser/chromeos/arc/arc_intent_helper_bridge.cc',
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index 6bd841f..ac8a862c 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -2785,6 +2785,8 @@
       'browser/ui/crypto_module_password_dialog_nss.h',
       'browser/ui/webui/options/certificate_manager_handler.cc',
       'browser/ui/webui/options/certificate_manager_handler.h',
+      'browser/ui/webui/settings/certificates_handler.cc',
+      'browser/ui/webui/settings/certificates_handler.h',
     ],
     'chrome_browser_ui_omnibox_non_mobile_sources': [
       'browser/ui/omnibox/alternate_nav_infobar_delegate.cc',
diff --git a/chrome/common/extensions/api/input_ime.json b/chrome/common/extensions/api/input_ime.json
index 8faf98f..0f981fc 100644
--- a/chrome/common/extensions/api/input_ime.json
+++ b/chrome/common/extensions/api/input_ime.json
@@ -593,13 +593,53 @@
                 "name": "windowObject",
                 "type": "object",
                 "isInstanceOf": "Window",
-                "description": "The JavaScript 'window' object of the newly created IME window."
+                "description": "The JavaScript 'window' object of the newly created IME window. It contains the additional 'id' property for the parameters of the other functions like showWindow/hideWindow."
               }
             ]
            }
          ]
       },
       {
+        "name": "showWindow",
+        "type": "function",
+        "description": "Shows the IME window. This makes the hidden window visible.",
+        "platforms": ["win", "linux"],
+        "parameters": [
+          {
+            "type": "integer",
+            "name": "windowId",
+            "description": "The ID of the IME window."
+          },
+          {
+            "type": "function",
+            "name": "callback",
+            "optional": true,
+            "description": "Called when the operation completes.",
+            "parameters": []
+           }
+         ]
+      },
+      {
+        "name": "hideWindow",
+        "type": "function",
+        "description": "Hides the IME window. This doesn't close the window. Instead, it makes the window invisible. The extension can cache the window and show/hide it for better performance.",
+        "platforms": ["win", "linux"],
+        "parameters": [
+          {
+            "type": "integer",
+            "name": "windowId",
+            "description": "The ID of the IME window."
+          },
+          {
+            "type": "function",
+            "name": "callback",
+            "optional": true,
+            "description": "Called when the operation completes.",
+            "parameters": []
+           }
+         ]
+      },
+      {
         "name": "activate",
         "type": "function",
         "description": "Activates the IME extension so that it can receive events.",
diff --git a/chrome/renderer/resources/extensions/input.ime_custom_bindings.js b/chrome/renderer/resources/extensions/input.ime_custom_bindings.js
index f114124e..9f4d9acb 100644
--- a/chrome/renderer/resources/extensions/input.ime_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/input.ime_custom_bindings.js
@@ -51,6 +51,7 @@
     if (windowParams && windowParams.frameId) {
       view = appWindowNatives.GetFrame(
           windowParams.frameId, false /* notifyBrowser */);
+      view.id = windowParams.frameId;
     }
     callback(view);
   });
diff --git a/chrome/test/base/v8_unit_test.cc b/chrome/test/base/v8_unit_test.cc
index 392ff45b..9f52f06 100644
--- a/chrome/test/base/v8_unit_test.cc
+++ b/chrome/test/base/v8_unit_test.cc
@@ -11,7 +11,6 @@
 #include "base/strings/stringprintf.h"
 #include "chrome/common/chrome_paths.h"
 #include "third_party/WebKit/public/web/WebKit.h"
-#include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h"
 
 namespace {
 
@@ -96,7 +95,6 @@
   v8::Local<v8::Context> context =
       v8::Local<v8::Context>::New(isolate, context_);
   v8::Context::Scope context_scope(context);
-  blink::WebScopedMicrotaskSuppression microtasks_scope;
 
   v8::Local<v8::Value> function_property =
       context->Global()->Get(v8::String::NewFromUtf8(isolate, "runTest"));
@@ -211,7 +209,6 @@
   v8::Local<v8::Context> context =
       v8::Local<v8::Context>::New(isolate, context_);
   v8::Context::Scope context_scope(context);
-  blink::WebScopedMicrotaskSuppression microtasks_scope;
   v8::Local<v8::String> source =
       v8::String::NewFromUtf8(isolate,
                               script_source.data(),
@@ -260,7 +257,6 @@
   v8::Local<v8::Context> context =
       v8::Local<v8::Context>::New(isolate, context_);
   v8::Context::Scope context_scope(context);
-  blink::WebScopedMicrotaskSuppression microtasks_scope;
 
   v8::Local<v8::Value> function_property = context->Global()->Get(
       v8::String::NewFromUtf8(isolate, function_name.c_str()));
diff --git a/chrome/test/data/push_messaging/push_test.js b/chrome/test/data/push_messaging/push_test.js
index 73a307e..c1fe6aa 100644
--- a/chrome/test/data/push_messaging/push_test.js
+++ b/chrome/test/data/push_messaging/push_test.js
@@ -7,16 +7,6 @@
 var resultQueue = new ResultQueue();
 var pushSubscription = null;
 
-// NIST P-256 public key made available to tests. Must be an uncompressed
-// point in accordance with SEC1 2.3.3.
-var applicationServerKey = new Uint8Array([
-  0x04, 0x55, 0x52, 0x6A, 0xA5, 0x6E, 0x8E, 0xAA, 0x47, 0x97, 0x36, 0x10, 0xC1,
-  0x66, 0x3C, 0x1E, 0x65, 0xBF, 0xA1, 0x7B, 0xEE, 0x48, 0xC9, 0xC6, 0xBB, 0xBF,
-  0x02, 0x18, 0x53, 0x72, 0x1D, 0x0C, 0x7B, 0xA9, 0xE3, 0x11, 0xB7, 0x03, 0x52,
-  0x21, 0xD3, 0x71, 0x90, 0x13, 0xA8, 0xC1, 0xCF, 0xED, 0x20, 0xF7, 0x1F, 0xD1,
-  0x7F, 0xF2, 0x76, 0xB6, 0x01, 0x20, 0xD8, 0x35, 0xA5, 0xD9, 0x3C, 0x43, 0xFD
-]);
-
 var pushSubscriptionOptions = {
   userVisibleOnly: true
 };
@@ -116,36 +106,8 @@
   }
 }
 
-// This is the old style of push subscriptions which we are phasing away
-// from, where the subscription used a sender ID instead of public key.
-function subscribePushWithoutKey() {
-  navigator.serviceWorker.ready.then(function(swRegistration) {
-    return swRegistration.pushManager.subscribe(
-        pushSubscriptionOptions)
-        .then(function(subscription) {
-          pushSubscription = subscription;
-          sendResultToTest(subscription.endpoint);
-        });
-  }).catch(sendErrorToTest);
-}
-
 function subscribePush() {
   navigator.serviceWorker.ready.then(function(swRegistration) {
-    pushSubscriptionOptions.applicationServerKey = applicationServerKey.buffer;
-    return swRegistration.pushManager.subscribe(pushSubscriptionOptions)
-        .then(function(subscription) {
-          pushSubscription = subscription;
-          sendResultToTest(subscription.endpoint);
-        });
-  }).catch(sendErrorToTest);
-}
-
-function subscribePushBadKey() {
-  navigator.serviceWorker.ready.then(function(swRegistration) {
-    var invalidApplicationServerKey = Uint8Array.from(applicationServerKey);
-    invalidApplicationServerKey[0] = 0x05;
-    pushSubscriptionOptions.applicationServerKey =
-        invalidApplicationServerKey.buffer;
     return swRegistration.pushManager.subscribe(pushSubscriptionOptions)
         .then(function(subscription) {
           pushSubscription = subscription;
diff --git a/chrome/test/data/webui/splitter_test.html b/chrome/test/data/webui/splitter_test.html
index 9d4a567..0d9dd7a 100644
--- a/chrome/test/data/webui/splitter_test.html
+++ b/chrome/test/data/webui/splitter_test.html
@@ -1,9 +1,9 @@
 <!doctype html>
 <html>
 <body>
-<div></div>
+<div id="previous"></div>
 <div id="splitter"></div>
-<div></div>
+<div id="next"></div>
 <script>
 function testSplitter_IgnoresRightMouse() {
   var splitter = document.getElementById('splitter');
@@ -17,6 +17,63 @@
   assertFalse(splitter.dispatchEvent(downLeft));
   assertTrue(downLeft.defaultPrevented);
 }
+
+function testSplitter_ResizePreviousElement() {
+  var splitter = document.getElementById('splitter');
+  cr.ui.decorate(splitter, cr.ui.Splitter);
+  splitter.resizeNextElement = false;
+
+  var previousElement = document.getElementById('previous');
+  previousElement.style.width = '0px';
+  var beforeWidth = parseFloat(previousElement.style.width);
+
+  var down = new MouseEvent('mousedown',
+      {button: 0, cancelable: true, clientX: 0});
+  splitter.dispatchEvent(down);
+
+  var move = new MouseEvent('mousemove',
+      {button: 0, cancelable: true, clientX: 50});
+  splitter.dispatchEvent(move);
+
+  move = new MouseEvent('mousemove',
+      {button: 0, cancelable: true, clientX: 100});
+  splitter.dispatchEvent(move);
+
+  var up = new MouseEvent('mouseup',
+      {button: 0, cancelable: true, clientX: 100});
+  splitter.dispatchEvent(up);
+
+  var afterWidth = parseFloat(previousElement.style.width);
+  assertEquals(100, afterWidth - beforeWidth);
+}
+
+function testSplitter_ResizeNextElement() {
+  var splitter = document.getElementById('splitter');
+  cr.ui.decorate(splitter, cr.ui.Splitter, true);
+  splitter.resizeNextElement = true;
+  var nextElement = document.getElementById('next');
+  nextElement.style.width = '0px';
+  var beforeWidth = parseFloat(nextElement.style.width);
+
+  var down = new MouseEvent('mousedown',
+      {button: 0, cancelable: true, clientX: 100});
+  splitter.dispatchEvent(down);
+
+  var move = new MouseEvent('mousemove',
+      {button: 0, cancelable: true, clientX: 50});
+  splitter.dispatchEvent(move);
+
+  move = new MouseEvent('mousemove',
+      {button: 0, cancelable: true, clientX: 0});
+  splitter.dispatchEvent(move);
+
+  var up = new MouseEvent('mouseup',
+      {button: 0, cancelable: true, clientX: 0});
+  splitter.dispatchEvent(up);
+
+  var afterWidth = parseFloat(nextElement.style.width);
+  assertEquals(100, afterWidth - beforeWidth);
+}
 </script>
 </body>
 </html>
diff --git a/chromecast/renderer/cast_content_renderer_client.cc b/chromecast/renderer/cast_content_renderer_client.cc
index f6b7a77..c06c618 100644
--- a/chromecast/renderer/cast_content_renderer_client.cc
+++ b/chromecast/renderer/cast_content_renderer_client.cc
@@ -25,7 +25,6 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/render_view.h"
-#include "content/public/renderer/render_view_observer.h"
 #include "third_party/WebKit/public/platform/WebColor.h"
 #include "third_party/WebKit/public/web/WebFrameWidget.h"
 #include "third_party/WebKit/public/web/WebSettings.h"
@@ -72,31 +71,6 @@
 // though the comment of WebColor says it is in RGBA.
 const blink::WebColor kColorBlack = 0xFF000000;
 
-class CastRenderViewObserver : content::RenderViewObserver {
- public:
-  CastRenderViewObserver(CastContentRendererClient* client,
-                         content::RenderView* render_view);
-  ~CastRenderViewObserver() override {}
-
-  void DidClearWindowObject(blink::WebLocalFrame* frame) override;
-
- private:
-  CastContentRendererClient* const client_;
-
-  DISALLOW_COPY_AND_ASSIGN(CastRenderViewObserver);
-};
-
-CastRenderViewObserver::CastRenderViewObserver(
-    CastContentRendererClient* client,
-    content::RenderView* render_view)
-    : content::RenderViewObserver(render_view),
-      client_(client) {
-}
-
-void CastRenderViewObserver::DidClearWindowObject(blink::WebLocalFrame* frame) {
-  client_->AddRendererNativeBindings(frame);
-}
-
 }  // namespace
 
 CastContentRendererClient::CastContentRendererClient()
@@ -108,10 +82,6 @@
 CastContentRendererClient::~CastContentRendererClient() {
 }
 
-void CastContentRendererClient::AddRendererNativeBindings(
-    blink::WebLocalFrame* frame) {
-}
-
 void CastContentRendererClient::RenderThreadStarted() {
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
 
@@ -168,9 +138,6 @@
     // application running.
     webview->settings()->setOfflineWebApplicationCacheEnabled(false);
   }
-
-  // Note: RenderView will own the lifetime of its observer.
-  new CastRenderViewObserver(this, render_view);
 }
 
 void CastContentRendererClient::AddKeySystems(
diff --git a/chromecast/renderer/cast_content_renderer_client.h b/chromecast/renderer/cast_content_renderer_client.h
index 6350038..470e8a8 100644
--- a/chromecast/renderer/cast_content_renderer_client.h
+++ b/chromecast/renderer/cast_content_renderer_client.h
@@ -31,9 +31,6 @@
 
   ~CastContentRendererClient() override;
 
-  // Adds any platform-specific bindings to the current frame.
-  virtual void AddRendererNativeBindings(blink::WebLocalFrame* frame);
-
   // ContentRendererClient implementation:
   void RenderThreadStarted() override;
   void RenderViewCreated(content::RenderView* render_view) override;
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index e895bb6b..e97faf4 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-8025.0.0
\ No newline at end of file
+8031.0.0
\ No newline at end of file
diff --git a/chromeos/chromeos_switches.cc b/chromeos/chromeos_switches.cc
index 37762723..1fbad80 100644
--- a/chromeos/chromeos_switches.cc
+++ b/chromeos/chromeos_switches.cc
@@ -119,6 +119,9 @@
 // locate the device.
 const char kEnableConsumerManagement[] = "enable-consumer-management";
 
+// Enables details panel in Files app.
+const char kEnableFilesDetailsPanel[] = "enable-files-details-panel";
+
 // If this switch is set, the device cannot be remotely disabled by its owner.
 const char kDisableDeviceDisabling[] = "disable-device-disabling";
 
diff --git a/chromeos/chromeos_switches.h b/chromeos/chromeos_switches.h
index 92c24fcf..0124dd4 100644
--- a/chromeos/chromeos_switches.h
+++ b/chromeos/chromeos_switches.h
@@ -61,6 +61,7 @@
 CHROMEOS_EXPORT extern const char kEnableArc[];
 CHROMEOS_EXPORT extern const char kEnableConsumerManagement[];
 CHROMEOS_EXPORT extern const char kEnableExtensionAssetsSharing[];
+CHROMEOS_EXPORT extern const char kEnableFilesDetailsPanel[];
 CHROMEOS_EXPORT extern const char kEnableFirstRunUITransitions[];
 CHROMEOS_EXPORT extern const char kEnableImeMenu[];
 CHROMEOS_EXPORT extern const char kEnableKioskMode[];
diff --git a/components/filesystem/file_system_app.cc b/components/filesystem/file_system_app.cc
index e4620ba8..011f74d 100644
--- a/components/filesystem/file_system_app.cc
+++ b/components/filesystem/file_system_app.cc
@@ -38,10 +38,9 @@
 FileSystemApp::~FileSystemApp() {}
 
 void FileSystemApp::Initialize(mojo::Connector* connector,
-                               const std::string& url,
-                               const std::string& user_id,
+                               const mojo::Identity& identity,
                                uint32_t id) {
-  tracing_.Initialize(connector, url);
+  tracing_.Initialize(connector, identity.name());
 }
 
 bool FileSystemApp::AcceptConnection(mojo::Connection* connection) {
diff --git a/components/filesystem/file_system_app.h b/components/filesystem/file_system_app.h
index 9a5983cb..91c18bc 100644
--- a/components/filesystem/file_system_app.h
+++ b/components/filesystem/file_system_app.h
@@ -31,8 +31,8 @@
   static base::FilePath GetUserDataDir();
 
   // |mojo::ShellClient| override:
-  void Initialize(mojo::Connector* connector, const std::string& url,
-                  const std::string& user_id, uint32_t id) override;
+  void Initialize(mojo::Connector* connector, const mojo::Identity& identity,
+                  uint32_t id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
   // |InterfaceFactory<Files>| implementation:
diff --git a/components/filesystem/file_system_impl.cc b/components/filesystem/file_system_impl.cc
index d64427a..f8b9594d 100644
--- a/components/filesystem/file_system_impl.cc
+++ b/components/filesystem/file_system_impl.cc
@@ -24,7 +24,7 @@
                                mojo::InterfaceRequest<FileSystem> request,
                                base::FilePath persistent_dir,
                                LockTable* lock_table)
-    : remote_application_name_(connection->GetRemoteApplicationName()),
+    : remote_application_name_(connection->GetRemoteIdentity().name()),
       binding_(this, std::move(request)),
       lock_table_(lock_table),
       persistent_dir_(persistent_dir) {}
diff --git a/components/font_service/font_service_app.cc b/components/font_service/font_service_app.cc
index d0c0c1c5..6e73b99 100644
--- a/components/font_service/font_service_app.cc
+++ b/components/font_service/font_service_app.cc
@@ -59,9 +59,9 @@
 FontServiceApp::~FontServiceApp() {}
 
 void FontServiceApp::Initialize(mojo::Connector* connector,
-                                const std::string& url,
-                                const std::string& user_id, uint32_t id) {
-  tracing_.Initialize(connector, url);
+                                const mojo::Identity& identity,
+                                uint32_t id) {
+  tracing_.Initialize(connector, identity.name());
 }
 
 bool FontServiceApp::AcceptConnection(mojo::Connection* connection) {
diff --git a/components/font_service/font_service_app.h b/components/font_service/font_service_app.h
index 52b1f03..957f231f 100644
--- a/components/font_service/font_service_app.h
+++ b/components/font_service/font_service_app.h
@@ -27,8 +27,8 @@
 
  private:
   // mojo::ShellClient:
-  void Initialize(mojo::Connector* connector, const std::string& url,
-                  const std::string& user_id, uint32_t id) override;
+  void Initialize(mojo::Connector* connector, const mojo::Identity& identity,
+                  uint32_t id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
   // mojo::InterfaceFactory<FontService>:
diff --git a/components/leveldb/leveldb_app.cc b/components/leveldb/leveldb_app.cc
index 3dfd509d..4ac0ca0 100644
--- a/components/leveldb/leveldb_app.cc
+++ b/components/leveldb/leveldb_app.cc
@@ -14,10 +14,9 @@
 LevelDBApp::~LevelDBApp() {}
 
 void LevelDBApp::Initialize(mojo::Connector* connector,
-                            const std::string& url,
-                            const std::string& user_id,
+                            const mojo::Identity& identity,
                             uint32_t id) {
-  tracing_.Initialize(connector, url);
+  tracing_.Initialize(connector, identity.name());
   service_.reset(new LevelDBServiceImpl);
 }
 
diff --git a/components/leveldb/leveldb_app.h b/components/leveldb/leveldb_app.h
index 886f349..4b87fc89 100644
--- a/components/leveldb/leveldb_app.h
+++ b/components/leveldb/leveldb_app.h
@@ -22,8 +22,7 @@
  private:
   // |ShellClient| override:
   void Initialize(mojo::Connector* connector,
-                  const std::string& url,
-                  const std::string& user_id,
+                  const mojo::Identity& identity,
                   uint32_t id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
diff --git a/components/mus/mus_app.cc b/components/mus/mus_app.cc
index f04ac9bc..2d714799 100644
--- a/components/mus/mus_app.cc
+++ b/components/mus/mus_app.cc
@@ -96,8 +96,7 @@
 }
 
 void MandolineUIServicesApp::Initialize(mojo::Connector* connector,
-                                        const std::string& url,
-                                        const std::string& user_id,
+                                        const mojo::Identity& identity,
                                         uint32_t id) {
   connector_ = connector;
   surfaces_state_ = new SurfacesState;
@@ -135,7 +134,7 @@
   gpu_state_ = new GpuState();
   connection_manager_.reset(new ws::ConnectionManager(this, surfaces_state_));
 
-  tracing_.Initialize(connector, url);
+  tracing_.Initialize(connector, identity.name());
 }
 
 bool MandolineUIServicesApp::AcceptConnection(Connection* connection) {
@@ -184,7 +183,7 @@
                                     mojom::DisplayManagerRequest request) {
   // TODO(sky): validate id.
   connection_manager_->display_manager()
-      ->GetUserDisplayManager(connection->GetRemoteUserID())
+      ->GetUserDisplayManager(connection->GetRemoteIdentity().user_id())
       ->AddDisplayManagerBinding(std::move(request));
 }
 
@@ -192,7 +191,7 @@
     mojo::Connection* connection,
     mojom::WindowManagerFactoryServiceRequest request) {
   connection_manager_->window_manager_factory_registry()->Register(
-      connection->GetRemoteUserID(), std::move(request));
+      connection->GetRemoteIdentity().user_id(), std::move(request));
 }
 
 void MandolineUIServicesApp::Create(Connection* connection,
diff --git a/components/mus/mus_app.h b/components/mus/mus_app.h
index b94ea536..e82f7d6 100644
--- a/components/mus/mus_app.h
+++ b/components/mus/mus_app.h
@@ -63,8 +63,8 @@
   void InitializeResources(mojo::Connector* connector);
 
   // mojo::ShellClient:
-  void Initialize(mojo::Connector* connector, const std::string& url,
-                  const std::string& user_id, uint32_t id) override;
+  void Initialize(mojo::Connector* connector, const mojo::Identity& identity,
+                  uint32_t id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
   // ConnectionManagerDelegate:
diff --git a/components/profile_service/profile_app.cc b/components/profile_service/profile_app.cc
index 5be0fd9..27491db 100644
--- a/components/profile_service/profile_app.cc
+++ b/components/profile_service/profile_app.cc
@@ -36,13 +36,12 @@
 }
 
 void ProfileApp::Initialize(mojo::Connector* connector,
-                            const std::string& url,
-                            const std::string& user_id,
+                            const mojo::Identity& identity,
                             uint32_t id) {
-  tracing_.Initialize(connector, url);
+  tracing_.Initialize(connector, identity.name());
   leveldb_service_.reset(new leveldb::LevelDBServiceImpl);
 
-  auto it = g_user_id_to_data_dir.Get().find(user_id);
+  auto it = g_user_id_to_data_dir.Get().find(identity.user_id());
   DCHECK(it != g_user_id_to_data_dir.Get().end());
   profile_data_dir_ = it->second;
 }
diff --git a/components/profile_service/profile_app.h b/components/profile_service/profile_app.h
index 12f0d4e..8da3f56 100644
--- a/components/profile_service/profile_app.h
+++ b/components/profile_service/profile_app.h
@@ -56,8 +56,7 @@
  private:
   // |ShellClient| override:
   void Initialize(mojo::Connector* connector,
-                  const std::string& url,
-                  const std::string& user_id,
+                  const mojo::Identity& identity,
                   uint32_t id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
diff --git a/components/resource_provider/resource_provider_app.cc b/components/resource_provider/resource_provider_app.cc
index 43412393..cd16a98894 100644
--- a/components/resource_provider/resource_provider_app.cc
+++ b/components/resource_provider/resource_provider_app.cc
@@ -22,15 +22,14 @@
 }
 
 void ResourceProviderApp::Initialize(mojo::Connector* connector,
-                                     const std::string& url,
-                                     const std::string& user_id,
+                                     const mojo::Identity& identity,
                                      uint32_t id) {
-  tracing_.Initialize(connector, url);
+  tracing_.Initialize(connector, identity.name());
 }
 
 bool ResourceProviderApp::AcceptConnection(mojo::Connection* connection) {
   const base::FilePath app_path(
-      GetPathForApplicationName(connection->GetRemoteApplicationName()));
+      GetPathForApplicationName(connection->GetRemoteIdentity().name()));
   if (app_path.empty())
     return false;  // The specified app has no resources.
 
@@ -42,7 +41,7 @@
     mojo::Connection* connection,
     mojo::InterfaceRequest<ResourceProvider> request) {
   const base::FilePath app_path(
-      GetPathForApplicationName(connection->GetRemoteApplicationName()));
+      GetPathForApplicationName(connection->GetRemoteIdentity().name()));
   // We validated path at AcceptConnection() time, so it should still
   // be valid.
   CHECK(!app_path.empty());
diff --git a/components/resource_provider/resource_provider_app.h b/components/resource_provider/resource_provider_app.h
index 14b867a..10f7602 100644
--- a/components/resource_provider/resource_provider_app.h
+++ b/components/resource_provider/resource_provider_app.h
@@ -25,8 +25,8 @@
 
  private:
   // mojo::ShellClient:
-  void Initialize(mojo::Connector* connector, const std::string& url,
-                  const std::string& user_id, uint32_t id) override;
+  void Initialize(mojo::Connector* connector, const mojo::Identity& identity,
+                  uint32_t id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
   // mojo::InterfaceFactory<ResourceProvider>:
diff --git a/content/browser/accessibility/accessibility_event_recorder_win.cc b/content/browser/accessibility/accessibility_event_recorder_win.cc
index fa76749..cb40bfb 100644
--- a/content/browser/accessibility/accessibility_event_recorder_win.cc
+++ b/content/browser/accessibility/accessibility_event_recorder_win.cc
@@ -287,7 +287,7 @@
   if (accessibility_hwnd != hwnd)
     return E_FAIL;
 
-  IAccessible* obj = manager_->GetRoot()->ToBrowserAccessibilityWin();
+  IAccessible* obj = ToBrowserAccessibilityWin(manager_->GetRoot());
   obj->AddRef();
   *ppv_object = obj;
   return S_OK;
diff --git a/content/browser/accessibility/accessibility_tree_formatter_auralinux.cc b/content/browser/accessibility/accessibility_tree_formatter_auralinux.cc
index 4ebb1c0..ef954c9 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_auralinux.cc
+++ b/content/browser/accessibility/accessibility_tree_formatter_auralinux.cc
@@ -46,8 +46,7 @@
     base::DictionaryValue* dict) {
   dict->SetInteger("id", node.GetId());
   BrowserAccessibilityAuraLinux* acc_obj =
-      const_cast<BrowserAccessibility*>(&node)
-          ->ToBrowserAccessibilityAuraLinux();
+      ToBrowserAccessibilityAuraLinux(const_cast<BrowserAccessibility*>(&node));
 
   AtkObject* atk_object = acc_obj->GetAtkObject();
   AtkRole role = acc_obj->atk_role();
diff --git a/content/browser/accessibility/accessibility_tree_formatter_mac.mm b/content/browser/accessibility/accessibility_tree_formatter_mac.mm
index 2c08e72..48b9d88 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_mac.mm
+++ b/content/browser/accessibility/accessibility_tree_formatter_mac.mm
@@ -42,14 +42,14 @@
   // confusing, convert it to local window coordinates using the top-left
   // corner when dumping the position.
   BrowserAccessibility* root = node.manager()->GetRootManager()->GetRoot();
-  BrowserAccessibilityCocoa* cocoa_root = root->ToBrowserAccessibilityCocoa();
+  BrowserAccessibilityCocoa* cocoa_root = ToBrowserAccessibilityCocoa(root);
   NSPoint root_position = [[cocoa_root position] pointValue];
   NSSize root_size = [[cocoa_root size] sizeValue];
   int root_top = -static_cast<int>(root_position.y + root_size.height);
   int root_left = static_cast<int>(root_position.x);
 
   BrowserAccessibilityCocoa* cocoa_node =
-      const_cast<BrowserAccessibility*>(&node)->ToBrowserAccessibilityCocoa();
+      ToBrowserAccessibilityCocoa(const_cast<BrowserAccessibility*>(&node));
   NSPoint node_position = [[cocoa_node position] pointValue];
   NSSize node_size = [[cocoa_node size] sizeValue];
 
@@ -221,7 +221,7 @@
     base::DictionaryValue* dict) {
   dict->SetInteger("id", node.GetId());
   BrowserAccessibilityCocoa* cocoa_node =
-      const_cast<BrowserAccessibility*>(&node)->ToBrowserAccessibilityCocoa();
+      ToBrowserAccessibilityCocoa(const_cast<BrowserAccessibility*>(&node));
   NSArray* supportedAttributes = [cocoa_node accessibilityAttributeNames];
 
   string role = SysNSStringToUTF8(
diff --git a/content/browser/accessibility/accessibility_tree_formatter_win.cc b/content/browser/accessibility/accessibility_tree_formatter_win.cc
index 6947938..c799846 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_win.cc
+++ b/content/browser/accessibility/accessibility_tree_formatter_win.cc
@@ -157,7 +157,7 @@
     const BrowserAccessibility& node, base::DictionaryValue* dict) {
   dict->SetInteger("id", node.GetId());
   BrowserAccessibilityWin* ax_object =
-      const_cast<BrowserAccessibility*>(&node)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(const_cast<BrowserAccessibility*>(&node));
   DCHECK(ax_object);
 
   VARIANT variant_self;
@@ -247,7 +247,7 @@
   LONG root_left, root_top, root_width, root_height;
   if (SUCCEEDED(ax_object->accLocation(
           &left, &top, &width, &height, variant_self)) &&
-      SUCCEEDED(root->ToBrowserAccessibilityWin()->accLocation(
+      SUCCEEDED(ToBrowserAccessibilityWin(root)->accLocation(
           &root_left, &root_top, &root_width, &root_height, variant_self))) {
     base::DictionaryValue* location = new base::DictionaryValue;
     location->SetInteger("x", left - root_left);
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index 7bb165b6..ee3874a 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -15,9 +15,18 @@
 #include "content/browser/accessibility/browser_accessibility_manager.h"
 #include "content/common/accessibility_messages.h"
 #include "ui/accessibility/ax_text_utils.h"
+#include "ui/accessibility/platform/ax_platform_node.h"
 
 namespace content {
 
+namespace {
+
+// Map from unique_id to BrowserAccessibility
+using UniqueIDMap = base::hash_map<int32_t, BrowserAccessibility*>;
+base::LazyInstance<UniqueIDMap> g_unique_id_map = LAZY_INSTANCE_INITIALIZER;
+
+}
+
 #if !defined(PLATFORM_HAS_NATIVE_ACCESSIBILITY_IMPL)
 // static
 BrowserAccessibility* BrowserAccessibility::Create() {
@@ -27,10 +36,23 @@
 
 BrowserAccessibility::BrowserAccessibility()
     : manager_(NULL),
-      node_(NULL) {
+      node_(NULL),
+      unique_id_(ui::AXPlatformNode::GetNextUniqueId()) {
+  g_unique_id_map.Get()[unique_id_] = this;
 }
 
 BrowserAccessibility::~BrowserAccessibility() {
+  if (unique_id_)
+    g_unique_id_map.Get().erase(unique_id_);
+}
+
+// static
+BrowserAccessibility* BrowserAccessibility::GetFromUniqueID(int32_t unique_id) {
+  auto iter = g_unique_id_map.Get().find(unique_id);
+  if (iter == g_unique_id_map.Get().end())
+    return nullptr;
+
+  return iter->second;
 }
 
 void BrowserAccessibility::Init(BrowserAccessibilityManager* manager,
@@ -594,6 +616,10 @@
   node_ = NULL;
   manager_ = NULL;
 
+  if (unique_id_)
+    g_unique_id_map.Get().erase(unique_id_);
+  unique_id_ = 0;
+
   NativeReleaseReference();
 }
 
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h
index edef50d..b2f14f9 100644
--- a/content/browser/accessibility/browser_accessibility.h
+++ b/content/browser/accessibility/browser_accessibility.h
@@ -75,6 +75,8 @@
 
   virtual ~BrowserAccessibility();
 
+  static BrowserAccessibility* GetFromUniqueID(int32_t unique_id);
+
   // Called only once, immediately after construction. The constructor doesn't
   // take any arguments because in the Windows subclass we use a special
   // function to construct a COM object.
@@ -194,6 +196,7 @@
   BrowserAccessibilityManager* manager() const { return manager_; }
   bool instance_active() const { return node_ != NULL; }
   ui::AXNode* node() const { return node_; }
+  int32_t unique_id() const { return unique_id_; }
 
   // These access the internal accessibility tree, which doesn't necessarily
   // reflect the accessibility tree that should be exposed on each platform.
@@ -220,17 +223,6 @@
   // IsNative returns false.
   virtual bool IsNative() const;
 
-#if defined(OS_MACOSX) && __OBJC__
-  const BrowserAccessibilityCocoa* ToBrowserAccessibilityCocoa() const;
-  BrowserAccessibilityCocoa* ToBrowserAccessibilityCocoa();
-#elif defined(OS_WIN)
-  const BrowserAccessibilityWin* ToBrowserAccessibilityWin() const;
-  BrowserAccessibilityWin* ToBrowserAccessibilityWin();
-#elif defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_X11)
-  const BrowserAccessibilityAuraLinux* ToBrowserAccessibilityAuraLinux() const;
-  BrowserAccessibilityAuraLinux* ToBrowserAccessibilityAuraLinux();
-#endif
-
   // Accessing accessibility attributes:
   //
   // There are dozens of possible attributes for an accessibility node,
@@ -328,6 +320,9 @@
   // The underlying node.
   ui::AXNode* node_;
 
+  // A unique ID, since node IDs are frame-local.
+  int32_t unique_id_;
+
  private:
   // |GetInnerText| recursively includes all the text from descendants such as
   // text found in any embedded object. In contrast, |GetText| might include a
diff --git a/content/browser/accessibility/browser_accessibility_auralinux.cc b/content/browser/accessibility/browser_accessibility_auralinux.cc
index 6b5a4f97..231a3dd7 100644
--- a/content/browser/accessibility/browser_accessibility_auralinux.cc
+++ b/content/browser/accessibility/browser_accessibility_auralinux.cc
@@ -23,6 +23,18 @@
   return atk_object->m_object;
 }
 
+const BrowserAccessibilityAuraLinux* ToBrowserAccessibilityAuraLinux(
+    const BrowserAccessibility* obj) {
+  DCHECK(!obj || obj->IsNative());
+  return static_cast<const BrowserAccessibilityAuraLinux*>(obj);
+}
+
+BrowserAccessibilityAuraLinux* ToBrowserAccessibilityAuraLinux(
+    BrowserAccessibility* obj) {
+  DCHECK(!obj || obj->IsNative());
+  return static_cast<BrowserAccessibilityAuraLinux*>(obj);
+}
+
 //
 // AtkAction interface.
 //
@@ -140,7 +152,7 @@
     return NULL;
 
   AtkObject* atk_result =
-      result->ToBrowserAccessibilityAuraLinux()->GetAtkObject();
+      ToBrowserAccessibilityAuraLinux(result)->GetAtkObject();
   g_object_ref(atk_result);
   return atk_result;
 }
@@ -474,7 +486,7 @@
   if (!obj)
     return NULL;
   if (obj->GetParent())
-    return obj->GetParent()->ToBrowserAccessibilityAuraLinux()->GetAtkObject();
+    return ToBrowserAccessibilityAuraLinux(obj->GetParent())->GetAtkObject();
 
   BrowserAccessibilityManagerAuraLinux* manager =
       static_cast<BrowserAccessibilityManagerAuraLinux*>(obj->manager());
@@ -500,9 +512,8 @@
   if (index < 0 || index >= static_cast<gint>(obj->PlatformChildCount()))
     return NULL;
 
-  AtkObject* result = obj->InternalGetChild(index)
-                          ->ToBrowserAccessibilityAuraLinux()
-                          ->GetAtkObject();
+  AtkObject* result = ToBrowserAccessibilityAuraLinux(
+      obj->InternalGetChild(index))->GetAtkObject();
   g_object_ref(result);
   return result;
 }
@@ -735,16 +746,6 @@
   return new BrowserAccessibilityAuraLinux();
 }
 
-const BrowserAccessibilityAuraLinux*
-BrowserAccessibility::ToBrowserAccessibilityAuraLinux() const {
-  return static_cast<const BrowserAccessibilityAuraLinux*>(this);
-}
-
-BrowserAccessibilityAuraLinux*
-BrowserAccessibility::ToBrowserAccessibilityAuraLinux() {
-  return static_cast<BrowserAccessibilityAuraLinux*>(this);
-}
-
 BrowserAccessibilityAuraLinux::BrowserAccessibilityAuraLinux()
     : atk_object_(NULL) {
 }
@@ -782,7 +783,7 @@
     if (this->GetParent()) {
       atk_object_set_parent(
           atk_object_,
-          this->GetParent()->ToBrowserAccessibilityAuraLinux()->GetAtkObject());
+          ToBrowserAccessibilityAuraLinux(this->GetParent())->GetAtkObject());
     }
   }
 }
diff --git a/content/browser/accessibility/browser_accessibility_auralinux.h b/content/browser/accessibility/browser_accessibility_auralinux.h
index 43a9c3f..773e79f 100644
--- a/content/browser/accessibility/browser_accessibility_auralinux.h
+++ b/content/browser/accessibility/browser_accessibility_auralinux.h
@@ -10,6 +10,7 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "content/browser/accessibility/browser_accessibility.h"
+#include "content/common/content_export.h"
 
 namespace content {
 
@@ -88,6 +89,12 @@
   DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityAuraLinux);
 };
 
+CONTENT_EXPORT const BrowserAccessibilityAuraLinux*
+ToBrowserAccessibilityAuraLinux(const BrowserAccessibility* obj);
+
+CONTENT_EXPORT BrowserAccessibilityAuraLinux* ToBrowserAccessibilityAuraLinux(
+    BrowserAccessibility* obj);
+
 }  // namespace content
 
 #endif  // CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_AURALINUX_H_
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index 947575e..80af6fd3 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -16,6 +16,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "content/app/strings/grit/content_strings.h"
+#include "content/browser/accessibility/browser_accessibility_mac.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
 #include "content/browser/accessibility/browser_accessibility_manager_mac.h"
 #include "content/browser/accessibility/one_shot_accessibility_tree_search.h"
@@ -539,8 +540,8 @@
     children_.reset([[NSMutableArray alloc] initWithCapacity:childCount]);
     for (uint32_t index = 0; index < childCount; ++index) {
       BrowserAccessibilityCocoa* child =
-          browserAccessibility_->PlatformGetChild(index)->
-              ToBrowserAccessibilityCocoa();
+          ToBrowserAccessibilityCocoa(
+              browserAccessibility_->PlatformGetChild(index));
       if ([child isIgnored])
         [children_ addObjectsFromArray:[child children]];
       else
@@ -560,7 +561,7 @@
       // a DCHECK in the future.
       if (child) {
         BrowserAccessibilityCocoa* child_cocoa =
-            child->ToBrowserAccessibilityCocoa();
+            ToBrowserAccessibilityCocoa(child);
         [children_ addObject:child_cocoa];
       }
     }
@@ -572,8 +573,8 @@
   if (![self isIgnored]) {
     children_.reset();
   } else {
-    [browserAccessibility_->GetParent()->ToBrowserAccessibilityCocoa()
-       childrenChanged];
+    [ToBrowserAccessibilityCocoa(browserAccessibility_->GetParent())
+         childrenChanged];
   }
 }
 
@@ -591,7 +592,7 @@
     BrowserAccessibility* cell =
         browserAccessibility_->manager()->GetFromID(id);
     if (cell && cell->GetRole() == ui::AX_ROLE_COLUMN_HEADER)
-      [ret addObject:cell->ToBrowserAccessibilityCocoa()];
+      [ret addObject:ToBrowserAccessibilityCocoa(cell)];
   }
   return ret;
 }
@@ -807,7 +808,7 @@
     BrowserAccessibility* headerObject =
         browserAccessibility_->manager()->GetFromID(headerElementId);
     if (headerObject)
-      return headerObject->ToBrowserAccessibilityCocoa();
+      return ToBrowserAccessibilityCocoa(headerObject);
   }
   return nil;
 }
@@ -896,7 +897,7 @@
     BrowserAccessibility* element =
         browserAccessibility_->manager()->GetFromID(attributeValues[i]);
     if (element)
-      [outArray addObject:element->ToBrowserAccessibilityCocoa()];
+      [outArray addObject:ToBrowserAccessibilityCocoa(element)];
   }
 }
 
@@ -957,7 +958,7 @@
   // A nil parent means we're the root.
   if (browserAccessibility_->GetParent()) {
     return NSAccessibilityUnignoredAncestor(
-        browserAccessibility_->GetParent()->ToBrowserAccessibilityCocoa());
+        ToBrowserAccessibilityCocoa(browserAccessibility_->GetParent()));
   } else {
     // Hook back up to RenderWidgetHostViewCocoa.
     BrowserAccessibilityManagerMac* manager =
@@ -1185,7 +1186,7 @@
     BrowserAccessibility* cell =
         browserAccessibility_->manager()->GetFromID(id);
     if (cell && cell->GetRole() == ui::AX_ROLE_ROW_HEADER)
-      [ret addObject:cell->ToBrowserAccessibilityCocoa()];
+      [ret addObject:ToBrowserAccessibilityCocoa(cell)];
   }
   return ret;
 }
@@ -1223,7 +1224,7 @@
       BrowserAccessibility* rowElement =
           browserAccessibility_->manager()->GetFromID(id);
       if (rowElement)
-        [ret addObject:rowElement->ToBrowserAccessibilityCocoa()];
+        [ret addObject:ToBrowserAccessibilityCocoa(rowElement)];
     }
   }
 
@@ -1242,7 +1243,7 @@
   if (!GetState(browserAccessibility_, ui::AX_STATE_MULTISELECTABLE)) {
     // First try the focused child.
     if (focusedChild && focusedChild != browserAccessibility_) {
-      [ret addObject:focusedChild->ToBrowserAccessibilityCocoa()];
+      [ret addObject:ToBrowserAccessibilityCocoa(focusedChild)];
       return ret;
     }
 
@@ -1253,7 +1254,7 @@
       BrowserAccessibility* activeDescendant =
           manager->GetFromID(activeDescendantId);
       if (activeDescendant) {
-        [ret addObject:activeDescendant->ToBrowserAccessibilityCocoa()];
+        [ret addObject:ToBrowserAccessibilityCocoa(activeDescendant)];
         return ret;
       }
     }
@@ -1267,14 +1268,14 @@
     BrowserAccessibility* child =
       browserAccessibility_->PlatformGetChild(index);
     if (child->HasState(ui::AX_STATE_SELECTED))
-      [ret addObject:child->ToBrowserAccessibilityCocoa()];
+      [ret addObject:ToBrowserAccessibilityCocoa(child)];
   }
 
   // And if nothing's selected but one has focus, use the focused one.
   if ([ret count] == 0 &&
       focusedChild &&
       focusedChild != browserAccessibility_) {
-    [ret addObject:focusedChild->ToBrowserAccessibilityCocoa()];
+    [ret addObject:ToBrowserAccessibilityCocoa(focusedChild)];
   }
 
   return ret;
@@ -1437,7 +1438,7 @@
     BrowserAccessibility* titleElement =
         browserAccessibility_->manager()->GetFromID(labelledby_ids[0]);
     if (titleElement)
-      return titleElement->ToBrowserAccessibilityCocoa();
+      return ToBrowserAccessibilityCocoa(titleElement);
   }
 
   return nil;
@@ -1539,7 +1540,7 @@
     BrowserAccessibility* cell =
         browserAccessibility_->manager()->GetFromID(id);
     if (cell)
-      [ret addObject:cell->ToBrowserAccessibilityCocoa()];
+      [ret addObject:ToBrowserAccessibilityCocoa(cell)];
   }
   return ret;
 }
@@ -1548,9 +1549,8 @@
   NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease];
   uint32_t childCount = browserAccessibility_->PlatformChildCount();
   for (uint32_t index = 0; index < childCount; ++index) {
-    BrowserAccessibilityCocoa* child =
-        browserAccessibility_->PlatformGetChild(index)->
-            ToBrowserAccessibilityCocoa();
+    BrowserAccessibilityCocoa* child = ToBrowserAccessibilityCocoa(
+        browserAccessibility_->PlatformGetChild(index));
     [ret addObject:child];
   }
   return ret;
@@ -1737,7 +1737,7 @@
           continue;
         }
         if (colIndex == column)
-          return cell->ToBrowserAccessibilityCocoa();
+          return ToBrowserAccessibilityCocoa(cell);
         if (colIndex > column)
           break;
       }
@@ -1749,7 +1749,7 @@
     BrowserAccessibility* object;
     int offset;
     if (GetTextMarkerData(parameter, &object, &offset))
-      return object->ToBrowserAccessibilityCocoa();
+      return ToBrowserAccessibilityCocoa(object);
 
     return nil;
   }
@@ -1864,7 +1864,7 @@
       NSMutableArray* result = [NSMutableArray arrayWithCapacity:count];
       for (size_t i = 0; i < count; ++i) {
         BrowserAccessibility* match = search.GetMatchAtIndex(i);
-        [result addObject:match->ToBrowserAccessibilityCocoa()];
+        [result addObject:ToBrowserAccessibilityCocoa(match)];
       }
       return result;
     }
diff --git a/content/browser/accessibility/browser_accessibility_mac.h b/content/browser/accessibility/browser_accessibility_mac.h
index aed8fd4..d516024 100644
--- a/content/browser/accessibility/browser_accessibility_mac.h
+++ b/content/browser/accessibility/browser_accessibility_mac.h
@@ -11,11 +11,19 @@
 
 #include "base/macros.h"
 #include "content/browser/accessibility/browser_accessibility.h"
+#include "content/common/content_export.h"
 
 @class BrowserAccessibilityCocoa;
 
 namespace content {
 
+#if __OBJC__
+CONTENT_EXPORT const BrowserAccessibilityCocoa* ToBrowserAccessibilityCocoa(
+    const BrowserAccessibility* obj);
+CONTENT_EXPORT BrowserAccessibilityCocoa* ToBrowserAccessibilityCocoa(
+    BrowserAccessibility* obj);
+#endif
+
 class BrowserAccessibilityMac : public BrowserAccessibility {
  public:
   // BrowserAccessibility overrides.
diff --git a/content/browser/accessibility/browser_accessibility_mac.mm b/content/browser/accessibility/browser_accessibility_mac.mm
index da1f55e..34475bd 100644
--- a/content/browser/accessibility/browser_accessibility_mac.mm
+++ b/content/browser/accessibility/browser_accessibility_mac.mm
@@ -64,13 +64,17 @@
 }
 
 const BrowserAccessibilityCocoa*
-BrowserAccessibility::ToBrowserAccessibilityCocoa() const {
-  return static_cast<const BrowserAccessibilityMac*>(this)->native_view();
+ToBrowserAccessibilityCocoa(const BrowserAccessibility* obj) {
+  DCHECK(obj);
+  DCHECK(obj->IsNative());
+  return static_cast<const BrowserAccessibilityMac*>(obj)->native_view();
 }
 
-BrowserAccessibilityCocoa* BrowserAccessibility::ToBrowserAccessibilityCocoa() {
-  return static_cast<BrowserAccessibilityMac*>(this)->
-      native_view();
+BrowserAccessibilityCocoa* ToBrowserAccessibilityCocoa(
+    BrowserAccessibility* obj) {
+  DCHECK(obj);
+  DCHECK(obj->IsNative());
+  return static_cast<BrowserAccessibilityMac*>(obj)->native_view();
 }
 
 }  // namespace content
diff --git a/content/browser/accessibility/browser_accessibility_mac_unittest.mm b/content/browser/accessibility/browser_accessibility_mac_unittest.mm
index c85957f..0b2511d 100644
--- a/content/browser/accessibility/browser_accessibility_mac_unittest.mm
+++ b/content/browser/accessibility/browser_accessibility_mac_unittest.mm
@@ -8,6 +8,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "content/browser/accessibility/browser_accessibility_cocoa.h"
+#include "content/browser/accessibility/browser_accessibility_mac.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
 #include "content/browser/accessibility/browser_accessibility_manager_mac.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -53,7 +54,7 @@
             nil,
             MakeAXTreeUpdate(root, child1, child2),
             NULL));
-    accessibility_.reset([manager_->GetRoot()->ToBrowserAccessibilityCocoa()
+    accessibility_.reset([ToBrowserAccessibilityCocoa(manager_->GetRoot())
         retain]);
   }
 
diff --git a/content/browser/accessibility/browser_accessibility_manager_android.cc b/content/browser/accessibility/browser_accessibility_manager_android.cc
index 9c7a316..e527963 100644
--- a/content/browser/accessibility/browser_accessibility_manager_android.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_android.cc
@@ -208,32 +208,32 @@
   // the Android system that the accessibility hierarchy rooted at this
   // node has changed.
   Java_BrowserAccessibilityManager_handleContentChanged(
-      env, obj.obj(), node->GetId());
+      env, obj.obj(), node->unique_id());
 
   switch (event_type) {
     case ui::AX_EVENT_LOAD_COMPLETE:
       Java_BrowserAccessibilityManager_handlePageLoaded(
-          env, obj.obj(), GetFocus()->GetId());
+          env, obj.obj(), GetFocus()->unique_id());
       break;
     case ui::AX_EVENT_FOCUS:
       Java_BrowserAccessibilityManager_handleFocusChanged(
-          env, obj.obj(), node->GetId());
+          env, obj.obj(), node->unique_id());
       break;
     case ui::AX_EVENT_CHECKED_STATE_CHANGED:
       Java_BrowserAccessibilityManager_handleCheckStateChanged(
-          env, obj.obj(), node->GetId());
+          env, obj.obj(), node->unique_id());
       break;
     case ui::AX_EVENT_CLICKED:
       Java_BrowserAccessibilityManager_handleClicked(env, obj.obj(),
-                                                     node->GetId());
+                                                     node->unique_id());
       break;
     case ui::AX_EVENT_SCROLL_POSITION_CHANGED:
       Java_BrowserAccessibilityManager_handleScrollPositionChanged(
-          env, obj.obj(), node->GetId());
+          env, obj.obj(), node->unique_id());
       break;
     case ui::AX_EVENT_SCROLLED_TO_ANCHOR:
       Java_BrowserAccessibilityManager_handleScrolledToAnchor(
-          env, obj.obj(), node->GetId());
+          env, obj.obj(), node->unique_id());
       break;
     case ui::AX_EVENT_ALERT:
       // An alert is a special case of live region. Fall through to the
@@ -249,16 +249,16 @@
     }
     case ui::AX_EVENT_TEXT_SELECTION_CHANGED:
       Java_BrowserAccessibilityManager_handleTextSelectionChanged(
-          env, obj.obj(), node->GetId());
+          env, obj.obj(), node->unique_id());
       break;
     case ui::AX_EVENT_TEXT_CHANGED:
     case ui::AX_EVENT_VALUE_CHANGED:
       if (android_node->IsEditableText() && GetFocus() == node) {
         Java_BrowserAccessibilityManager_handleEditableTextChanged(
-            env, obj.obj(), node->GetId());
+            env, obj.obj(), node->unique_id());
       } else if (android_node->IsSlider()) {
         Java_BrowserAccessibilityManager_handleSliderChanged(
-            env, obj.obj(), node->GetId());
+            env, obj.obj(), node->unique_id());
       }
       break;
     default:
@@ -291,7 +291,7 @@
     JNIEnv* env,
     const JavaParamRef<jobject>& obj) {
   if (GetRoot())
-    return static_cast<jint>(GetRoot()->GetId());
+    return static_cast<jint>(GetRoot()->unique_id());
   else
     return -1;
 }
@@ -300,7 +300,7 @@
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
     jint id) {
-  return GetFromID(id) != NULL;
+  return GetFromUniqueID(id) != NULL;
 }
 
 void BrowserAccessibilityManagerAndroid::HitTest(
@@ -316,8 +316,7 @@
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
     jint id) {
-  BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>(
-      GetFromID(id));
+  BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
   if (!node)
     return false;
 
@@ -328,8 +327,7 @@
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
     jint id) {
-  BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>(
-      GetFromID(id));
+  BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
   if (!node)
     return false;
 
@@ -340,8 +338,7 @@
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
     jint id) {
-  BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>(
-      GetFromID(id));
+  BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
   if (!node)
     return false;
 
@@ -353,18 +350,17 @@
     const JavaParamRef<jobject>& obj,
     const JavaParamRef<jobject>& info,
     jint id) {
-  BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>(
-      GetFromID(id));
+  BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
   if (!node)
     return false;
 
   if (node->GetParent()) {
     Java_BrowserAccessibilityManager_setAccessibilityNodeInfoParent(
-        env, obj, info, node->GetParent()->GetId());
+        env, obj, info, node->GetParent()->unique_id());
   }
   for (unsigned i = 0; i < node->PlatformChildCount(); ++i) {
     Java_BrowserAccessibilityManager_addAccessibilityNodeInfoChild(
-        env, obj, info, node->InternalGetChild(i)->GetId());
+        env, obj, info, node->InternalGetChild(i)->unique_id());
   }
   Java_BrowserAccessibilityManager_setAccessibilityNodeInfoBooleanAttributes(
       env, obj, info,
@@ -472,8 +468,7 @@
     const JavaParamRef<jobject>& event,
     jint id,
     jint event_type) {
-  BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>(
-      GetFromID(id));
+  BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
   if (!node)
     return false;
 
@@ -575,7 +570,7 @@
 void BrowserAccessibilityManagerAndroid::Click(JNIEnv* env,
                                                const JavaParamRef<jobject>& obj,
                                                jint id) {
-  BrowserAccessibility* node = GetFromID(id);
+  BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
   if (node)
     DoDefaultAction(*node);
 }
@@ -583,7 +578,7 @@
 void BrowserAccessibilityManagerAndroid::Focus(JNIEnv* env,
                                                const JavaParamRef<jobject>& obj,
                                                jint id) {
-  BrowserAccessibility* node = GetFromID(id);
+  BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
   if (node)
     SetFocus(*node);
 }
@@ -598,7 +593,7 @@
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
     jint id) {
-  BrowserAccessibility* node = GetFromID(id);
+  BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
   if (node)
     ScrollToMakeVisible(*node, gfx::Rect(node->GetLocation().size()));
 }
@@ -608,7 +603,7 @@
     const JavaParamRef<jobject>& obj,
     jint id,
     const JavaParamRef<jstring>& value) {
-  BrowserAccessibility* node = GetFromID(id);
+  BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
   if (node) {
     BrowserAccessibilityManager::SetValue(
         *node, base::android::ConvertJavaStringToUTF16(env, value));
@@ -621,7 +616,7 @@
     jint id,
     jint start,
     jint end) {
-  BrowserAccessibility* node = GetFromID(id);
+  BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
   if (node)
     SetTextSelection(*node, start, end);
 }
@@ -631,7 +626,7 @@
     const JavaParamRef<jobject>& obj,
     jint id,
     jboolean increment) {
-  BrowserAccessibility* node = GetFromID(id);
+  BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
   if (!node)
     return false;
 
@@ -681,7 +676,7 @@
   }
 
   Java_BrowserAccessibilityManager_handleHover(
-      env, obj.obj(), node->GetId());
+      env, obj.obj(), node->unique_id());
 }
 
 jint BrowserAccessibilityManagerAndroid::FindElementType(
@@ -690,7 +685,7 @@
     jint start_id,
     const JavaParamRef<jstring>& element_type_str,
     jboolean forwards) {
-  BrowserAccessibility* start_node = GetFromID(start_id);
+  BrowserAccessibilityAndroid* start_node = GetFromUniqueID(start_id);
   if (!start_node)
     return 0;
 
@@ -719,7 +714,7 @@
   if (tree_search.CountMatches() == 0)
     return 0;
 
-  return tree_search.GetMatchAtIndex(0)->GetId();
+  return tree_search.GetMatchAtIndex(0)->unique_id();
 }
 
 jboolean BrowserAccessibilityManagerAndroid::NextAtGranularity(
@@ -729,8 +724,7 @@
     jboolean extend_selection,
     jint id,
     jint cursor_index) {
-  BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>(
-      GetFromID(id));
+  BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
   if (!node)
     return false;
 
@@ -759,8 +753,7 @@
     jboolean extend_selection,
     jint id,
     jint cursor_index) {
-  BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>(
-      GetFromID(id));
+  BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
   if (!node)
     return false;
 
@@ -880,8 +873,7 @@
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
     jint id) {
-  BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>(
-      GetFromID(id));
+  BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
   if (!node)
     return false;
 
@@ -893,8 +885,7 @@
     const JavaParamRef<jobject>& obj,
     jint id,
     int direction) {
-  BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>(
-      GetFromID(id));
+  BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
   if (!node)
     return false;
 
@@ -921,6 +912,12 @@
   return false;
 }
 
+BrowserAccessibilityAndroid*
+BrowserAccessibilityManagerAndroid::GetFromUniqueID(int32_t unique_id) {
+  return static_cast<BrowserAccessibilityAndroid*>(
+      BrowserAccessibility::GetFromUniqueID(unique_id));
+}
+
 bool RegisterBrowserAccessibilityManager(JNIEnv* env) {
   return RegisterNativesImpl(env);
 }
diff --git a/content/browser/accessibility/browser_accessibility_manager_android.h b/content/browser/accessibility/browser_accessibility_manager_android.h
index 4bc42b5..816bf0c7 100644
--- a/content/browser/accessibility/browser_accessibility_manager_android.h
+++ b/content/browser/accessibility/browser_accessibility_manager_android.h
@@ -224,6 +224,8 @@
   bool UseRootScrollOffsetsWhenComputingBounds() override;
 
  private:
+  BrowserAccessibilityAndroid* GetFromUniqueID(int32_t unique_id);
+
   // This gives BrowserAccessibilityManager::Create access to the class
   // constructor.
   friend class BrowserAccessibilityManager;
diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.mm b/content/browser/accessibility/browser_accessibility_manager_mac.mm
index 712de43..0df142e5 100644
--- a/content/browser/accessibility/browser_accessibility_manager_mac.mm
+++ b/content/browser/accessibility/browser_accessibility_manager_mac.mm
@@ -140,7 +140,7 @@
     }
   }
 
-  auto native_node = node->ToBrowserAccessibilityCocoa();
+  auto native_node = ToBrowserAccessibilityCocoa(node);
   DCHECK(native_node);
 
   // Refer to |AXObjectCache::postPlatformNotification| in WebKit source code.
@@ -187,7 +187,7 @@
       BrowserAccessibility* focus = GetFocus();
       if (!focus)
         break;
-      NSAccessibilityPostNotification(focus->ToBrowserAccessibilityCocoa(),
+      NSAccessibilityPostNotification(ToBrowserAccessibilityCocoa(focus),
                                       mac_notification);
 
       if (base::mac::IsOSElCapitanOrLater()) {
@@ -203,9 +203,9 @@
           return;
 
         NSAccessibilityPostNotificationWithUserInfo(
-            focus->ToBrowserAccessibilityCocoa(), mac_notification, user_info);
+            ToBrowserAccessibilityCocoa(focus), mac_notification, user_info);
         NSAccessibilityPostNotificationWithUserInfo(
-            root->ToBrowserAccessibilityCocoa(), mac_notification, user_info);
+            ToBrowserAccessibilityCocoa(root), mac_notification, user_info);
         return;
       }
       break;
@@ -318,7 +318,7 @@
   BrowserAccessibility* focus_object = GetFromID(focus_id);
   if (focus_object) {
     focus_object = focus_object->GetClosestPlatformObject();
-    auto native_focus_object = focus_object->ToBrowserAccessibilityCocoa();
+    auto native_focus_object = ToBrowserAccessibilityCocoa(focus_object);
     if (native_focus_object) {
       [user_info setObject:[native_focus_object selectedTextMarkerRange]
                     forKey:NSAccessibilitySelectedTextMarkerRangeAttribute];
diff --git a/content/browser/accessibility/browser_accessibility_manager_win.cc b/content/browser/accessibility/browser_accessibility_manager_win.cc
index a60b749..7c2165cb 100644
--- a/content/browser/accessibility/browser_accessibility_manager_win.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_win.cc
@@ -20,10 +20,6 @@
 
 namespace content {
 
-// Map from unique_id_win to BrowserAccessibility
-using UniqueIDWinMap = base::hash_map<LONG, BrowserAccessibility*>;
-base::LazyInstance<UniqueIDWinMap> g_unique_id_map = LAZY_INSTANCE_INITIALIZER;
-
 // static
 BrowserAccessibilityManager* BrowserAccessibilityManager::Create(
     const ui::AXTreeUpdate& initial_tree,
@@ -149,7 +145,11 @@
   else if (focus_event_on_root_needed_)
     OnWindowFocused();
 
-  LONG child_id = node->ToBrowserAccessibilityWin()->unique_id_win();
+  // Pass the negation of this node's unique id in the |child_id|
+  // argument to NotifyWinEvent; the AT client will then call get_accChild
+  // on the HWND's accessibility object and pass it that same id, which
+  // we can use to retrieve the IAccessible for this node.
+  LONG child_id = -node->unique_id();
   ::NotifyWinEvent(event, hwnd, OBJID_CLIENT, child_id);
 }
 
@@ -293,13 +293,9 @@
   if (!node)
     return;
 
-  if (event_id != EVENT_MIN) {
-    // Pass the node's unique id in the |child_id| argument to NotifyWinEvent;
-    // the AT client will then call get_accChild on the HWND's accessibility
-    // object and pass it that same id, which we can use to retrieve the
-    // IAccessible for this node.
+  if (event_id != EVENT_MIN)
     MaybeCallNotifyWinEvent(event_id, node);
-  }
+
 
   // If this is a layout complete notification (sent when a container scrolls)
   // and there is a descendant tracked object, send a notification on it.
@@ -323,8 +319,6 @@
     return;
   if (!obj->IsNative())
     return;
-  LONG unique_id_win = obj->ToBrowserAccessibilityWin()->unique_id_win();
-  g_unique_id_map.Get()[unique_id_win] = obj;
 }
 
 void BrowserAccessibilityManagerWin::OnNodeWillBeDeleted(ui::AXTree* tree,
@@ -332,8 +326,6 @@
   DCHECK(node);
   BrowserAccessibility* obj = GetFromAXNode(node);
   if (obj && obj->IsNative()) {
-    g_unique_id_map.Get().erase(
-        obj->ToBrowserAccessibilityWin()->unique_id_win());
     if (obj == tracked_scroll_object_) {
       tracked_scroll_object_->Release();
       tracked_scroll_object_ = NULL;
@@ -367,7 +359,7 @@
     DCHECK(changed_node);
     BrowserAccessibility* obj = GetFromAXNode(changed_node);
     if (obj && obj->IsNative() && !obj->PlatformIsChildOfLeaf())
-      obj->ToBrowserAccessibilityWin()->UpdateStep1ComputeWinAttributes();
+      ToBrowserAccessibilityWin(obj)->UpdateStep1ComputeWinAttributes();
   }
 
   // The next step updates the hypertext of each node, which is a
@@ -378,7 +370,7 @@
     DCHECK(changed_node);
     BrowserAccessibility* obj = GetFromAXNode(changed_node);
     if (obj && obj->IsNative() && !obj->PlatformIsChildOfLeaf())
-      obj->ToBrowserAccessibilityWin()->UpdateStep2ComputeHypertext();
+      ToBrowserAccessibilityWin(obj)->UpdateStep2ComputeHypertext();
   }
 
   // The third step fires events on nodes based on what's changed - like
@@ -394,7 +386,7 @@
     DCHECK(changed_node);
     BrowserAccessibility* obj = GetFromAXNode(changed_node);
     if (obj && obj->IsNative() && !obj->PlatformIsChildOfLeaf()) {
-      obj->ToBrowserAccessibilityWin()->UpdateStep3FireEvents(
+      ToBrowserAccessibilityWin(obj)->UpdateStep3FireEvents(
           changes[i].type == AXTreeDelegate::SUBTREE_CREATED);
     }
   }
@@ -408,13 +400,4 @@
   tracked_scroll_object_->AddRef();
 }
 
-BrowserAccessibilityWin* BrowserAccessibilityManagerWin::GetFromUniqueIdWin(
-    LONG unique_id_win) {
-  auto iter = g_unique_id_map.Get().find(unique_id_win);
-  if (iter == g_unique_id_map.Get().end())
-    return nullptr;
-
-  return iter->second->ToBrowserAccessibilityWin();
-}
-
 }  // namespace content
diff --git a/content/browser/accessibility/browser_accessibility_manager_win.h b/content/browser/accessibility/browser_accessibility_manager_win.h
index b505a63..be0b5d9 100644
--- a/content/browser/accessibility/browser_accessibility_manager_win.h
+++ b/content/browser/accessibility/browser_accessibility_manager_win.h
@@ -53,10 +53,6 @@
   // TODO(dmazzoni): remove once http://crbug.com/113483 is fixed.
   void TrackScrollingObject(BrowserAccessibilityWin* node);
 
-  // Return a pointer to the object corresponding to the given windows-specific
-  // unique id, does not make a new reference.
-  BrowserAccessibilityWin* GetFromUniqueIdWin(LONG unique_id_win);
-
   // Called when |accessible_hwnd_| is deleted by its parent.
   void OnAccessibleHwndDeleted();
 
diff --git a/content/browser/accessibility/browser_accessibility_win.cc b/content/browser/accessibility/browser_accessibility_win.cc
index a78d8b2..bf3b0af 100644
--- a/content/browser/accessibility/browser_accessibility_win.cc
+++ b/content/browser/accessibility/browser_accessibility_win.cc
@@ -42,10 +42,6 @@
 
 const base::char16 BrowserAccessibilityWin::kEmbeddedCharacter = L'\xfffc';
 
-// static
-LONG BrowserAccessibilityWin::next_unique_id_win_ =
-    base::win::kFirstBrowserAccessibilityManagerAccessibilityId;
-
 //
 // BrowserAccessibilityRelation
 //
@@ -150,7 +146,7 @@
     return E_FAIL;
 
   *target = static_cast<IAccessible*>(
-      result->ToBrowserAccessibilityWin()->NewReference());
+      ToBrowserAccessibilityWin(result)->NewReference());
   return S_OK;
 }
 
@@ -207,29 +203,10 @@
   return instance->NewReference();
 }
 
-const BrowserAccessibilityWin* BrowserAccessibility::ToBrowserAccessibilityWin()
-    const {
-  return static_cast<const BrowserAccessibilityWin*>(this);
-}
-
-BrowserAccessibilityWin* BrowserAccessibility::ToBrowserAccessibilityWin() {
-  return static_cast<BrowserAccessibilityWin*>(this);
-}
-
 BrowserAccessibilityWin::BrowserAccessibilityWin()
     : win_attributes_(new WinAttributes()),
       previous_scroll_x_(0),
       previous_scroll_y_(0) {
-  // Start unique IDs at -1 and decrement each time, because get_accChild
-  // uses positive IDs to enumerate children, so we use negative IDs to
-  // clearly distinguish between indices and unique IDs.
-  unique_id_win_ = next_unique_id_win_;
-  if (next_unique_id_win_ ==
-          base::win::kLastBrowserAccessibilityManagerAccessibilityId) {
-    next_unique_id_win_ =
-        base::win::kFirstBrowserAccessibilityManagerAccessibilityId;
-  }
-  next_unique_id_win_--;
 }
 
 BrowserAccessibilityWin::~BrowserAccessibilityWin() {
@@ -281,7 +258,7 @@
     child->lVal = CHILDID_SELF;
   } else {
     child->vt = VT_DISPATCH;
-    child->pdispVal = result->ToBrowserAccessibilityWin()->NewReference();
+    child->pdispVal = ToBrowserAccessibilityWin(result)->NewReference();
   }
   return S_OK;
 }
@@ -355,7 +332,7 @@
   }
 
   end->vt = VT_DISPATCH;
-  end->pdispVal = result->ToBrowserAccessibilityWin()->NewReference();
+  end->pdispVal = ToBrowserAccessibilityWin(result)->NewReference();
   return S_OK;
 }
 
@@ -511,7 +488,7 @@
   if (!disp_parent)
     return E_INVALIDARG;
 
-  IAccessible* parent_obj = GetParent()->ToBrowserAccessibilityWin();
+  IAccessible* parent_obj = ToBrowserAccessibilityWin(GetParent());
   if (parent_obj == NULL) {
     // This happens if we're the root of the tree;
     // return the IAccessible for the window.
@@ -646,7 +623,7 @@
       if (InternalGetChild(i)->HasState(ui::AX_STATE_SELECTED)) {
         selected->vt = VT_DISPATCH;
         selected->pdispVal =
-            InternalGetChild(i)->ToBrowserAccessibilityWin()->NewReference();
+            ToBrowserAccessibilityWin(InternalGetChild(i))->NewReference();
         return S_OK;
       }
     }
@@ -661,7 +638,7 @@
     if (InternalGetChild(i)->HasState(ui::AX_STATE_SELECTED)) {
       enum_variant->ItemAt(index)->vt = VT_DISPATCH;
       enum_variant->ItemAt(index)->pdispVal =
-        InternalGetChild(i)->ToBrowserAccessibilityWin()->NewReference();
+          ToBrowserAccessibilityWin(InternalGetChild(i))->NewReference();
       ++index;
     }
   }
@@ -751,7 +728,7 @@
   if (!unique_id)
     return E_INVALIDARG;
 
-  *unique_id = unique_id_win_;
+  *unique_id = -unique_id_;
   return S_OK;
 }
 
@@ -1289,7 +1266,7 @@
 
   int cell_id = unique_cell_ids[cell_index];
   BrowserAccessibilityWin* cell =
-      manager()->GetFromID(cell_id)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(manager()->GetFromID(cell_id));
   int col_index;
   if (cell &&
       cell->GetIntAttribute(
@@ -1394,7 +1371,7 @@
   for (int i = 0; i < columns; ++i) {
     int cell_id = cell_ids[row * columns + i];
     BrowserAccessibilityWin* cell =
-        manager()->GetFromID(cell_id)->ToBrowserAccessibilityWin();
+        ToBrowserAccessibilityWin(manager()->GetFromID(cell_id));
     if (cell && cell->GetRole() == ui::AX_ROLE_ROW_HEADER) {
       base::string16 cell_name = cell->GetString16Attribute(
           ui::AX_ATTR_NAME);
@@ -1439,7 +1416,7 @@
       GetIntListAttribute(ui::AX_ATTR_CELL_IDS);
   int cell_id = cell_ids[row * columns + column];
   BrowserAccessibilityWin* cell =
-      manager()->GetFromID(cell_id)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(manager()->GetFromID(cell_id));
   int rowspan;
   if (cell &&
       cell->GetIntAttribute(
@@ -1477,7 +1454,7 @@
 
   int cell_id = unique_cell_ids[cell_index];
   BrowserAccessibilityWin* cell =
-      manager()->GetFromID(cell_id)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(manager()->GetFromID(cell_id));
   int cell_row_index;
   if (cell &&
       cell->GetIntAttribute(
@@ -1606,7 +1583,7 @@
 
   int cell_id = unique_cell_ids[index];
   BrowserAccessibilityWin* cell =
-      manager()->GetFromID(cell_id)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(manager()->GetFromID(cell_id));
   int rowspan;
   int colspan;
   if (cell &&
@@ -1765,7 +1742,7 @@
   for (int i = 0; i < rows; ++i) {
     int cell_id = cell_ids[i * columns + column];
     BrowserAccessibilityWin* cell =
-        manager()->GetFromID(cell_id)->ToBrowserAccessibilityWin();
+        ToBrowserAccessibilityWin(manager()->GetFromID(cell_id));
     if (cell && cell->GetRole() == ui::AX_ROLE_COLUMN_HEADER)
       (*n_column_header_cells)++;
   }
@@ -1778,7 +1755,7 @@
     BrowserAccessibility* cell = manager()->GetFromID(cell_id);
     if (cell && cell->GetRole() == ui::AX_ROLE_COLUMN_HEADER) {
       (*cell_accessibles)[index] = static_cast<IAccessible*>(
-          cell->ToBrowserAccessibilityWin()->NewReference());
+          ToBrowserAccessibilityWin(cell)->NewReference());
       ++index;
     }
   }
@@ -1875,7 +1852,7 @@
     BrowserAccessibility* cell = manager()->GetFromID(cell_id);
     if (cell && cell->GetRole() == ui::AX_ROLE_ROW_HEADER) {
       (*cell_accessibles)[index] = static_cast<IAccessible*>(
-          cell->ToBrowserAccessibilityWin()->NewReference());
+          ToBrowserAccessibilityWin(cell)->NewReference());
       ++index;
     }
   }
@@ -1970,7 +1947,7 @@
   }
 
   *table = static_cast<IAccessibleTable*>(
-      find_table->ToBrowserAccessibilityWin()->NewReference());
+      ToBrowserAccessibilityWin(find_table)->NewReference());
 
   return S_OK;
 }
@@ -2412,7 +2389,7 @@
 
   int32_t id = hyperlinks()[index];
   BrowserAccessibilityWin* child =
-      manager()->GetFromID(id)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(manager()->GetFromID(id));
   if (child) {
     *hyperlink = static_cast<IAccessibleHyperlink*>(child->NewReference());
     return S_OK;
@@ -2510,7 +2487,7 @@
   const auto parent = GetParent();
   if (parent) {
     hypertext_offset =
-        parent->ToBrowserAccessibilityWin()->GetHypertextOffsetFromChild(*this);
+        ToBrowserAccessibilityWin(parent)->GetHypertextOffsetFromChild(*this);
   }
   *index = static_cast<LONG>(hypertext_offset);
   return S_OK;
@@ -2751,7 +2728,7 @@
   *name_space_id = 0;
   *node_value = SysAllocString(value().c_str());
   *num_children = PlatformChildCount();
-  *unique_id = unique_id_win_;
+  *unique_id = -unique_id_;
 
   if (GetRole() == ui::AX_ROLE_ROOT_WEB_AREA ||
     GetRole() == ui::AX_ROLE_WEB_AREA) {
@@ -2889,7 +2866,7 @@
   if (!node)
     return E_INVALIDARG;
 
-  *node = GetParent()->ToBrowserAccessibilityWin()->NewReference();
+  *node = ToBrowserAccessibilityWin(GetParent())->NewReference();
   return S_OK;
 }
 
@@ -2905,7 +2882,7 @@
     return S_FALSE;
   }
 
-  *node = PlatformGetChild(0)->ToBrowserAccessibilityWin()->NewReference();
+  *node = ToBrowserAccessibilityWin(PlatformGetChild(0))->NewReference();
   return S_OK;
 }
 
@@ -2921,8 +2898,8 @@
     return S_FALSE;
   }
 
-  *node = PlatformGetChild(PlatformChildCount() - 1)
-      ->ToBrowserAccessibilityWin()->NewReference();
+  *node = ToBrowserAccessibilityWin(
+      PlatformGetChild(PlatformChildCount() - 1))->NewReference();
   return S_OK;
 }
 
@@ -2939,8 +2916,8 @@
     return S_FALSE;
   }
 
-  *node = GetParent()->InternalGetChild(GetIndexInParent() - 1)->
-      ToBrowserAccessibilityWin()->NewReference();
+  *node = ToBrowserAccessibilityWin(
+      GetParent()->InternalGetChild(GetIndexInParent() - 1))->NewReference();
   return S_OK;
 }
 
@@ -2959,8 +2936,8 @@
     return S_FALSE;
   }
 
-  *node = GetParent()->InternalGetChild(GetIndexInParent() + 1)->
-      ToBrowserAccessibilityWin()->NewReference();
+  *node = ToBrowserAccessibilityWin(
+      GetParent()->InternalGetChild(GetIndexInParent() + 1))->NewReference();
   return S_OK;
 }
 
@@ -2982,7 +2959,7 @@
     return S_FALSE;
   }
 
-  *node = child->ToBrowserAccessibilityWin()->NewReference();
+  *node = ToBrowserAccessibilityWin(child)->NewReference();
   return S_OK;
 }
 
@@ -3101,7 +3078,7 @@
     BrowserAccessibility* node = this;
     while (node->GetParent())
       node = node->GetParent()->manager()->GetRoot();
-    return node->ToBrowserAccessibilityWin()->QueryInterface(
+    return ToBrowserAccessibilityWin(node)->QueryInterface(
         IID_IAccessible2, object);
   }
 
@@ -3458,7 +3435,7 @@
   // child object it points to.
   for (unsigned int i = 0; i < PlatformChildCount(); ++i) {
     BrowserAccessibilityWin* child =
-        PlatformGetChild(i)->ToBrowserAccessibilityWin();
+        ToBrowserAccessibilityWin(PlatformGetChild(i));
     DCHECK(child);
     // Similar to Firefox, we don't expose text-only objects in IA2 hypertext.
     if (child->IsTextOnlyObject()) {
@@ -3562,7 +3539,7 @@
 
     // Changing a static text node can affect the IAccessibleText hypertext
     // of the parent node, so force an update on the parent.
-    BrowserAccessibilityWin* parent = GetParent()->ToBrowserAccessibilityWin();
+    BrowserAccessibilityWin* parent = ToBrowserAccessibilityWin(GetParent());
     if (parent && IsTextOnlyObject() &&
         name() != old_win_attributes_->name) {
       parent->UpdateStep1ComputeWinAttributes();
@@ -3611,10 +3588,10 @@
     return this;
 
   if (child_id >= 1 && child_id <= static_cast<LONG>(PlatformChildCount()))
-    return PlatformGetChild(child_id - 1)->ToBrowserAccessibilityWin();
+    return ToBrowserAccessibilityWin(PlatformGetChild(child_id - 1));
 
-  return manager()->ToBrowserAccessibilityManagerWin()->
-      GetFromUniqueIdWin(child_id);
+  return ToBrowserAccessibilityWin(
+      BrowserAccessibility::GetFromUniqueID(-child_id));
 }
 
 HRESULT BrowserAccessibilityWin::GetStringAttributeAsBstr(
@@ -3687,7 +3664,7 @@
   const auto parent = GetParent();
   if (parent) {
     hyperlink_index =
-        parent->ToBrowserAccessibilityWin()->GetHyperlinkIndexFromChild(*this);
+        ToBrowserAccessibilityWin(parent)->GetHyperlinkIndexFromChild(*this);
   }
 
   if (hyperlink_index >= 0)
@@ -3734,7 +3711,7 @@
     DCHECK_LT(index_in_parent, static_cast<int32_t>(InternalChildCount()));
     for (uint32_t i = 0; i < static_cast<uint32_t>(index_in_parent); ++i) {
       const BrowserAccessibilityWin* sibling =
-          InternalGetChild(i)->ToBrowserAccessibilityWin();
+          ToBrowserAccessibilityWin(InternalGetChild(i));
       DCHECK(sibling);
       if (sibling->IsTextOnlyObject())
         hypertextOffset += sibling->GetText().size();
@@ -3753,11 +3730,11 @@
 
 int32_t BrowserAccessibilityWin::GetHypertextOffsetFromDescendant(
     const BrowserAccessibilityWin& descendant) const {
-  auto parent_object = descendant.GetParent()->ToBrowserAccessibilityWin();
+  auto parent_object = ToBrowserAccessibilityWin(descendant.GetParent());
   auto current_object = const_cast<BrowserAccessibilityWin*>(&descendant);
   while (parent_object && parent_object != this) {
     current_object = parent_object;
-    parent_object = current_object->GetParent()->ToBrowserAccessibilityWin();
+    parent_object = ToBrowserAccessibilityWin(current_object->GetParent());
   }
   if (!parent_object)
     return -1;
@@ -3839,7 +3816,7 @@
 int BrowserAccessibilityWin::GetSelectionAnchor() const {
   int32_t anchor_id = manager()->GetTreeData().sel_anchor_object_id;
   const auto anchor_object =
-      manager()->GetFromID(anchor_id)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(manager()->GetFromID(anchor_id));
   if (!anchor_object)
     return -1;
 
@@ -3850,7 +3827,7 @@
 int BrowserAccessibilityWin::GetSelectionFocus() const {
   int32_t focus_id = manager()->GetTreeData().sel_focus_object_id;
   const auto focus_object =
-      manager()->GetFromID(focus_id)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(manager()->GetFromID(focus_id));
   if (!focus_object)
     return -1;
 
@@ -4048,7 +4025,7 @@
 }
 
 BrowserAccessibilityWin* BrowserAccessibilityWin::GetFromID(int32_t id) {
-  return manager()->GetFromID(id)->ToBrowserAccessibilityWin();
+  return ToBrowserAccessibilityWin(manager()->GetFromID(id));
 }
 
 bool BrowserAccessibilityWin::IsListBoxOptionOrMenuListOption() {
@@ -4703,4 +4680,15 @@
   win_attributes_->ia2_state = ia2_state;
 }
 
+BrowserAccessibilityWin* ToBrowserAccessibilityWin(BrowserAccessibility* obj) {
+  DCHECK(!obj || obj->IsNative());
+  return static_cast<BrowserAccessibilityWin*>(obj);
+}
+
+const BrowserAccessibilityWin*
+ToBrowserAccessibilityWin(const BrowserAccessibility* obj) {
+  DCHECK(!obj || obj->IsNative());
+  return static_cast<const BrowserAccessibilityWin*>(obj);
+}
+
 }  // namespace content
diff --git a/content/browser/accessibility/browser_accessibility_win.h b/content/browser/accessibility/browser_accessibility_win.h
index adeb16b4..b237be9 100644
--- a/content/browser/accessibility/browser_accessibility_win.h
+++ b/content/browser/accessibility/browser_accessibility_win.h
@@ -97,10 +97,6 @@
 
   CONTENT_EXPORT ~BrowserAccessibilityWin() override;
 
-  // The Windows-specific unique ID, used as the child ID for MSAA methods
-  // like NotifyWinEvent, and as the unique ID for IAccessible2 and ISimpleDOM.
-  LONG unique_id_win() const { return unique_id_win_; }
-
   // Called after an atomic tree update completes. See
   // BrowserAccessibilityManagerWin::OnAtomicUpdateFinished for more
   // details on what these do.
@@ -867,11 +863,6 @@
   void AddRelations(ui::AXIntListAttribute src_attr,
                     const base::string16& iaccessiblerelation_type);
 
-  // Windows-specific unique ID (unique within the browser process),
-  // used for get_accChild, NotifyWinEvent, and as the unique ID for
-  // IAccessible2 and ISimpleDOM.
-  LONG unique_id_win_;
-
   struct WinAttributes {
     WinAttributes();
     ~WinAttributes();
@@ -918,9 +909,6 @@
   int previous_scroll_x_;
   int previous_scroll_y_;
 
-  // The next unique id to use.
-  static LONG next_unique_id_win_;
-
   // Give BrowserAccessibility::Create access to our constructor.
   friend class BrowserAccessibility;
   friend class BrowserAccessibilityRelation;
@@ -928,6 +916,12 @@
   DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityWin);
 };
 
+CONTENT_EXPORT BrowserAccessibilityWin*
+ToBrowserAccessibilityWin(BrowserAccessibility* obj);
+
+CONTENT_EXPORT const BrowserAccessibilityWin*
+ToBrowserAccessibilityWin(const BrowserAccessibility* obj);
+
 }  // namespace content
 
 #endif  // CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_WIN_H_
diff --git a/content/browser/accessibility/browser_accessibility_win_unittest.cc b/content/browser/accessibility/browser_accessibility_win_unittest.cc
index d86b380..b8b3e77 100644
--- a/content/browser/accessibility/browser_accessibility_win_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_win_unittest.cc
@@ -161,8 +161,7 @@
       MakeAXTreeUpdate(root, button, checkbox),
       NULL, new CountedBrowserAccessibilityFactory()));
   ASSERT_EQ(3, CountedBrowserAccessibility::num_instances());
-  IAccessible* root_accessible =
-      manager->GetRoot()->ToBrowserAccessibilityWin();
+  IAccessible* root_accessible = ToBrowserAccessibilityWin(manager->GetRoot());
   IDispatch* root_iaccessible = NULL;
   IDispatch* child1_iaccessible = NULL;
   base::win::ScopedVariant childid_self(CHILDID_SELF);
@@ -215,7 +214,7 @@
   // value.
   base::win::ScopedVariant one(1);
   base::win::ScopedComPtr<IDispatch> text_dispatch;
-  HRESULT hr = manager->GetRoot()->ToBrowserAccessibilityWin()->get_accChild(
+  HRESULT hr = ToBrowserAccessibilityWin(manager->GetRoot())->get_accChild(
       one, text_dispatch.Receive());
   ASSERT_EQ(S_OK, hr);
 
@@ -249,7 +248,7 @@
 
   // Query for the text IAccessible and verify that it now returns "new text"
   // as its value.
-  hr = manager->GetRoot()->ToBrowserAccessibilityWin()->get_accChild(
+  hr = ToBrowserAccessibilityWin(manager->GetRoot())->get_accChild(
       one, text_dispatch.Receive());
   ASSERT_EQ(S_OK, hr);
 
@@ -396,12 +395,12 @@
   ASSERT_EQ(7, CountedBrowserAccessibility::num_instances());
 
   BrowserAccessibilityWin* root_obj =
-      manager->GetRoot()->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(manager->GetRoot());
   ASSERT_NE(nullptr, root_obj);
   ASSERT_EQ(1U, root_obj->PlatformChildCount());
 
   BrowserAccessibilityWin* text_field_obj =
-      root_obj->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(root_obj->PlatformGetChild(0));
   ASSERT_NE(nullptr, text_field_obj);
 
   long text_len;
@@ -516,7 +515,7 @@
   ASSERT_EQ(3, CountedBrowserAccessibility::num_instances());
 
   BrowserAccessibilityWin* root_obj =
-      manager->GetRoot()->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(manager->GetRoot());
 
   long text_len;
   EXPECT_EQ(S_OK, root_obj->get_nCharacters(&text_len));
@@ -637,7 +636,7 @@
   ASSERT_EQ(9, CountedBrowserAccessibility::num_instances());
 
   BrowserAccessibilityWin* root_obj =
-      manager->GetRoot()->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(manager->GetRoot());
 
   long text_len;
   EXPECT_EQ(S_OK, root_obj->get_nCharacters(&text_len));
@@ -821,8 +820,8 @@
             1 << ui::AX_STATE_ENABLED,
             root->GetState());
 
-  LONG unique_id_win = root->ToBrowserAccessibilityWin()->unique_id_win();
-  ASSERT_EQ(root, manager->GetFromUniqueIdWin(unique_id_win));
+  int32_t unique_id = ToBrowserAccessibilityWin(root)->unique_id();
+  ASSERT_EQ(root, BrowserAccessibility::GetFromUniqueID(unique_id));
 }
 
 TEST_F(BrowserAccessibilityTest, TestIA2Attributes) {
@@ -855,13 +854,13 @@
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityWin* root_accessible =
-      manager->GetRoot()->ToBrowserAccessibilityWin();
-      ASSERT_NE(nullptr, root_accessible);
-      ASSERT_EQ(2U, root_accessible->PlatformChildCount());
+      ToBrowserAccessibilityWin(manager->GetRoot());
+  ASSERT_NE(nullptr, root_accessible);
+  ASSERT_EQ(2U, root_accessible->PlatformChildCount());
 
-      BrowserAccessibilityWin* pseudo_accessible =
-          root_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
-      ASSERT_NE(nullptr, pseudo_accessible);
+  BrowserAccessibilityWin* pseudo_accessible =
+      ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(0));
+  ASSERT_NE(nullptr, pseudo_accessible);
 
   base::win::ScopedBstr attributes;
   HRESULT hr = pseudo_accessible->get_attributes(attributes.Receive());
@@ -871,7 +870,7 @@
   EXPECT_EQ(L"display:none;tag:<pseudo\\:before>;", attributes_str);
 
   BrowserAccessibilityWin* checkbox_accessible =
-      root_accessible->PlatformGetChild(1)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(1));
   ASSERT_NE(nullptr, checkbox_accessible);
 
   attributes.Reset();
@@ -962,27 +961,27 @@
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityWin* root_accessible =
-      manager->GetRoot()->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(manager->GetRoot());
   ASSERT_NE(nullptr, root_accessible);
   ASSERT_EQ(5U, root_accessible->PlatformChildCount());
 
   BrowserAccessibilityWin* combo_box_accessible =
-      root_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(0));
   ASSERT_NE(nullptr, combo_box_accessible);
   manager->SetFocusLocallyForTesting(combo_box_accessible);
   ASSERT_EQ(combo_box_accessible,
-            manager->GetFocus()->ToBrowserAccessibilityWin());
+            ToBrowserAccessibilityWin(manager->GetFocus()));
   BrowserAccessibilityWin* search_box_accessible =
-      root_accessible->PlatformGetChild(1)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(1));
   ASSERT_NE(nullptr, search_box_accessible);
   BrowserAccessibilityWin* text_field_accessible =
-      root_accessible->PlatformGetChild(2)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(2));
   ASSERT_NE(nullptr, text_field_accessible);
   BrowserAccessibilityWin* link_accessible =
-      root_accessible->PlatformGetChild(3)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(3));
   ASSERT_NE(nullptr, link_accessible);
   BrowserAccessibilityWin* slider_accessible =
-      root_accessible->PlatformGetChild(4)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(4));
   ASSERT_NE(nullptr, slider_accessible);
 
   base::win::ScopedVariant childid_self(CHILDID_SELF);
@@ -1124,15 +1123,15 @@
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityWin* root_accessible =
-      manager->GetRoot()->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(manager->GetRoot());
   ASSERT_NE(nullptr, root_accessible);
   ASSERT_EQ(2U, root_accessible->PlatformChildCount());
 
   BrowserAccessibilityWin* textarea_accessible =
-      root_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(0));
   ASSERT_NE(nullptr, textarea_accessible);
   BrowserAccessibilityWin* text_field_accessible =
-      root_accessible->PlatformGetChild(1)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(1));
   ASSERT_NE(nullptr, text_field_accessible);
 
   base::win::ScopedComPtr<IAccessibleText> textarea_object;
@@ -1223,18 +1222,18 @@
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityWin* root_accessible =
-      manager->GetRoot()->ToBrowserAccessibilityWin();
-      ASSERT_NE(nullptr, root_accessible);
-      ASSERT_EQ(2U, root_accessible->PlatformChildCount());
+      ToBrowserAccessibilityWin(manager->GetRoot());
+  ASSERT_NE(nullptr, root_accessible);
+  ASSERT_EQ(2U, root_accessible->PlatformChildCount());
 
   BrowserAccessibilityWin* combo_box_accessible =
-      root_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(0));
   ASSERT_NE(nullptr, combo_box_accessible);
   manager->SetFocusLocallyForTesting(combo_box_accessible);
   ASSERT_EQ(combo_box_accessible,
-      manager->GetFocus()->ToBrowserAccessibilityWin());
+            ToBrowserAccessibilityWin(manager->GetFocus()));
   BrowserAccessibilityWin* text_field_accessible =
-      root_accessible->PlatformGetChild(1)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(1));
   ASSERT_NE(nullptr, text_field_accessible);
 
   // -2 is never a valid offset.
@@ -1255,7 +1254,7 @@
   // Move the focus to the text field.
   manager->SetFocusLocallyForTesting(text_field_accessible);
   ASSERT_EQ(text_field_accessible,
-      manager->GetFocus()->ToBrowserAccessibilityWin());
+            ToBrowserAccessibilityWin(manager->GetFocus()));
 
   // The caret should not have moved.
   hr = text_field_accessible->get_caretOffset(&caret_offset);
@@ -1343,12 +1342,12 @@
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityWin* root_accessible =
-      manager->GetRoot()->ToBrowserAccessibilityWin();
-      ASSERT_NE(nullptr, root_accessible);
-      ASSERT_EQ(1U, root_accessible->PlatformChildCount());
+      ToBrowserAccessibilityWin(manager->GetRoot());
+  ASSERT_NE(nullptr, root_accessible);
+  ASSERT_EQ(1U, root_accessible->PlatformChildCount());
 
   BrowserAccessibilityWin* div_editable_accessible =
-      root_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(0));
   ASSERT_NE(nullptr, div_editable_accessible);
   ASSERT_EQ(2U, div_editable_accessible->PlatformChildCount());
 
@@ -1369,18 +1368,18 @@
   // Move the focus to the content editable.
   manager->SetFocusLocallyForTesting(div_editable_accessible);
   ASSERT_EQ(div_editable_accessible,
-      manager->GetFocus()->ToBrowserAccessibilityWin());
+            ToBrowserAccessibilityWin(manager->GetFocus()));
 
   BrowserAccessibilityWin* text_accessible =
-      div_editable_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(div_editable_accessible->PlatformGetChild(0));
   ASSERT_NE(nullptr, text_accessible);
   BrowserAccessibilityWin* link_accessible =
-      div_editable_accessible->PlatformGetChild(1)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(div_editable_accessible->PlatformGetChild(1));
   ASSERT_NE(nullptr, link_accessible);
   ASSERT_EQ(1U, link_accessible->PlatformChildCount());
 
   BrowserAccessibilityWin* link_text_accessible =
-      link_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(link_accessible->PlatformGetChild(0));
   ASSERT_NE(nullptr, link_text_accessible);
 
   // The caret should not have moved.
@@ -1461,12 +1460,12 @@
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityWin* root_accessible =
-      manager->GetRoot()->ToBrowserAccessibilityWin();
-      ASSERT_NE(nullptr, root_accessible);
-      ASSERT_EQ(1U, root_accessible->PlatformChildCount());
+      ToBrowserAccessibilityWin(manager->GetRoot());
+  ASSERT_NE(nullptr, root_accessible);
+  ASSERT_EQ(1U, root_accessible->PlatformChildCount());
 
   BrowserAccessibilityWin* div_editable_accessible =
-      root_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(0));
   ASSERT_NE(nullptr, div_editable_accessible);
   ASSERT_EQ(2U, div_editable_accessible->PlatformChildCount());
 
@@ -1477,15 +1476,15 @@
   LONG selection_end = -2;
 
   BrowserAccessibilityWin* text_accessible =
-      div_editable_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(div_editable_accessible->PlatformGetChild(0));
   ASSERT_NE(nullptr, text_accessible);
   BrowserAccessibilityWin* link_accessible =
-      div_editable_accessible->PlatformGetChild(1)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(div_editable_accessible->PlatformGetChild(1));
   ASSERT_NE(nullptr, link_accessible);
   ASSERT_EQ(1U, link_accessible->PlatformChildCount());
 
   BrowserAccessibilityWin* link_text_accessible =
-      link_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(link_accessible->PlatformGetChild(0));
   ASSERT_NE(nullptr, link_text_accessible);
 
   // get_nSelections should work on all objects.
@@ -1535,7 +1534,7 @@
   // Move the focus to the content editable.
   manager->SetFocusLocallyForTesting(div_editable_accessible);
   ASSERT_EQ(div_editable_accessible,
-      manager->GetFocus()->ToBrowserAccessibilityWin());
+            ToBrowserAccessibilityWin(manager->GetFocus()));
 
   // The caret should not have moved.
   hr = div_editable_accessible->get_caretOffset(&caret_offset);
@@ -1597,20 +1596,20 @@
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityWin* root_accessible =
-      manager->GetRoot()->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(manager->GetRoot());
   ASSERT_NE(nullptr, root_accessible);
   ASSERT_EQ(1U, root_accessible->PlatformChildCount());
 
   BrowserAccessibilityWin* div_accessible =
-      root_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(0));
   ASSERT_NE(nullptr, div_accessible);
   ASSERT_EQ(2U, div_accessible->PlatformChildCount());
 
   BrowserAccessibilityWin* text_accessible =
-      div_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(div_accessible->PlatformGetChild(0));
   ASSERT_NE(nullptr, text_accessible);
   BrowserAccessibilityWin* link_accessible =
-      div_accessible->PlatformGetChild(1)->ToBrowserAccessibilityWin();
+      ToBrowserAccessibilityWin(div_accessible->PlatformGetChild(1));
   ASSERT_NE(nullptr, link_accessible);
 
   // -1 is never a valid value.
@@ -1817,9 +1816,9 @@
           new CountedBrowserAccessibilityFactory()));
 
   BrowserAccessibility* root = manager->GetRoot();
-  LONG root_unique_id = root->ToBrowserAccessibilityWin()->unique_id_win();
+  int32_t root_unique_id = root->unique_id();
   BrowserAccessibility* child = root->PlatformGetChild(0);
-  LONG child_unique_id = child->ToBrowserAccessibilityWin()->unique_id_win();
+  int32_t child_unique_id = child->unique_id();
 
   // Now destroy that original tree and create a new tree.
   manager.reset(
@@ -1828,37 +1827,37 @@
           nullptr,
           new CountedBrowserAccessibilityFactory()));
   root = manager->GetRoot();
-  LONG root_unique_id_2 = root->ToBrowserAccessibilityWin()->unique_id_win();
+  int32_t root_unique_id_2 = root->unique_id();
   child = root->PlatformGetChild(0);
-  LONG child_unique_id_2 = child->ToBrowserAccessibilityWin()->unique_id_win();
+  int32_t child_unique_id_2 = child->unique_id();
 
   // The nodes in the new tree should not have the same ids.
   EXPECT_NE(root_unique_id, root_unique_id_2);
   EXPECT_NE(child_unique_id, child_unique_id_2);
 
   // Trying to access the unique IDs of the old, deleted objects should fail.
-  base::win::ScopedVariant old_root_variant(root_unique_id);
+  base::win::ScopedVariant old_root_variant(-root_unique_id);
   base::win::ScopedComPtr<IDispatch> old_root_dispatch;
-  HRESULT hr = root->ToBrowserAccessibilityWin()->get_accChild(
+  HRESULT hr = ToBrowserAccessibilityWin(root)->get_accChild(
       old_root_variant, old_root_dispatch.Receive());
   EXPECT_EQ(E_INVALIDARG, hr);
 
-  base::win::ScopedVariant old_child_variant(child_unique_id);
+  base::win::ScopedVariant old_child_variant(-child_unique_id);
   base::win::ScopedComPtr<IDispatch> old_child_dispatch;
-  hr = root->ToBrowserAccessibilityWin()->get_accChild(
+  hr = ToBrowserAccessibilityWin(root)->get_accChild(
       old_child_variant, old_child_dispatch.Receive());
   EXPECT_EQ(E_INVALIDARG, hr);
 
   // Trying to access the unique IDs of the new objects should succeed.
-  base::win::ScopedVariant new_root_variant(root_unique_id_2);
+  base::win::ScopedVariant new_root_variant(-root_unique_id_2);
   base::win::ScopedComPtr<IDispatch> new_root_dispatch;
-  hr = root->ToBrowserAccessibilityWin()->get_accChild(
+  hr = ToBrowserAccessibilityWin(root)->get_accChild(
       new_root_variant, new_root_dispatch.Receive());
   EXPECT_EQ(S_OK, hr);
 
-  base::win::ScopedVariant new_child_variant(child_unique_id_2);
+  base::win::ScopedVariant new_child_variant(-child_unique_id_2);
   base::win::ScopedComPtr<IDispatch> new_child_dispatch;
-  hr = root->ToBrowserAccessibilityWin()->get_accChild(
+  hr = ToBrowserAccessibilityWin(root)->get_accChild(
       new_child_variant, new_child_dispatch.Receive());
   EXPECT_EQ(S_OK, hr);
 }
diff --git a/content/browser/appcache/appcache_url_request_job.cc b/content/browser/appcache/appcache_url_request_job.cc
index 05fe008b..35728e66 100644
--- a/content/browser/appcache/appcache_url_request_job.cc
+++ b/content/browser/appcache/appcache_url_request_job.cc
@@ -433,6 +433,12 @@
   return net::ERR_IO_PENDING;
 }
 
+net::HostPortPair AppCacheURLRequestJob::GetSocketAddress() const {
+  if (!http_info())
+    return net::HostPortPair();
+  return http_info()->socket_address;
+}
+
 void AppCacheURLRequestJob::SetExtraRequestHeaders(
     const net::HttpRequestHeaders& headers) {
   std::string value;
diff --git a/content/browser/appcache/appcache_url_request_job.h b/content/browser/appcache/appcache_url_request_job.h
index 057c13b..5b872376 100644
--- a/content/browser/appcache/appcache_url_request_job.h
+++ b/content/browser/appcache/appcache_url_request_job.h
@@ -152,6 +152,7 @@
   bool GetCharset(std::string* charset) override;
   void GetResponseInfo(net::HttpResponseInfo* info) override;
   int ReadRawData(net::IOBuffer* buf, int buf_size) override;
+  net::HostPortPair GetSocketAddress() const override;
 
   // Sets extra request headers for Job types that support request headers.
   // This is how we get informed of range-requests.
diff --git a/content/browser/frame_host/frame_mojo_shell.cc b/content/browser/frame_host/frame_mojo_shell.cc
index 8b54af6..de37229 100644
--- a/content/browser/frame_host/frame_mojo_shell.cc
+++ b/content/browser/frame_host/frame_mojo_shell.cc
@@ -48,8 +48,7 @@
 // drop it and replace it with services we provide in the browser. In the
 // future we may need to support both.
 void FrameMojoShell::Connect(
-    const mojo::String& application_name,
-    const mojo::String& user_id,
+    mojo::shell::mojom::IdentityPtr target,
     mojo::shell::mojom::InterfaceProviderRequest services,
     mojo::shell::mojom::InterfaceProviderPtr /* exposed_services */,
     const mojo::shell::mojom::Connector::ConnectCallback& callback) {
@@ -60,7 +59,7 @@
                                         GetProxy(&frame_services));
 
   MojoShellContext::ConnectToApplication(
-      application_name,
+      target->name,
       frame_host_->GetSiteInstance()->GetSiteURL().spec(), std::move(services),
       std::move(frame_services), callback);
 }
diff --git a/content/browser/frame_host/frame_mojo_shell.h b/content/browser/frame_host/frame_mojo_shell.h
index c243345..f0827e57 100644
--- a/content/browser/frame_host/frame_mojo_shell.h
+++ b/content/browser/frame_host/frame_mojo_shell.h
@@ -29,8 +29,7 @@
  private:
   // mojo::Connector:
   void Connect(
-      const mojo::String& application_name,
-      const mojo::String& user_id,
+      mojo::shell::mojom::IdentityPtr target,
       mojo::shell::mojom::InterfaceProviderRequest services,
       mojo::shell::mojom::InterfaceProviderPtr exposed_services,
       const mojo::shell::mojom::Connector::ConnectCallback& callback) override;
diff --git a/content/browser/frame_host/frame_tree_node.cc b/content/browser/frame_host/frame_tree_node.cc
index 7ef7ca4..f9b793f 100644
--- a/content/browser/frame_host/frame_tree_node.cc
+++ b/content/browser/frame_host/frame_tree_node.cc
@@ -14,7 +14,6 @@
 #include "content/browser/frame_host/navigation_request.h"
 #include "content/browser/frame_host/navigator.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
-#include "content/browser/frame_host/traced_frame_tree_node.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/common/frame_messages.h"
 #include "content/common/site_isolation_policy.h"
@@ -106,12 +105,6 @@
       g_frame_tree_node_id_map.Get().insert(
           std::make_pair(frame_tree_node_id_, this));
   CHECK(result.second);
-
-  TRACE_EVENT_OBJECT_CREATED_WITH_ID(
-      "navigation", "FrameTreeNode",
-      TRACE_ID_WITH_SCOPE("FrameTreeNode", frame_tree_node_id_));
-  TraceSnapshot();
-  base::trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(this);
 }
 
 FrameTreeNode::~FrameTreeNode() {
@@ -123,11 +116,6 @@
     opener_->RemoveObserver(opener_observer_.get());
 
   g_frame_tree_node_id_map.Get().erase(frame_tree_node_id_);
-
-  TRACE_EVENT_OBJECT_DELETED_WITH_ID(
-      "navigation", "FrameTreeNode",
-      TRACE_ID_WITH_SCOPE("FrameTreeNode", frame_tree_node_id_));
-  base::trace_event::TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
 }
 
 void FrameTreeNode::AddObserver(Observer* observer) {
@@ -184,7 +172,6 @@
 
 void FrameTreeNode::ResetForNewProcess() {
   current_frame_host()->set_last_committed_url(GURL());
-  TraceSnapshot();
 
   // Remove child nodes from the tree, then delete them. This destruction
   // operation will notify observers.
@@ -210,7 +197,6 @@
   if (!has_committed_real_load_ && url != GURL(url::kAboutBlankURL))
     has_committed_real_load_ = true;
   current_frame_host()->set_last_committed_url(url);
-  TraceSnapshot();
 }
 
 void FrameTreeNode::SetCurrentOrigin(const url::Origin& origin) {
@@ -462,16 +448,4 @@
   }
 }
 
-void FrameTreeNode::OnTraceLogEnabled() {
-  TraceSnapshot();
-}
-
-void FrameTreeNode::TraceSnapshot() const {
-  TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
-      "navigation", "FrameTreeNode",
-      TRACE_ID_WITH_SCOPE("FrameTreeNode", frame_tree_node_id_),
-      scoped_ptr<base::trace_event::ConvertableToTraceFormat>(
-          new TracedFrameTreeNode(*this)));
-}
-
 }  // namespace content
diff --git a/content/browser/frame_host/frame_tree_node.h b/content/browser/frame_host/frame_tree_node.h
index fda8ecd..c108da5 100644
--- a/content/browser/frame_host/frame_tree_node.h
+++ b/content/browser/frame_host/frame_tree_node.h
@@ -32,8 +32,7 @@
 // of those frames. We are mirroring this tree in the browser process. This
 // class represents a node in this tree and is a wrapper for all objects that
 // are frame-specific (as opposed to page-specific).
-class CONTENT_EXPORT FrameTreeNode :
-  public base::trace_event::TraceLog::EnabledStateObserver {
+class CONTENT_EXPORT FrameTreeNode {
  public:
   class Observer {
    public:
@@ -65,7 +64,7 @@
                 const std::string& unique_name,
                 const blink::WebFrameOwnerProperties& frame_owner_properties);
 
-  ~FrameTreeNode() override;
+  ~FrameTreeNode();
 
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
@@ -268,17 +267,11 @@
   // FrameTreeNode.
   void BeforeUnloadCanceled();
 
-  // TraceLog::EnabledStateObserver
-  void OnTraceLogEnabled() override;
-  void OnTraceLogDisabled() override {}
-
  private:
   class OpenerDestroyedObserver;
 
   void set_parent(FrameTreeNode* parent) { parent_ = parent; }
 
-  void TraceSnapshot() const;
-
   // The next available browser-global FrameTreeNode ID.
   static int next_frame_tree_node_id_;
 
diff --git a/content/browser/frame_host/traced_frame_tree_node.cc b/content/browser/frame_host/traced_frame_tree_node.cc
deleted file mode 100644
index fc27dc5d..0000000
--- a/content/browser/frame_host/traced_frame_tree_node.cc
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/frame_host/traced_frame_tree_node.h"
-
-#include "base/command_line.h"
-#include "base/json/json_writer.h"
-#include "base/strings/stringprintf.h"
-#include "content/browser/frame_host/frame_tree.h"
-#include "content/public/common/content_switches.h"
-#include "url/gurl.h"
-
-namespace content {
-
-TracedFrameTreeNode::TracedFrameTreeNode(const FrameTreeNode& node)
-    : parent_node_id_(-1),
-      process_id_(-1),
-      routing_id_(-1) {
-  FrameTreeNode* parent = node.parent();
-  if (parent)
-    parent_node_id_ = parent->frame_tree_node_id();
-
-  RenderFrameHostImpl* current_frame_host = node.current_frame_host();
-  if (!current_frame_host)
-    return;
-
-  if (current_frame_host->last_committed_url().is_valid())
-    url_ = current_frame_host->last_committed_url().spec();
-
-  base::ProcessHandle process_handle =
-    current_frame_host->GetProcess()->GetHandle();
-  if (process_handle == base::kNullProcessHandle)
-    return;
-
-  // On Windows, |rph->GetHandle()| does not duplicate ownership
-  // of the process handle and the render host still retains it. Therefore, we
-  // cannot create a base::Process object, which provides a proper way to get a
-  // process id, from the handle. For a stopgap, we use this deprecated
-  // function that does not require the ownership (http://crbug.com/417532).
-  process_id_ = base::GetProcId(process_handle);
-
-  routing_id_ = current_frame_host->GetRoutingID();
-  DCHECK_NE(routing_id_, MSG_ROUTING_NONE);
-}
-
-TracedFrameTreeNode::~TracedFrameTreeNode() {
-}
-
-void TracedFrameTreeNode::AppendAsTraceFormat(std::string* out) const {
-  scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue());
-
-  if (parent_node_id_ >= 0) {
-    scoped_ptr<base::DictionaryValue> ref(new base::DictionaryValue());
-    ref->SetString("id_ref", base::StringPrintf("0x%x", parent_node_id_));
-    ref->SetString("scope", "FrameTreeNode");
-    value->Set("parent", std::move(ref));
-  }
-
-  if (process_id_ >= 0) {
-    scoped_ptr<base::DictionaryValue> ref(new base::DictionaryValue());
-    ref->SetInteger("pid_ref", process_id_);
-    ref->SetString("id_ref", base::StringPrintf("0x%x", routing_id_));
-    ref->SetString("scope", "RenderFrame");
-    value->Set("RenderFrame", std::move(ref));
-  }
-
-  if (!url_.empty())
-    value->SetString("url", url_);
-
-  std::string tmp;
-  base::JSONWriter::Write(*value, &tmp);
-  *out += tmp;
-}
-
-}  // content
diff --git a/content/browser/frame_host/traced_frame_tree_node.h b/content/browser/frame_host/traced_frame_tree_node.h
deleted file mode 100644
index 79c2a80..0000000
--- a/content/browser/frame_host/traced_frame_tree_node.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/macros.h"
-#include "base/memory/scoped_vector.h"
-#include "base/trace_event/trace_event_impl.h"
-#include "base/values.h"
-#include "content/common/content_export.h"
-
-namespace content {
-
-class FrameTree;
-class FrameTreeNode;
-
-// This is a temporary container used when tracing snapshots of FrameTree
-// objects. When a snapshot of a FrameTree is taken, a TracedFrameTreeNode is
-// created and stored by the tracing system until the trace is dumped.
-class CONTENT_EXPORT TracedFrameTreeNode :
-  public base::trace_event::ConvertableToTraceFormat {
- public:
-  TracedFrameTreeNode(const FrameTreeNode& node);
-  void AppendAsTraceFormat(std::string* out) const override;
-
- private:
-  ~TracedFrameTreeNode() override;
-
-  int parent_node_id_;
-  std::string url_;
-  int process_id_;
-  int routing_id_;
-
-  DISALLOW_COPY_AND_ASSIGN(TracedFrameTreeNode);
-};
-
-}  // content
diff --git a/content/browser/gpu/compositor_util.cc b/content/browser/gpu/compositor_util.cc
index 5530aaa..eb2d69b81 100644
--- a/content/browser/gpu/compositor_util.cc
+++ b/content/browser/gpu/compositor_util.cc
@@ -220,7 +220,7 @@
   if (IsZeroCopyUploadEnabled())
     return false;
   const auto& command_line = *base::CommandLine::ForCurrentProcess();
-  return command_line.HasSwitch(switches::kEnablePartialRaster);
+  return !command_line.HasSwitch(switches::kDisablePartialRaster);
 }
 
 bool IsGpuMemoryBufferCompositorResourcesEnabled() {
diff --git a/content/browser/mojo/mojo_shell_client_host.cc b/content/browser/mojo/mojo_shell_client_host.cc
index 69f1cc5c..e762c225 100644
--- a/content/browser/mojo/mojo_shell_client_host.cc
+++ b/content/browser/mojo/mojo_shell_client_host.cc
@@ -124,8 +124,11 @@
   factory.Bind(mojo::InterfacePtrInfo<mojo::shell::mojom::ShellClientFactory>(
       std::move(request_pipe), 0u));
 
-  shell->CreateInstance(std::move(factory), url,
-                        mojo::shell::mojom::kInheritUserID,
+  mojo::shell::mojom::IdentityPtr target(mojo::shell::mojom::Identity::New());
+  target->name = url;
+  target->user_id = mojo::shell::mojom::kInheritUserID;
+  target->instance = "";
+  shell->CreateInstance(std::move(factory), std::move(target),
                         CreateCapabilityFilterForRenderer(),
                         std::move(request), base::Bind(&OnConnectionComplete));
 
diff --git a/content/browser/mojo/mojo_shell_context.cc b/content/browser/mojo/mojo_shell_context.cc
index 134db56..19b53fa 100644
--- a/content/browser/mojo/mojo_shell_context.cc
+++ b/content/browser/mojo/mojo_shell_context.cc
@@ -26,9 +26,9 @@
 #include "mojo/public/cpp/bindings/interface_request.h"
 #include "mojo/public/cpp/bindings/string.h"
 #include "mojo/shell/connect_params.h"
-#include "mojo/shell/identity.h"
 #include "mojo/shell/loader.h"
 #include "mojo/shell/native_runner.h"
+#include "mojo/shell/public/cpp/identity.h"
 #include "mojo/shell/public/cpp/shell_client.h"
 #include "mojo/shell/public/interfaces/connector.mojom.h"
 #include "mojo/shell/runner/host/in_process_native_runner.h"
@@ -285,15 +285,9 @@
     const mojo::shell::mojom::Connector::ConnectCallback& callback) {
   scoped_ptr<mojo::shell::ConnectParams> params(new mojo::shell::ConnectParams);
   // TODO(beng): kRootUserID is obviously wrong.
-  // TODO(beng): We need to set a permissive filter here temporarily because
-  //             content is known as a bogus system: name that the application
-  //             manager doesn't understand.
-  mojo::shell::Identity source_id(
-      requestor_name, std::string(), mojo::shell::mojom::kRootUserID);
-  source_id.set_filter(mojo::shell::GetPermissiveCapabilityFilter());
+  mojo::Identity source_id(requestor_name, mojo::shell::mojom::kRootUserID);
   params->set_source(source_id);
-  params->set_target(mojo::shell::Identity(
-      name, std::string(), mojo::shell::mojom::kRootUserID));
+  params->set_target(mojo::Identity(name, mojo::shell::mojom::kRootUserID));
   params->set_remote_interfaces(std::move(request));
   params->set_local_interfaces(std::move(exposed_services));
   params->set_connect_callback(callback);
diff --git a/content/browser/push_messaging/push_messaging_message_filter.cc b/content/browser/push_messaging/push_messaging_message_filter.cc
index ef75724..a2eb895 100644
--- a/content/browser/push_messaging/push_messaging_message_filter.cc
+++ b/content/browser/push_messaging/push_messaging_message_filter.cc
@@ -9,7 +9,6 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "base/command_line.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/metrics/histogram.h"
@@ -28,7 +27,6 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/child_process_host.h"
 #include "content/public/common/console_message_level.h"
-#include "content/public/common/content_switches.h"
 #include "content/public/common/push_messaging_status.h"
 #include "third_party/WebKit/public/platform/modules/push_messaging/WebPushPermissionStatus.h"
 
@@ -252,7 +250,8 @@
 void PushMessagingMessageFilter::OnSubscribeFromDocument(
     int render_frame_id,
     int request_id,
-    const PushSubscriptionOptions& options,
+    const std::string& sender_id,
+    bool user_visible,
     int64_t service_worker_registration_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   // TODO(mvanouwerkerk): Validate arguments?
@@ -260,7 +259,7 @@
   data.request_id = request_id;
   data.service_worker_registration_id = service_worker_registration_id;
   data.render_frame_id = render_frame_id;
-  data.user_visible = options.user_visible_only;
+  data.user_visible = user_visible;
 
   ServiceWorkerRegistration* service_worker_registration =
       service_worker_context_->GetLiveRegistration(
@@ -274,20 +273,20 @@
 
   service_worker_context_->StoreRegistrationUserData(
       service_worker_registration_id, data.requesting_origin,
-      kPushSenderIdServiceWorkerKey, options.sender_info,
-      base::Bind(&PushMessagingMessageFilter::DidPersistSenderInfo,
-                 weak_factory_io_to_io_.GetWeakPtr(), data, options));
+      kPushSenderIdServiceWorkerKey, sender_id,
+      base::Bind(&PushMessagingMessageFilter::DidPersistSenderId,
+                 weak_factory_io_to_io_.GetWeakPtr(), data, sender_id));
 }
 
 void PushMessagingMessageFilter::OnSubscribeFromWorker(
     int request_id,
     int64_t service_worker_registration_id,
-    const PushSubscriptionOptions& options) {
+    bool user_visible) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   RegisterData data;
   data.request_id = request_id;
   data.service_worker_registration_id = service_worker_registration_id;
-  data.user_visible = options.user_visible_only;
+  data.user_visible = user_visible;
 
   ServiceWorkerRegistration* service_worker_registration =
       service_worker_context_->GetLiveRegistration(
@@ -298,35 +297,34 @@
   }
   data.requesting_origin = service_worker_registration->pattern().GetOrigin();
 
-  // If there is a sender_info in the subscription options, it will be used,
-  // otherwise the registration sender_info will be used.
-  CheckForExistingRegistration(data, options);
+  // This sender_id will be ignored; instead it will be fetched from storage.
+  CheckForExistingRegistration(data, std::string() /* sender_id */);
 }
 
-void PushMessagingMessageFilter::DidPersistSenderInfo(
+void PushMessagingMessageFilter::DidPersistSenderId(
     const RegisterData& data,
-    const PushSubscriptionOptions& options,
+    const std::string& sender_id,
     ServiceWorkerStatusCode service_worker_status) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   if (service_worker_status != SERVICE_WORKER_OK)
     SendSubscriptionError(data, PUSH_REGISTRATION_STATUS_STORAGE_ERROR);
   else
-    CheckForExistingRegistration(data, options);
+    CheckForExistingRegistration(data, sender_id);
 }
 
 void PushMessagingMessageFilter::CheckForExistingRegistration(
     const RegisterData& data,
-    const PushSubscriptionOptions& options) {
+    const std::string& sender_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   service_worker_context_->GetRegistrationUserData(
       data.service_worker_registration_id, kPushRegistrationIdServiceWorkerKey,
       base::Bind(&PushMessagingMessageFilter::DidCheckForExistingRegistration,
-                 weak_factory_io_to_io_.GetWeakPtr(), data, options));
+                 weak_factory_io_to_io_.GetWeakPtr(), data, sender_id));
 }
 
 void PushMessagingMessageFilter::DidCheckForExistingRegistration(
     const RegisterData& data,
-    const PushSubscriptionOptions& options,
+    const std::string& sender_id,
     const std::string& push_registration_id,
     ServiceWorkerStatusCode service_worker_status) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -347,11 +345,11 @@
   // service_worker_status != SERVICE_WORKER_ERROR_NOT_FOUND instead of
   // attempting to do a fresh registration?
   // https://w3c.github.io/push-api/#widl-PushRegistrationManager-register-Promise-PushRegistration
-  if (!options.sender_info.empty()) {
+  if (data.FromDocument()) {
     BrowserThread::PostTask(
         BrowserThread::UI, FROM_HERE,
         base::Bind(&Core::RegisterOnUI, base::Unretained(ui_core_.get()), data,
-                   options.sender_info));
+                   sender_id));
   } else {
     service_worker_context_->GetRegistrationUserData(
         data.service_worker_registration_id, kPushSenderIdServiceWorkerKey,
@@ -394,7 +392,7 @@
 
 void PushMessagingMessageFilter::Core::RegisterOnUI(
     const PushMessagingMessageFilter::RegisterData& data,
-    const std::string& sender_info) {
+    const std::string& sender_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   PushMessagingService* push_service = service();
   if (!push_service) {
@@ -440,18 +438,16 @@
     return;
   }
 
-  PushSubscriptionOptions options;
-  options.user_visible_only = data.user_visible;
-  options.sender_info = sender_info;
   if (data.FromDocument()) {
     push_service->SubscribeFromDocument(
-        data.requesting_origin, data.service_worker_registration_id,
-        render_process_id_, data.render_frame_id, options,
+        data.requesting_origin, data.service_worker_registration_id, sender_id,
+        render_process_id_, data.render_frame_id, data.user_visible,
         base::Bind(&Core::DidRegister, weak_factory_ui_to_ui_.GetWeakPtr(),
                    data));
   } else {
     push_service->SubscribeFromWorker(
-        data.requesting_origin, data.service_worker_registration_id, options,
+        data.requesting_origin, data.service_worker_registration_id, sender_id,
+        data.user_visible,
         base::Bind(&Core::DidRegister, weak_factory_ui_to_ui_.GetWeakPtr(),
                    data));
   }
diff --git a/content/browser/push_messaging/push_messaging_message_filter.h b/content/browser/push_messaging/push_messaging_message_filter.h
index d2db18a..aba0b34 100644
--- a/content/browser/push_messaging/push_messaging_message_filter.h
+++ b/content/browser/push_messaging/push_messaging_message_filter.h
@@ -23,7 +23,6 @@
 
 class PushMessagingService;
 class ServiceWorkerContextWrapper;
-struct PushSubscriptionOptions;
 
 extern const char kPushSenderIdServiceWorkerKey[];
 extern const char kPushRegistrationIdServiceWorkerKey[];
@@ -51,25 +50,26 @@
 
   void OnSubscribeFromDocument(int render_frame_id,
                                int request_id,
-                               const PushSubscriptionOptions& options,
+                               const std::string& sender_id,
+                               bool user_visible,
                                int64_t service_worker_registration_id);
 
   void OnSubscribeFromWorker(int request_id,
                              int64_t service_worker_registration_id,
-                             const PushSubscriptionOptions& options);
+                             bool user_visible);
 
-  void DidPersistSenderInfo(const RegisterData& data,
-                            const PushSubscriptionOptions& options,
-                            ServiceWorkerStatusCode service_worker_status);
+  void DidPersistSenderId(const RegisterData& data,
+                          const std::string& sender_id,
+                          ServiceWorkerStatusCode service_worker_status);
 
   // sender_id is ignored if data.FromDocument() is false.
   void CheckForExistingRegistration(const RegisterData& data,
-                                    const PushSubscriptionOptions& options);
+                                    const std::string& sender_id);
 
   // sender_id is ignored if data.FromDocument() is false.
   void DidCheckForExistingRegistration(
       const RegisterData& data,
-      const PushSubscriptionOptions& options,
+      const std::string& sender_id,
       const std::string& push_registration_id,
       ServiceWorkerStatusCode service_worker_status);
 
diff --git a/content/browser/renderer_host/legacy_render_widget_host_win.cc b/content/browser/renderer_host/legacy_render_widget_host_win.cc
index 9e230574..f99cb38 100644
--- a/content/browser/renderer_host/legacy_render_widget_host_win.cc
+++ b/content/browser/renderer_host/legacy_render_widget_host_win.cc
@@ -181,7 +181,7 @@
     return static_cast<LRESULT>(0L);
 
   base::win::ScopedComPtr<IAccessible> root(
-      manager->GetRoot()->ToBrowserAccessibilityWin());
+      ToBrowserAccessibilityWin(manager->GetRoot()));
   return LresultFromObject(IID_IAccessible, w_param,
       static_cast<IAccessible*>(root.Detach()));
 }
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 17ce1b5..34f50aa 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1283,8 +1283,8 @@
 
   if (IsZeroCopyUploadEnabled())
     command_line->AppendSwitch(switches::kEnableZeroCopy);
-  if (IsPartialRasterEnabled())
-    command_line->AppendSwitch(switches::kEnablePartialRaster);
+  if (!IsPartialRasterEnabled())
+    command_line->AppendSwitch(switches::kDisablePartialRaster);
 
   if (IsForceGpuRasterizationEnabled())
     command_line->AppendSwitch(switches::kForceGpuRasterization);
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index 3a46b4c..27e1809f 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -747,7 +747,7 @@
   BrowserAccessibilityManager* manager =
       host_->GetOrCreateRootBrowserAccessibilityManager();
   if (manager)
-    return manager->GetRoot()->ToBrowserAccessibilityWin();
+    return ToBrowserAccessibilityWin(manager->GetRoot());
 #endif
 
   NOTIMPLEMENTED();
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 7baa14a..1675b98 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -31,6 +31,7 @@
 #include "base/sys_info.h"
 #include "base/trace_event/trace_event.h"
 #import "content/browser/accessibility/browser_accessibility_cocoa.h"
+#import "content/browser/accessibility/browser_accessibility_mac.h"
 #include "content/browser/accessibility/browser_accessibility_manager_mac.h"
 #include "content/browser/bad_message.h"
 #import "content/browser/cocoa/system_hotkey_helper_mac.h"
@@ -2823,8 +2824,8 @@
   if (([attribute isEqualToString:NSAccessibilityChildrenAttribute] ||
           [attribute isEqualToString:NSAccessibilityContentsAttribute]) &&
       manager) {
-    return [NSArray arrayWithObjects:manager->
-        GetRoot()->ToBrowserAccessibilityCocoa(), nil];
+    return [NSArray arrayWithObjects:ToBrowserAccessibilityCocoa(
+        manager->GetRoot()), nil];
   } else if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) {
     return NSAccessibilityScrollAreaRole;
   }
@@ -2849,7 +2850,7 @@
   NSPoint localPoint = [self convertPoint:pointInWindow fromView:nil];
   localPoint.y = NSHeight([self bounds]) - localPoint.y;
   BrowserAccessibilityCocoa* root =
-      manager->GetRoot()->ToBrowserAccessibilityCocoa();
+      ToBrowserAccessibilityCocoa(manager->GetRoot());
   id obj = [root accessibilityHitTest:localPoint];
   return obj;
 }
@@ -2867,7 +2868,7 @@
           ->GetRootBrowserAccessibilityManager();
   // Only child is root.
   if (manager &&
-      manager->GetRoot()->ToBrowserAccessibilityCocoa() == child) {
+      ToBrowserAccessibilityCocoa(manager->GetRoot()) == child) {
     return 0;
   } else {
     return NSNotFound;
@@ -2883,7 +2884,7 @@
     DCHECK(focused_item);
     if (focused_item) {
       BrowserAccessibilityCocoa* focused_item_cocoa =
-          focused_item->ToBrowserAccessibilityCocoa();
+          ToBrowserAccessibilityCocoa(focused_item);
       DCHECK(focused_item_cocoa);
       if (focused_item_cocoa)
         return focused_item_cocoa;
diff --git a/content/child/push_messaging/push_provider.cc b/content/child/push_messaging/push_provider.cc
index 254d855..f8e807de 100644
--- a/content/child/push_messaging/push_provider.cc
+++ b/content/child/push_messaging/push_provider.cc
@@ -75,11 +75,8 @@
   subscription_callbacks_.AddWithID(callbacks, request_id);
   int64_t service_worker_registration_id =
       GetServiceWorkerRegistrationId(service_worker_registration);
-  PushSubscriptionOptions content_options;
-  content_options.user_visible_only = options.userVisibleOnly;
-  content_options.sender_info = options.applicationServerKey.utf8();
   thread_safe_sender_->Send(new PushMessagingHostMsg_SubscribeFromWorker(
-      request_id, service_worker_registration_id, content_options));
+      request_id, service_worker_registration_id, options.userVisibleOnly));
 }
 
 void PushProvider::unsubscribe(
diff --git a/content/child/resource_dispatcher.cc b/content/child/resource_dispatcher.cc
index ee780bc7..cbda6c4 100644
--- a/content/child/resource_dispatcher.cc
+++ b/content/child/resource_dispatcher.cc
@@ -572,6 +572,7 @@
   response->devtools_info = result.devtools_info;
   response->data.swap(result.data);
   response->download_file_path = result.download_file_path;
+  response->socket_address = result.socket_address;
 }
 
 int ResourceDispatcher::StartAsync(const RequestInfo& request_info,
diff --git a/content/child/v8_value_converter_impl_unittest.cc b/content/child/v8_value_converter_impl_unittest.cc
index 435ea30..311fa7f4 100644
--- a/content/child/v8_value_converter_impl_unittest.cc
+++ b/content/child/v8_value_converter_impl_unittest.cc
@@ -14,7 +14,6 @@
 #include "base/values.h"
 #include "content/child/v8_value_converter_impl.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h"
 #include "v8/include/v8.h"
 
 namespace content {
@@ -288,7 +287,6 @@
   v8::Local<v8::Context> context =
       v8::Local<v8::Context>::New(isolate_, context_);
   v8::Context::Scope context_scope(context);
-  blink::WebScopedMicrotaskSuppression microtasks_scope;
 
   // Set up objects to throw when reading or writing 'foo'.
   const char* source =
@@ -331,7 +329,6 @@
   v8::Local<v8::Context> context =
       v8::Local<v8::Context>::New(isolate_, context_);
   v8::Context::Scope context_scope(context);
-  blink::WebScopedMicrotaskSuppression microtasks_scope;
 
   const char* source = "(function() {"
       "var arr = [];"
@@ -408,7 +405,6 @@
   v8::Local<v8::Context> context =
       v8::Local<v8::Context>::New(isolate_, context_);
   v8::Context::Scope context_scope(context);
-  blink::WebScopedMicrotaskSuppression microtasks_scope;
 
   const char* source = "(function() {"
       "Object.prototype.foo = 'foo';"
@@ -433,7 +429,6 @@
   v8::Local<v8::Context> context =
       v8::Local<v8::Context>::New(isolate_, context_);
   v8::Context::Scope context_scope(context);
-  blink::WebScopedMicrotaskSuppression microtasks_scope;
 
   const char* source = "(function() {"
       "return { foo: undefined, bar: null };"
@@ -492,7 +487,6 @@
   v8::Local<v8::Context> context =
       v8::Local<v8::Context>::New(isolate_, context_);
   v8::Context::Scope context_scope(context);
-  blink::WebScopedMicrotaskSuppression microtasks_scope;
 
   const char* source = "(function() {"
       "return {"
@@ -531,7 +525,6 @@
   v8::Local<v8::Context> context =
       v8::Local<v8::Context>::New(isolate_, context_);
   v8::Context::Scope context_scope(context);
-  blink::WebScopedMicrotaskSuppression microtasks_scope;
 
   const char* source = "(function() {"
       "var a = [0];"
@@ -556,7 +549,6 @@
   v8::Local<v8::Context> context =
       v8::Local<v8::Context>::New(isolate_, context_);
   v8::Context::Scope context_scope(context);
-  blink::WebScopedMicrotaskSuppression microtasks_scope;
 
   v8::Local<v8::Object> object;
   {
diff --git a/content/common/gpu/client/gpu_jpeg_decode_accelerator_host.cc b/content/common/gpu/client/gpu_jpeg_decode_accelerator_host.cc
index f431ad9..05cdb8d 100644
--- a/content/common/gpu/client/gpu_jpeg_decode_accelerator_host.cc
+++ b/content/common/gpu/client/gpu_jpeg_decode_accelerator_host.cc
@@ -180,7 +180,8 @@
 
   decode_params.coded_size = video_frame->coded_size();
   decode_params.output_video_frame_handle = output_handle;
-  decode_params.output_buffer_size = output_buffer_size;
+  decode_params.output_buffer_size =
+      base::checked_cast<uint32_t>(output_buffer_size);
   Send(new AcceleratedJpegDecoderMsg_Decode(decoder_route_id_, decode_params));
 }
 
diff --git a/content/common/gpu/media/android_copying_backing_strategy.cc b/content/common/gpu/media/android_copying_backing_strategy.cc
index cf166af..e81c9eb0 100644
--- a/content/common/gpu/media/android_copying_backing_strategy.cc
+++ b/content/common/gpu/media/android_copying_backing_strategy.cc
@@ -18,10 +18,6 @@
 
 namespace content {
 
-const static GLfloat kIdentityMatrix[16] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-                                            0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-                                            0.0f, 0.0f, 0.0f, 1.0f};
-
 AndroidCopyingBackingStrategy::AndroidCopyingBackingStrategy(
     AVDAStateProvider* state_provider)
     : state_provider_(state_provider),
@@ -114,8 +110,11 @@
     surface_texture_->UpdateTexImage();
   }
 
-  float transfrom_matrix[16];
-  surface_texture_->GetTransformMatrix(transfrom_matrix);
+  float transform_matrix[16];
+  surface_texture_->GetTransformMatrix(transform_matrix);
+  // add y-flip to correct UV coordinate systems.
+  transform_matrix[13] += transform_matrix[5];
+  transform_matrix[5] = -transform_matrix[5];
 
   uint32_t picture_buffer_texture_id = picture_buffer.texture_id();
 
@@ -135,13 +134,11 @@
   //    attached.
   // 2. SurfaceTexture requires us to apply a transform matrix when we show
   //    the texture.
-  // TODO(hkuang): get the StreamTexture transform matrix in GPU process
-  // instead of using default matrix crbug.com/226218.
   copier_->DoCopyTextureWithTransform(
       state_provider_->GetGlDecoder().get(), GL_TEXTURE_EXTERNAL_OES,
       surface_texture_id_, GL_TEXTURE_2D, picture_buffer_texture_id,
       state_provider_->GetSize().width(), state_provider_->GetSize().height(),
-      false, false, false, kIdentityMatrix);
+      false, false, false, transform_matrix);
 }
 
 void AndroidCopyingBackingStrategy::CodecChanged(
diff --git a/content/common/gpu/media/android_video_decode_accelerator.cc b/content/common/gpu/media/android_video_decode_accelerator.cc
index 1de68a2e..dd3e75e 100644
--- a/content/common/gpu/media/android_video_decode_accelerator.cc
+++ b/content/common/gpu/media/android_video_decode_accelerator.cc
@@ -19,6 +19,7 @@
 #include "content/common/gpu/gpu_channel.h"
 #include "content/common/gpu/media/android_copying_backing_strategy.h"
 #include "content/common/gpu/media/android_deferred_rendering_backing_strategy.h"
+#include "content/common/gpu/media/shared_memory_region.h"
 #include "content/public/common/content_switches.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 #include "gpu/command_buffer/service/gpu_switches.h"
@@ -476,17 +477,16 @@
     return true;
   }
 
-  scoped_ptr<base::SharedMemory> shm;
+  scoped_ptr<SharedMemoryRegion> shm;
 
-  if (pending_input_buf_index_ != -1) {
-    // The buffer is already dequeued from MediaCodec, filled with data and
-    // bitstream_buffer.handle() is closed.
-    shm.reset(new base::SharedMemory());
-  } else {
-    shm.reset(new base::SharedMemory(bitstream_buffer.handle(), true));
+  if (pending_input_buf_index_ == -1) {
+    // When |pending_input_buf_index_| is not -1, the buffer is already dequeued
+    // from MediaCodec, filled with data and bitstream_buffer.handle() is
+    // closed.
+    shm.reset(new SharedMemoryRegion(bitstream_buffer, true));
 
-    if (!shm->Map(bitstream_buffer.size())) {
-      POST_ERROR(UNREADABLE_INPUT, "Failed to SharedMemory::Map()");
+    if (!shm->Map()) {
+      POST_ERROR(UNREADABLE_INPUT, "Failed to SharedMemoryRegion::Map()");
       return false;
     }
   }
@@ -506,7 +506,8 @@
 
   // Notice that |memory| will be null if we repeatedly enqueue the same buffer,
   // this happens after MEDIA_CODEC_NO_KEY.
-  const uint8_t* memory = static_cast<const uint8_t*>(shm->memory());
+  const uint8_t* memory =
+      shm ? static_cast<const uint8_t*>(shm->memory()) : nullptr;
   const std::string& key_id = bitstream_buffer.key_id();
   const std::string& iv = bitstream_buffer.iv();
   const std::vector<media::SubsampleEntry>& subsamples =
diff --git a/content/common/gpu/media/android_video_encode_accelerator.cc b/content/common/gpu/media/android_video_encode_accelerator.cc
index 5b70bd3..406c1bc 100644
--- a/content/common/gpu/media/android_video_encode_accelerator.cc
+++ b/content/common/gpu/media/android_video_encode_accelerator.cc
@@ -12,6 +12,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
 #include "content/common/gpu/gpu_channel.h"
+#include "content/common/gpu/media/shared_memory_region.h"
 #include "content/public/common/content_switches.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 #include "media/base/android/media_codec_util.h"
@@ -421,14 +422,11 @@
 
   media::BitstreamBuffer bitstream_buffer = available_bitstream_buffers_.back();
   available_bitstream_buffers_.pop_back();
-  scoped_ptr<base::SharedMemory> shm(
-      new base::SharedMemory(bitstream_buffer.handle(), false));
-  RETURN_ON_FAILURE(shm->Map(bitstream_buffer.size()),
-                    "Failed to map SHM",
-                    kPlatformFailureError);
-  RETURN_ON_FAILURE(size <= shm->mapped_size(),
-                    "Encoded buffer too large: " << size << ">"
-                                                 << shm->mapped_size(),
+  scoped_ptr<SharedMemoryRegion> shm(
+      new SharedMemoryRegion(bitstream_buffer, false));
+  RETURN_ON_FAILURE(shm->Map(), "Failed to map SHM", kPlatformFailureError);
+  RETURN_ON_FAILURE(size <= shm->size(),
+                    "Encoded buffer too large: " << size << ">" << shm->size(),
                     kPlatformFailureError);
 
   media::MediaCodecStatus status = media_codec_->CopyFromOutputBuffer(
diff --git a/content/common/gpu/media/gpu_video_decode_accelerator.cc b/content/common/gpu/media/gpu_video_decode_accelerator.cc
index c0ef547..7ce14e9 100644
--- a/content/common/gpu/media/gpu_video_decode_accelerator.cc
+++ b/content/common/gpu/media/gpu_video_decode_accelerator.cc
@@ -486,6 +486,17 @@
   video_decode_accelerator_->SetCdm(cdm_id);
 }
 
+void GpuVideoDecodeAccelerator::CallOrPostNotifyError(
+    media::VideoDecodeAccelerator::Error error) {
+  if (child_task_runner_->BelongsToCurrentThread()) {
+    NotifyError(error);
+  } else {
+    child_task_runner_->PostTask(
+        FROM_HERE, base::Bind(&GpuVideoDecodeAccelerator::NotifyError,
+                              base::Unretained(this), error));
+  }
+}
+
 // Runs on IO thread if video_decode_accelerator_->CanDecodeOnIOThread() is
 // true, otherwise on the main thread.
 void GpuVideoDecodeAccelerator::OnDecode(
diff --git a/content/common/gpu/media/gpu_video_decode_accelerator.h b/content/common/gpu/media/gpu_video_decode_accelerator.h
index aa36bf17..ac9b118 100644
--- a/content/common/gpu/media/gpu_video_decode_accelerator.h
+++ b/content/common/gpu/media/gpu_video_decode_accelerator.h
@@ -109,6 +109,9 @@
                  uint32_t texture_target,
                  scoped_refptr<gl::GLImage> image);
 
+  // Helper function to call NotifyError in the |child_task_runner_| thread.
+  void CallOrPostNotifyError(media::VideoDecodeAccelerator::Error error);
+
   // Route ID to communicate with the host.
   const int32_t host_route_id_;
 
diff --git a/content/common/gpu/media/media_messages.cc b/content/common/gpu/media/media_messages.cc
index 88364d9..6b9648d 100644
--- a/content/common/gpu/media/media_messages.cc
+++ b/content/common/gpu/media/media_messages.cc
@@ -16,6 +16,8 @@
                                                 const param_type& p) {
   WriteParam(m, p.id());
   WriteParam(m, static_cast<uint64_t>(p.size()));
+  DCHECK_GE(p.offset(), 0);
+  WriteParam(m, static_cast<uint64_t>(p.offset()));
   WriteParam(m, p.presentation_timestamp());
   WriteParam(m, p.key_id());
   if (!p.key_id().empty()) {
@@ -30,7 +32,9 @@
                                                param_type* r) {
   DCHECK(r);
   uint64_t size = 0;
+  uint64_t offset = 0;
   if (!(ReadParam(m, iter, &r->id_) && ReadParam(m, iter, &size) &&
+        ReadParam(m, iter, &offset) &&
         ReadParam(m, iter, &r->presentation_timestamp_) &&
         ReadParam(m, iter, &r->key_id_)))
     return false;
@@ -42,6 +46,13 @@
   }
   r->size_ = checked_size.ValueOrDie();
 
+  base::CheckedNumeric<off_t> checked_offset(offset);
+  if (!checked_offset.IsValid()) {
+    DLOG(ERROR) << "Invalid offset: " << offset;
+    return false;
+  }
+  r->offset_ = checked_offset.ValueOrDie();
+
   if (!r->key_id_.empty()) {
     if (!(ReadParam(m, iter, &r->iv_) && ReadParam(m, iter, &r->subsamples_)))
       return false;
diff --git a/content/common/gpu/media/shared_memory_region.cc b/content/common/gpu/media/shared_memory_region.cc
new file mode 100644
index 0000000..4ee6a24
--- /dev/null
+++ b/content/common/gpu/media/shared_memory_region.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sys_info.h"
+#include "content/common/gpu/media/shared_memory_region.h"
+
+namespace content {
+
+SharedMemoryRegion::SharedMemoryRegion(const base::SharedMemoryHandle& handle,
+                                       off_t offset,
+                                       size_t size,
+                                       bool read_only)
+    : shm_(handle, read_only),
+      offset_(offset),
+      size_(size),
+      alignment_size_(offset % base::SysInfo::VMAllocationGranularity()) {
+  DCHECK_GE(offset_, 0) << "Invalid offset: " << offset_;
+}
+
+SharedMemoryRegion::SharedMemoryRegion(
+    const media::BitstreamBuffer& bitstream_buffer,
+    bool read_only)
+    : SharedMemoryRegion(bitstream_buffer.handle(),
+                         bitstream_buffer.offset(),
+                         bitstream_buffer.size(),
+                         read_only) {}
+
+bool SharedMemoryRegion::Map() {
+  if (offset_ < 0) {
+    DVLOG(1) << "Invalid offset: " << offset_;
+    return false;
+  }
+  return shm_.MapAt(offset_ - alignment_size_, size_ + alignment_size_);
+}
+
+void* SharedMemoryRegion::memory() {
+  int8_t* addr = reinterpret_cast<int8_t*>(shm_.memory());
+  return addr ? addr + alignment_size_ : nullptr;
+}
+
+}  // namespace content
diff --git a/content/common/gpu/media/shared_memory_region.h b/content/common/gpu/media/shared_memory_region.h
new file mode 100644
index 0000000..f7c5db29
--- /dev/null
+++ b/content/common/gpu/media/shared_memory_region.h
@@ -0,0 +1,57 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_GPU_MEDIA_SHARED_MEMORY_REGION_H_
+#define CONTENT_COMMON_GPU_MEDIA_SHARED_MEMORY_REGION_H_
+
+#include "base/memory/shared_memory.h"
+#include "media/base/bitstream_buffer.h"
+
+namespace content {
+
+// Helper class to access a region of a SharedMemory. Different from
+// SharedMemory, in which the |offset| of function MapAt() must be aligned to
+// the value of |SysInfo::VMAllocationGranularity()|, the |offset| of a
+// SharedMemoryRegion needs not to be aligned, this class hides the details
+// and returns the mapped address of the given offset.
+class SharedMemoryRegion {
+ public:
+  // Creates a SharedMemoryRegion.
+  // The mapped memory region begins at |offset| bytes from the start of the
+  // shared memory and the length is |size|. It will take the ownership of
+  // the |handle| and release the resource when being destroyed. Different
+  // from SharedMemory, the |offset| needs not to be aligned to the value of
+  // |SysInfo::VMAllocationGranularity()|.
+  SharedMemoryRegion(const base::SharedMemoryHandle& handle,
+                     off_t offset,
+                     size_t size,
+                     bool read_only);
+
+  // Creates a SharedMemoryRegion from the given |bistream_buffer|.
+  SharedMemoryRegion(const media::BitstreamBuffer& bitstream_buffer,
+                     bool read_only);
+
+  // Maps the shared memory into the caller's address space.
+  // Return true on success, false otherwise.
+  bool Map();
+
+  // Gets a pointer to the mapped region if it has been mapped via Map().
+  // Returns |nullptr| if it is not mapped. The returned pointer points
+  // to the memory at the offset previously passed to the constructor.
+  void* memory();
+
+  size_t size() const { return size_; }
+
+ private:
+  base::SharedMemory shm_;
+  off_t offset_;
+  size_t size_;
+  size_t alignment_size_;
+
+  DISALLOW_COPY_AND_ASSIGN(SharedMemoryRegion);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_COMMON_GPU_MEDIA_SHARED_MEMORY_REGION_H_
diff --git a/content/common/gpu/media/v4l2_jpeg_decode_accelerator.cc b/content/common/gpu/media/v4l2_jpeg_decode_accelerator.cc
index 7f6e9ba..0121ead 100644
--- a/content/common/gpu/media/v4l2_jpeg_decode_accelerator.cc
+++ b/content/common/gpu/media/v4l2_jpeg_decode_accelerator.cc
@@ -112,10 +112,11 @@
 }
 
 V4L2JpegDecodeAccelerator::JobRecord::JobRecord(
-    media::BitstreamBuffer bitstream_buffer,
+    const media::BitstreamBuffer& bitstream_buffer,
     scoped_refptr<media::VideoFrame> video_frame)
-    : bitstream_buffer(bitstream_buffer), out_frame(video_frame) {
-}
+    : bitstream_buffer_id(bitstream_buffer.id()),
+      shm(bitstream_buffer, true),
+      out_frame(video_frame) {}
 
 V4L2JpegDecodeAccelerator::JobRecord::~JobRecord() {
 }
@@ -268,11 +269,9 @@
 
 void V4L2JpegDecodeAccelerator::DecodeTask(scoped_ptr<JobRecord> job_record) {
   DCHECK(decoder_task_runner_->BelongsToCurrentThread());
-  job_record->shm.reset(
-      new base::SharedMemory(job_record->bitstream_buffer.handle(), true));
-  if (!job_record->shm->Map(job_record->bitstream_buffer.size())) {
+  if (!job_record->shm.Map()) {
     PLOG(ERROR) << __func__ << ": could not map bitstream_buffer";
-    PostNotifyError(job_record->bitstream_buffer.id(), UNREADABLE_INPUT);
+    PostNotifyError(job_record->bitstream_buffer_id, UNREADABLE_INPUT);
     return;
   }
   input_jobs_.push(make_linked_ptr(job_record.release()));
@@ -296,7 +295,7 @@
   linked_ptr<JobRecord> job_record = input_jobs_.front();
   // Check input buffer size is enough
   return (input_buffer_map_.empty() ||
-          (job_record->bitstream_buffer.size() + sizeof(kDefaultDhtSeg)) >
+          (job_record->shm.size() + sizeof(kDefaultDhtSeg)) >
               input_buffer_map_.front().length);
 }
 
@@ -341,8 +340,7 @@
   // The input image may miss huffman table. We didn't parse the image before,
   // so we create more to avoid the situation of not enough memory.
   // Reserve twice size to avoid recreating input buffer frequently.
-  size_t reserve_size =
-      (job_record->bitstream_buffer.size() + sizeof(kDefaultDhtSeg)) * 2;
+  size_t reserve_size = (job_record->shm.size() + sizeof(kDefaultDhtSeg)) * 2;
   struct v4l2_format format;
   memset(&format, 0, sizeof(format));
   format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
@@ -719,17 +717,16 @@
       // V4L2_PIX_FMT_YUV420.
       if (!CopyOutputImage(output_buffer_pixelformat_, output_record.address,
                            output_buffer_coded_size_, job_record->out_frame)) {
-        PostNotifyError(job_record->bitstream_buffer.id(), PLATFORM_FAILURE);
+        PostNotifyError(job_record->bitstream_buffer_id, PLATFORM_FAILURE);
         return;
       }
 
       DVLOG(3) << "Decoding finished, returning bitstream buffer, id="
-               << job_record->bitstream_buffer.id();
+               << job_record->bitstream_buffer_id;
 
       child_task_runner_->PostTask(
-          FROM_HERE,
-          base::Bind(&V4L2JpegDecodeAccelerator::VideoFrameReady, weak_ptr_,
-                     job_record->bitstream_buffer.id()));
+          FROM_HERE, base::Bind(&V4L2JpegDecodeAccelerator::VideoFrameReady,
+                                weak_ptr_, job_record->bitstream_buffer_id));
     }
   }
 }
@@ -827,10 +824,9 @@
   DCHECK(!input_record.at_device);
 
   // It will add default huffman segment if it's missing.
-  if (!AddHuffmanTable(job_record->shm->memory(),
-                       job_record->bitstream_buffer.size(),
+  if (!AddHuffmanTable(job_record->shm.memory(), job_record->shm.size(),
                        input_record.address, input_record.length)) {
-    PostNotifyError(job_record->bitstream_buffer.id(), PARSE_JPEG_FAILED);
+    PostNotifyError(job_record->bitstream_buffer_id, PARSE_JPEG_FAILED);
     return false;
   }
 
@@ -844,8 +840,9 @@
   running_jobs_.push(job_record);
   free_input_buffers_.pop_back();
 
-  DVLOG(3) << __func__ << ": enqueued frame id="
-           << job_record->bitstream_buffer.id() << " to device.";
+  DVLOG(3) << __func__
+           << ": enqueued frame id=" << job_record->bitstream_buffer_id
+           << " to device.";
   return true;
 }
 
diff --git a/content/common/gpu/media/v4l2_jpeg_decode_accelerator.h b/content/common/gpu/media/v4l2_jpeg_decode_accelerator.h
index 4358080..bef33b22 100644
--- a/content/common/gpu/media/v4l2_jpeg_decode_accelerator.h
+++ b/content/common/gpu/media/v4l2_jpeg_decode_accelerator.h
@@ -18,6 +18,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread.h"
 #include "content/common/content_export.h"
+#include "content/common/gpu/media/shared_memory_region.h"
 #include "content/common/gpu/media/v4l2_device.h"
 #include "media/base/bitstream_buffer.h"
 #include "media/base/video_frame.h"
@@ -58,16 +59,16 @@
   // the time of submission we may not have one available (and don't need one
   // to submit input to the device).
   struct JobRecord {
-    JobRecord(media::BitstreamBuffer bitstream_buffer,
+    JobRecord(const media::BitstreamBuffer& bitstream_buffer,
               scoped_refptr<media::VideoFrame> video_frame);
     ~JobRecord();
 
-    // Input image buffer.
-    media::BitstreamBuffer bitstream_buffer;
+    // Input image buffer ID.
+    int32_t bitstream_buffer_id;
+    // Memory mapped from |bitstream_buffer|.
+    SharedMemoryRegion shm;
     // Output frame buffer.
     scoped_refptr<media::VideoFrame> out_frame;
-    // Memory mapped from |bitstream_buffer|.
-    scoped_ptr<base::SharedMemory> shm;
   };
 
   void EnqueueInput();
diff --git a/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc b/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc
index f48fc93..a338cc26 100644
--- a/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc
+++ b/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc
@@ -19,6 +19,7 @@
 #include "base/macros.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/stringprintf.h"
+#include "content/common/gpu/media/shared_memory_region.h"
 #include "content/common/gpu/media/v4l2_slice_video_decode_accelerator.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/media_switches.h"
@@ -169,14 +170,12 @@
   BitstreamBufferRef(
       base::WeakPtr<VideoDecodeAccelerator::Client>& client,
       const scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner,
-      base::SharedMemory* shm,
-      size_t size,
+      SharedMemoryRegion* shm,
       int32_t input_id);
   ~BitstreamBufferRef();
   const base::WeakPtr<VideoDecodeAccelerator::Client> client;
   const scoped_refptr<base::SingleThreadTaskRunner> client_task_runner;
-  const scoped_ptr<base::SharedMemory> shm;
-  const size_t size;
+  const scoped_ptr<SharedMemoryRegion> shm;
   off_t bytes_used;
   const int32_t input_id;
 };
@@ -184,13 +183,11 @@
 V4L2SliceVideoDecodeAccelerator::BitstreamBufferRef::BitstreamBufferRef(
     base::WeakPtr<VideoDecodeAccelerator::Client>& client,
     const scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner,
-    base::SharedMemory* shm,
-    size_t size,
+    SharedMemoryRegion* shm,
     int32_t input_id)
     : client(client),
       client_task_runner(client_task_runner),
       shm(shm),
-      size(size),
       bytes_used(0),
       input_id(input_id) {}
 
@@ -1211,9 +1208,8 @@
 
   scoped_ptr<BitstreamBufferRef> bitstream_record(new BitstreamBufferRef(
       io_client_, io_task_runner_,
-      new base::SharedMemory(bitstream_buffer.handle(), true),
-      bitstream_buffer.size(), bitstream_buffer.id()));
-  if (!bitstream_record->shm->Map(bitstream_buffer.size())) {
+      new SharedMemoryRegion(bitstream_buffer, true), bitstream_buffer.id()));
+  if (!bitstream_record->shm->Map()) {
     LOGF(ERROR) << "Could not map bitstream_buffer";
     NOTIFY_ERROR(UNREADABLE_INPUT);
     return;
@@ -1245,7 +1241,7 @@
 
   const uint8_t* const data = reinterpret_cast<const uint8_t*>(
       decoder_current_bitstream_buffer_->shm->memory());
-  const size_t data_size = decoder_current_bitstream_buffer_->size;
+  const size_t data_size = decoder_current_bitstream_buffer_->shm->size();
   decoder_->SetStream(data, data_size);
 
   return true;
@@ -1645,7 +1641,7 @@
     // which - when reached - will trigger flush sequence.
     decoder_input_queue_.push(
         linked_ptr<BitstreamBufferRef>(new BitstreamBufferRef(
-            io_client_, io_task_runner_, nullptr, 0, kFlushBufferId)));
+            io_client_, io_task_runner_, nullptr, kFlushBufferId)));
     return;
   }
 
diff --git a/content/common/gpu/media/v4l2_video_decode_accelerator.cc b/content/common/gpu/media/v4l2_video_decode_accelerator.cc
index 3ed7f9621..3554be5 100644
--- a/content/common/gpu/media/v4l2_video_decode_accelerator.cc
+++ b/content/common/gpu/media/v4l2_video_decode_accelerator.cc
@@ -15,12 +15,12 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/macros.h"
-#include "base/memory/shared_memory.h"
 #include "base/message_loop/message_loop.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
+#include "content/common/gpu/media/shared_memory_region.h"
 #include "content/common/gpu/media/v4l2_video_decode_accelerator.h"
 #include "media/base/media_switches.h"
 #include "media/filters/h264_parser.h"
@@ -65,14 +65,12 @@
   BitstreamBufferRef(
       base::WeakPtr<Client>& client,
       scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner,
-      base::SharedMemory* shm,
-      size_t size,
+      scoped_ptr<SharedMemoryRegion> shm,
       int32_t input_id);
   ~BitstreamBufferRef();
   const base::WeakPtr<Client> client;
   const scoped_refptr<base::SingleThreadTaskRunner> client_task_runner;
-  const scoped_ptr<base::SharedMemory> shm;
-  const size_t size;
+  const scoped_ptr<SharedMemoryRegion> shm;
   size_t bytes_used;
   const int32_t input_id;
 };
@@ -94,13 +92,11 @@
 V4L2VideoDecodeAccelerator::BitstreamBufferRef::BitstreamBufferRef(
     base::WeakPtr<Client>& client,
     scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner,
-    base::SharedMemory* shm,
-    size_t size,
+    scoped_ptr<SharedMemoryRegion> shm,
     int32_t input_id)
     : client(client),
       client_task_runner(client_task_runner),
-      shm(shm),
-      size(size),
+      shm(std::move(shm)),
       bytes_used(0),
       input_id(input_id) {}
 
@@ -482,9 +478,10 @@
 
   scoped_ptr<BitstreamBufferRef> bitstream_record(new BitstreamBufferRef(
       io_client_, io_task_runner_,
-      new base::SharedMemory(bitstream_buffer.handle(), true),
-      bitstream_buffer.size(), bitstream_buffer.id()));
-  if (!bitstream_record->shm->Map(bitstream_buffer.size())) {
+      scoped_ptr<SharedMemoryRegion>(
+          new SharedMemoryRegion(bitstream_buffer, true)),
+      bitstream_buffer.id()));
+  if (!bitstream_record->shm->Map()) {
     LOG(ERROR) << "Decode(): could not map bitstream_buffer";
     NOTIFY_ERROR(UNREADABLE_INPUT);
     return;
@@ -543,54 +540,51 @@
     // Setup to use the next buffer.
     decoder_current_bitstream_buffer_.reset(buffer_ref.release());
     decoder_input_queue_.pop();
-    DVLOG(3) << "DecodeBufferTask(): reading input_id="
-             << decoder_current_bitstream_buffer_->input_id
-             << ", addr=" << (decoder_current_bitstream_buffer_->shm ?
-                              decoder_current_bitstream_buffer_->shm->memory() :
-                              NULL)
-             << ", size=" << decoder_current_bitstream_buffer_->size;
+    const auto& shm = decoder_current_bitstream_buffer_->shm;
+    if (shm) {
+      DVLOG(3) << "DecodeBufferTask(): reading input_id="
+               << decoder_current_bitstream_buffer_->input_id
+               << ", addr=" << shm->memory() << ", size=" << shm->size();
+    } else {
+      DCHECK_EQ(decoder_current_bitstream_buffer_->input_id, kFlushBufferId);
+      DVLOG(3) << "DecodeBufferTask(): reading input_id=kFlushBufferId";
+    }
   }
   bool schedule_task = false;
-  const size_t size = decoder_current_bitstream_buffer_->size;
   size_t decoded_size = 0;
-  if (size == 0) {
-    const int32_t input_id = decoder_current_bitstream_buffer_->input_id;
-    if (input_id >= 0) {
-      // This is a buffer queued from the client that has zero size.  Skip.
+  const auto& shm = decoder_current_bitstream_buffer_->shm;
+  if (!shm) {
+    // This is a dummy buffer, queued to flush the pipe.  Flush.
+    DCHECK_EQ(decoder_current_bitstream_buffer_->input_id, kFlushBufferId);
+    // Enqueue a buffer guaranteed to be empty.  To do that, we flush the
+    // current input, enqueue no data to the next frame, then flush that down.
+    schedule_task = true;
+    if (decoder_current_input_buffer_ != -1 &&
+        input_buffer_map_[decoder_current_input_buffer_].input_id !=
+            kFlushBufferId)
+      schedule_task = FlushInputFrame();
+
+    if (schedule_task && AppendToInputFrame(NULL, 0) && FlushInputFrame()) {
+      DVLOG(2) << "DecodeBufferTask(): enqueued flush buffer";
+      decoder_partial_frame_pending_ = false;
       schedule_task = true;
     } else {
-      // This is a buffer of zero size, queued to flush the pipe.  Flush.
-      DCHECK_EQ(decoder_current_bitstream_buffer_->shm.get(),
-                static_cast<base::SharedMemory*>(NULL));
-      // Enqueue a buffer guaranteed to be empty.  To do that, we flush the
-      // current input, enqueue no data to the next frame, then flush that down.
-      schedule_task = true;
-      if (decoder_current_input_buffer_ != -1 &&
-          input_buffer_map_[decoder_current_input_buffer_].input_id !=
-              kFlushBufferId)
-        schedule_task = FlushInputFrame();
-
-      if (schedule_task && AppendToInputFrame(NULL, 0) && FlushInputFrame()) {
-        DVLOG(2) << "DecodeBufferTask(): enqueued flush buffer";
-        decoder_partial_frame_pending_ = false;
-        schedule_task = true;
-      } else {
-        // If we failed to enqueue the empty buffer (due to pipeline
-        // backpressure), don't advance the bitstream buffer queue, and don't
-        // schedule the next task.  This bitstream buffer queue entry will get
-        // reprocessed when the pipeline frees up.
-        schedule_task = false;
-      }
+      // If we failed to enqueue the empty buffer (due to pipeline
+      // backpressure), don't advance the bitstream buffer queue, and don't
+      // schedule the next task.  This bitstream buffer queue entry will get
+      // reprocessed when the pipeline frees up.
+      schedule_task = false;
     }
+  } else if (shm->size() == 0) {
+    // This is a buffer queued from the client that has zero size.  Skip.
+    schedule_task = true;
   } else {
     // This is a buffer queued from the client, with actual contents.  Decode.
     const uint8_t* const data =
-        reinterpret_cast<const uint8_t*>(
-            decoder_current_bitstream_buffer_->shm->memory()) +
+        reinterpret_cast<const uint8_t*>(shm->memory()) +
         decoder_current_bitstream_buffer_->bytes_used;
     const size_t data_size =
-        decoder_current_bitstream_buffer_->size -
-        decoder_current_bitstream_buffer_->bytes_used;
+        shm->size() - decoder_current_bitstream_buffer_->bytes_used;
     if (!AdvanceFrameFragment(data, data_size, &decoded_size)) {
       NOTIFY_ERROR(UNREADABLE_INPUT);
       return;
@@ -619,8 +613,8 @@
 
   if (schedule_task) {
     decoder_current_bitstream_buffer_->bytes_used += decoded_size;
-    if (decoder_current_bitstream_buffer_->bytes_used ==
-        decoder_current_bitstream_buffer_->size) {
+    if ((shm ? shm->size() : 0) ==
+        decoder_current_bitstream_buffer_->bytes_used) {
       // Our current bitstream buffer is done; return it.
       int32_t input_id = decoder_current_bitstream_buffer_->input_id;
       DVLOG(3) << "DecodeBufferTask(): finished input_id=" << input_id;
@@ -1276,7 +1270,7 @@
   // Queue up an empty buffer -- this triggers the flush.
   decoder_input_queue_.push(
       linked_ptr<BitstreamBufferRef>(new BitstreamBufferRef(
-          io_client_, io_task_runner_, NULL, 0, kFlushBufferId)));
+          io_client_, io_task_runner_, nullptr, kFlushBufferId)));
   decoder_flushing_ = true;
   SendPictureReady();  // Send all pending PictureReady.
 
diff --git a/content/common/gpu/media/v4l2_video_encode_accelerator.cc b/content/common/gpu/media/v4l2_video_encode_accelerator.cc
index 9f62cc5..4cc8f26 100644
--- a/content/common/gpu/media/v4l2_video_encode_accelerator.cc
+++ b/content/common/gpu/media/v4l2_video_encode_accelerator.cc
@@ -17,6 +17,7 @@
 #include "base/numerics/safe_conversions.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
+#include "content/common/gpu/media/shared_memory_region.h"
 #include "content/common/gpu/media/v4l2_video_encode_accelerator.h"
 #include "content/public/common/content_switches.h"
 #include "media/base/bitstream_buffer.h"
@@ -51,13 +52,10 @@
 namespace content {
 
 struct V4L2VideoEncodeAccelerator::BitstreamBufferRef {
-  BitstreamBufferRef(int32_t id,
-                     scoped_ptr<base::SharedMemory> shm,
-                     size_t size)
-      : id(id), shm(std::move(shm)), size(size) {}
+  BitstreamBufferRef(int32_t id, scoped_ptr<SharedMemoryRegion> shm)
+      : id(id), shm(std::move(shm)) {}
   const int32_t id;
-  const scoped_ptr<base::SharedMemory> shm;
-  const size_t size;
+  const scoped_ptr<SharedMemoryRegion> shm;
 };
 
 V4L2VideoEncodeAccelerator::InputRecord::InputRecord() : at_device(false) {
@@ -224,15 +222,14 @@
     return;
   }
 
-  scoped_ptr<base::SharedMemory> shm(
-      new base::SharedMemory(buffer.handle(), false));
-  if (!shm->Map(buffer.size())) {
+  scoped_ptr<SharedMemoryRegion> shm(new SharedMemoryRegion(buffer, false));
+  if (!shm->Map()) {
     NOTIFY_ERROR(kPlatformFailureError);
     return;
   }
 
   scoped_ptr<BitstreamBufferRef> buffer_ref(
-      new BitstreamBufferRef(buffer.id(), std::move(shm), buffer.size()));
+      new BitstreamBufferRef(buffer.id(), std::move(shm)));
   encoder_thread_.message_loop()->PostTask(
       FROM_HERE,
       base::Bind(&V4L2VideoEncodeAccelerator::UseOutputBitstreamBufferTask,
diff --git a/content/common/gpu/media/vaapi_jpeg_decode_accelerator.cc b/content/common/gpu/media/vaapi_jpeg_decode_accelerator.cc
index d294ae5..f6d555b 100644
--- a/content/common/gpu/media/vaapi_jpeg_decode_accelerator.cc
+++ b/content/common/gpu/media/vaapi_jpeg_decode_accelerator.cc
@@ -14,6 +14,7 @@
 #include "base/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
 #include "content/common/gpu/gpu_channel.h"
+#include "content/common/gpu/media/shared_memory_region.h"
 #include "content/common/gpu/media/vaapi_picture.h"
 #include "media/base/video_frame.h"
 #include "media/filters/jpeg_parser.h"
@@ -76,10 +77,10 @@
 }  // namespace
 
 VaapiJpegDecodeAccelerator::DecodeRequest::DecodeRequest(
-    const media::BitstreamBuffer& bitstream_buffer,
-    scoped_ptr<base::SharedMemory> shm,
+    int32_t bitstream_buffer_id,
+    scoped_ptr<SharedMemoryRegion> shm,
     const scoped_refptr<media::VideoFrame>& video_frame)
-    : bitstream_buffer(bitstream_buffer),
+    : bitstream_buffer_id(bitstream_buffer_id),
       shm(std::move(shm)),
       video_frame(video_frame) {}
 
@@ -226,9 +227,9 @@
   media::JpegParseResult parse_result;
   if (!media::ParseJpegPicture(
           reinterpret_cast<const uint8_t*>(request->shm->memory()),
-          request->bitstream_buffer.size(), &parse_result)) {
+          request->shm->size(), &parse_result)) {
     DLOG(ERROR) << "ParseJpegPicture failed";
-    NotifyErrorFromDecoderThread(request->bitstream_buffer.id(),
+    NotifyErrorFromDecoderThread(request->bitstream_buffer_id,
                                  PARSE_JPEG_FAILED);
     return;
   }
@@ -237,7 +238,7 @@
       VaSurfaceFormatForJpeg(parse_result.frame_header);
   if (!new_va_rt_format) {
     DLOG(ERROR) << "Unsupported subsampling";
-    NotifyErrorFromDecoderThread(request->bitstream_buffer.id(),
+    NotifyErrorFromDecoderThread(request->bitstream_buffer_id,
                                  UNSUPPORTED_JPEG);
     return;
   }
@@ -255,7 +256,7 @@
     if (!vaapi_wrapper_->CreateSurfaces(va_rt_format_, new_coded_size, 1,
                                         &va_surfaces)) {
       LOG(ERROR) << "Create VA surface failed";
-      NotifyErrorFromDecoderThread(request->bitstream_buffer.id(),
+      NotifyErrorFromDecoderThread(request->bitstream_buffer_id,
                                    PLATFORM_FAILURE);
       return;
     }
@@ -266,15 +267,15 @@
   if (!VaapiJpegDecoder::Decode(vaapi_wrapper_.get(), parse_result,
                                 va_surface_id_)) {
     LOG(ERROR) << "Decode JPEG failed";
-    NotifyErrorFromDecoderThread(request->bitstream_buffer.id(),
+    NotifyErrorFromDecoderThread(request->bitstream_buffer_id,
                                  PLATFORM_FAILURE);
     return;
   }
 
-  if (!OutputPicture(va_surface_id_, request->bitstream_buffer.id(),
+  if (!OutputPicture(va_surface_id_, request->bitstream_buffer_id,
                      request->video_frame)) {
     LOG(ERROR) << "Output picture failed";
-    NotifyErrorFromDecoderThread(request->bitstream_buffer.id(),
+    NotifyErrorFromDecoderThread(request->bitstream_buffer_id,
                                  PLATFORM_FAILURE);
     return;
   }
@@ -290,25 +291,24 @@
   DVLOG(4) << "Mapping new input buffer id: " << bitstream_buffer.id()
            << " size: " << bitstream_buffer.size();
 
+  // SharedMemoryRegion will take over the |bitstream_buffer.handle()|.
+  scoped_ptr<SharedMemoryRegion> shm(
+      new SharedMemoryRegion(bitstream_buffer, true));
+
   if (bitstream_buffer.id() < 0) {
     LOG(ERROR) << "Invalid bitstream_buffer, id: " << bitstream_buffer.id();
-    if (base::SharedMemory::IsHandleValid(bitstream_buffer.handle()))
-      base::SharedMemory::CloseHandle(bitstream_buffer.handle());
     NotifyErrorFromDecoderThread(bitstream_buffer.id(), INVALID_ARGUMENT);
     return;
   }
 
-  scoped_ptr<base::SharedMemory> shm(
-      new base::SharedMemory(bitstream_buffer.handle(), true));
-
-  if (!shm->Map(bitstream_buffer.size())) {
+  if (!shm->Map()) {
     LOG(ERROR) << "Failed to map input buffer";
     NotifyErrorFromDecoderThread(bitstream_buffer.id(), UNREADABLE_INPUT);
     return;
   }
 
   scoped_ptr<DecodeRequest> request(
-      new DecodeRequest(bitstream_buffer, std::move(shm), video_frame));
+      new DecodeRequest(bitstream_buffer.id(), std::move(shm), video_frame));
 
   decoder_task_runner_->PostTask(
       FROM_HERE, base::Bind(&VaapiJpegDecodeAccelerator::DecodeTask,
diff --git a/content/common/gpu/media/vaapi_jpeg_decode_accelerator.h b/content/common/gpu/media/vaapi_jpeg_decode_accelerator.h
index 7d78a55..232b04d 100644
--- a/content/common/gpu/media/vaapi_jpeg_decode_accelerator.h
+++ b/content/common/gpu/media/vaapi_jpeg_decode_accelerator.h
@@ -15,6 +15,7 @@
 #include "base/threading/non_thread_safe.h"
 #include "base/threading/thread.h"
 #include "content/common/content_export.h"
+#include "content/common/gpu/media/shared_memory_region.h"
 #include "content/common/gpu/media/vaapi_jpeg_decoder.h"
 #include "content/common/gpu/media/vaapi_wrapper.h"
 #include "media/base/bitstream_buffer.h"
@@ -47,13 +48,13 @@
   // An input buffer and the corresponding output video frame awaiting
   // consumption, provided by the client.
   struct DecodeRequest {
-    DecodeRequest(const media::BitstreamBuffer& bitstream_buffer,
-                  scoped_ptr<base::SharedMemory> shm,
+    DecodeRequest(int32_t bitstream_buffer_id,
+                  scoped_ptr<SharedMemoryRegion> shm,
                   const scoped_refptr<media::VideoFrame>& video_frame);
     ~DecodeRequest();
 
-    media::BitstreamBuffer bitstream_buffer;
-    scoped_ptr<base::SharedMemory> shm;
+    int32_t bitstream_buffer_id;
+    scoped_ptr<SharedMemoryRegion> shm;
     scoped_refptr<media::VideoFrame> video_frame;
   };
 
diff --git a/content/common/gpu/media/vaapi_video_decode_accelerator.cc b/content/common/gpu/media/vaapi_video_decode_accelerator.cc
index a430438..147ac53e 100644
--- a/content/common/gpu/media/vaapi_video_decode_accelerator.cc
+++ b/content/common/gpu/media/vaapi_video_decode_accelerator.cc
@@ -256,8 +256,7 @@
   DISALLOW_COPY_AND_ASSIGN(VaapiVP9Accelerator);
 };
 
-VaapiVideoDecodeAccelerator::InputBuffer::InputBuffer() : id(0), size(0) {
-}
+VaapiVideoDecodeAccelerator::InputBuffer::InputBuffer() : id(0) {}
 
 VaapiVideoDecodeAccelerator::InputBuffer::~InputBuffer() {
 }
@@ -447,10 +446,10 @@
   DVLOG(4) << "Mapping new input buffer id: " << bitstream_buffer.id()
            << " size: " << (int)bitstream_buffer.size();
 
-  scoped_ptr<base::SharedMemory> shm(
-      new base::SharedMemory(bitstream_buffer.handle(), true));
-  RETURN_AND_NOTIFY_ON_FAILURE(shm->Map(bitstream_buffer.size()),
-                              "Failed to map input buffer", UNREADABLE_INPUT,);
+  scoped_ptr<SharedMemoryRegion> shm(
+      new SharedMemoryRegion(bitstream_buffer, true));
+  RETURN_AND_NOTIFY_ON_FAILURE(shm->Map(), "Failed to map input buffer",
+                               UNREADABLE_INPUT, );
 
   base::AutoLock auto_lock(lock_);
 
@@ -458,7 +457,6 @@
   linked_ptr<InputBuffer> input_buffer(new InputBuffer());
   input_buffer->shm.reset(shm.release());
   input_buffer->id = bitstream_buffer.id();
-  input_buffer->size = bitstream_buffer.size();
 
   ++num_stream_bufs_at_decoder_;
   TRACE_COUNTER1("Video Decoder", "Stream buffers at decoder",
@@ -497,13 +495,12 @@
       curr_input_buffer_ = input_buffers_.front();
       input_buffers_.pop();
 
-      DVLOG(4) << "New current bitstream buffer, id: "
-               << curr_input_buffer_->id
-               << " size: " << curr_input_buffer_->size;
+      DVLOG(4) << "New current bitstream buffer, id: " << curr_input_buffer_->id
+               << " size: " << curr_input_buffer_->shm->size();
 
       decoder_->SetStream(
           static_cast<uint8_t*>(curr_input_buffer_->shm->memory()),
-          curr_input_buffer_->size);
+          curr_input_buffer_->shm->size());
       return true;
 
     default:
diff --git a/content/common/gpu/media/vaapi_video_decode_accelerator.h b/content/common/gpu/media/vaapi_video_decode_accelerator.h
index 11cc082..c38feeb 100644
--- a/content/common/gpu/media/vaapi_video_decode_accelerator.h
+++ b/content/common/gpu/media/vaapi_video_decode_accelerator.h
@@ -20,13 +20,13 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/memory/linked_ptr.h"
-#include "base/memory/shared_memory.h"
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/synchronization/condition_variable.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread.h"
 #include "content/common/content_export.h"
+#include "content/common/gpu/media/shared_memory_region.h"
 #include "content/common/gpu/media/vaapi_wrapper.h"
 #include "media/base/bitstream_buffer.h"
 #include "media/video/picture.h"
@@ -210,8 +210,7 @@
     ~InputBuffer();
 
     int32_t id;
-    size_t size;
-    scoped_ptr<base::SharedMemory> shm;
+    scoped_ptr<SharedMemoryRegion> shm;
   };
 
   // Queue for incoming input buffers.
diff --git a/content/common/gpu/media/vaapi_video_encode_accelerator.cc b/content/common/gpu/media/vaapi_video_encode_accelerator.cc
index 049cd7a..4e2a06e 100644
--- a/content/common/gpu/media/vaapi_video_encode_accelerator.cc
+++ b/content/common/gpu/media/vaapi_video_encode_accelerator.cc
@@ -13,6 +13,7 @@
 #include "base/metrics/histogram.h"
 #include "base/numerics/safe_conversions.h"
 #include "content/common/gpu/media/h264_dpb.h"
+#include "content/common/gpu/media/shared_memory_region.h"
 #include "media/base/bind_to_current_loop.h"
 #include "third_party/libva/va/va_enc_h264.h"
 
@@ -100,13 +101,10 @@
 };
 
 struct VaapiVideoEncodeAccelerator::BitstreamBufferRef {
-  BitstreamBufferRef(int32_t id,
-                     scoped_ptr<base::SharedMemory> shm,
-                     size_t size)
-      : id(id), shm(std::move(shm)), size(size) {}
+  BitstreamBufferRef(int32_t id, scoped_ptr<SharedMemoryRegion> shm)
+      : id(id), shm(std::move(shm)) {}
   const int32_t id;
-  const scoped_ptr<base::SharedMemory> shm;
-  const size_t size;
+  const scoped_ptr<SharedMemoryRegion> shm;
 };
 
 media::VideoEncodeAccelerator::SupportedProfiles
@@ -546,11 +544,8 @@
 
   size_t data_size = 0;
   if (!vaapi_wrapper_->DownloadAndDestroyCodedBuffer(
-          encode_job->coded_buffer,
-          encode_job->input_surface->id(),
-          target_data,
-          buffer->size,
-          &data_size)) {
+          encode_job->coded_buffer, encode_job->input_surface->id(),
+          target_data, buffer->shm->size(), &data_size)) {
     NOTIFY_ERROR(kPlatformFailureError, "Failed downloading coded buffer");
     return;
   }
@@ -669,15 +664,14 @@
     return;
   }
 
-  scoped_ptr<base::SharedMemory> shm(
-      new base::SharedMemory(buffer.handle(), false));
-  if (!shm->Map(buffer.size())) {
+  scoped_ptr<SharedMemoryRegion> shm(new SharedMemoryRegion(buffer, false));
+  if (!shm->Map()) {
     NOTIFY_ERROR(kPlatformFailureError, "Failed mapping shared memory.");
     return;
   }
 
   scoped_ptr<BitstreamBufferRef> buffer_ref(
-      new BitstreamBufferRef(buffer.id(), std::move(shm), buffer.size()));
+      new BitstreamBufferRef(buffer.id(), std::move(shm)));
 
   encoder_thread_task_runner_->PostTask(
       FROM_HERE,
diff --git a/content/common/mojo/mojo_shell_connection_impl.cc b/content/common/mojo/mojo_shell_connection_impl.cc
index eb11c96..839e206 100644
--- a/content/common/mojo/mojo_shell_connection_impl.cc
+++ b/content/common/mojo/mojo_shell_connection_impl.cc
@@ -95,8 +95,7 @@
 }
 
 void MojoShellConnectionImpl::Initialize(mojo::Connector* connector,
-                                         const std::string& url,
-                                         const std::string& user_id,
+                                         const mojo::Identity& identity,
                                          uint32_t id) {
   initialized_ = true;
 }
diff --git a/content/common/mojo/mojo_shell_connection_impl.h b/content/common/mojo/mojo_shell_connection_impl.h
index c63b174..5f53363 100644
--- a/content/common/mojo/mojo_shell_connection_impl.h
+++ b/content/common/mojo/mojo_shell_connection_impl.h
@@ -56,8 +56,8 @@
   ~MojoShellConnectionImpl() override;
 
   // mojo::ShellClient:
-  void Initialize(mojo::Connector* connector, const std::string& url,
-                  const std::string& user_id, uint32_t id) override;
+  void Initialize(mojo::Connector* connector, const mojo::Identity& identity,
+                  uint32_t id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
   // MojoShellConnection:
diff --git a/content/common/push_messaging_messages.h b/content/common/push_messaging_messages.h
index df88b2f..38a39e8 100644
--- a/content/common/push_messaging_messages.h
+++ b/content/common/push_messaging_messages.h
@@ -8,7 +8,6 @@
 #include <stdint.h>
 
 #include "content/public/common/push_messaging_status.h"
-#include "content/public/common/push_subscription_options.h"
 #include "ipc/ipc_message_macros.h"
 #include "third_party/WebKit/public/platform/modules/push_messaging/WebPushError.h"
 #include "third_party/WebKit/public/platform/modules/push_messaging/WebPushPermissionStatus.h"
@@ -30,11 +29,6 @@
     blink::WebPushError::ErrorType,
     blink::WebPushError::ErrorType::ErrorTypeLast)
 
-IPC_STRUCT_TRAITS_BEGIN(content::PushSubscriptionOptions)
-  IPC_STRUCT_TRAITS_MEMBER(user_visible_only)
-  IPC_STRUCT_TRAITS_MEMBER(sender_info)
-IPC_STRUCT_TRAITS_END()
-
 // Messages sent from the browser to the child process.
 
 IPC_MESSAGE_ROUTED4(PushMessagingMsg_SubscribeFromDocumentSuccess,
@@ -86,16 +80,17 @@
 
 // Messages sent from the child process to the browser.
 
-IPC_MESSAGE_CONTROL4(PushMessagingHostMsg_SubscribeFromDocument,
+IPC_MESSAGE_CONTROL5(PushMessagingHostMsg_SubscribeFromDocument,
                      int32_t /* render_frame_id */,
                      int32_t /* request_id */,
-                     content::PushSubscriptionOptions /* options */,
+                     std::string /* sender_id */,
+                     bool /* user_visible */,
                      int64_t /* service_worker_registration_id */)
 
 IPC_MESSAGE_CONTROL3(PushMessagingHostMsg_SubscribeFromWorker,
                      int32_t /* request_id */,
                      int64_t /* service_worker_registration_id */,
-                     content::PushSubscriptionOptions /* options */)
+                     bool /* user_visible */)
 
 IPC_MESSAGE_CONTROL2(PushMessagingHostMsg_Unsubscribe,
                      int32_t /* request_id */,
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 4f5c244..01e33ec 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -780,8 +780,6 @@
       'browser/frame_host/render_widget_host_view_child_frame.h',
       'browser/frame_host/render_widget_host_view_guest.cc',
       'browser/frame_host/render_widget_host_view_guest.h',
-      'browser/frame_host/traced_frame_tree_node.cc',
-      'browser/frame_host/traced_frame_tree_node.h',
       'browser/gamepad/gamepad_consumer.h',
       'browser/gamepad/gamepad_data_fetcher.cc',
       'browser/gamepad/gamepad_data_fetcher.h',
diff --git a/content/content_common.gypi b/content/content_common.gypi
index 0400de30..07dcea9 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -432,6 +432,8 @@
       'common/gpu/media/media_messages.h',
       'common/gpu/media/media_service.cc',
       'common/gpu/media/media_service.h',
+      'common/gpu/media/shared_memory_region.cc',
+      'common/gpu/media/shared_memory_region.h',
       'common/gpu/stream_texture_android.cc',
       'common/gpu/stream_texture_android.h',
       'common/host_discardable_shared_memory_manager.cc',
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java
index a5b0ed0..7a739095 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java
@@ -128,8 +128,12 @@
         assertTrue(mContentViewCore.hasSelection());
     }
 
+    /*
     @SmallTest
     @Feature({"TextInput"})
+    https://crbug.com/592428
+    */
+    @FlakyTest
     public void testPastePopupNotShownOnLongPressingNonEmptyInput() throws Throwable {
         copyStringToClipboard("SampleTextToCopy");
         DOMUtils.longPressNode(this, mContentViewCore, "empty_input_text");
@@ -139,8 +143,12 @@
         waitForPastePopupStatus(false);
     }
 
+    /*
     @SmallTest
     @Feature({"TextInput"})
+    https://crbug.com/592428
+    */
+    @FlakyTest
     public void testPastePopupClearedOnTappingEmptyInput() throws Throwable {
         copyStringToClipboard("SampleTextToCopy");
         DOMUtils.longPressNode(this, mContentViewCore, "empty_input_text");
@@ -149,8 +157,12 @@
         waitForPastePopupStatus(false);
     }
 
+    /*
     @SmallTest
     @Feature({"TextInput"})
+    https://crbug.com/592428
+    */
+    @FlakyTest
     public void testPastePopupClearedOnTappingNonEmptyInput() throws Throwable {
         copyStringToClipboard("SampleTextToCopy");
         DOMUtils.longPressNode(this, mContentViewCore, "empty_input_text");
@@ -159,8 +171,12 @@
         waitForPastePopupStatus(false);
     }
 
+    /*
     @SmallTest
     @Feature({"TextInput"})
+    https://crbug.com/592428
+    */
+    @FlakyTest
     public void testPastePopupClearedOnTappingOutsideInput() throws Throwable {
         copyStringToClipboard("SampleTextToCopy");
         DOMUtils.longPressNode(this, mContentViewCore, "empty_input_text");
@@ -169,8 +185,12 @@
         waitForPastePopupStatus(false);
     }
 
+    /*
     @SmallTest
     @Feature({"TextInput"})
+    https://crbug.com/592428
+    */
+    @FlakyTest
     public void testPastePopupClearedOnLongPressingOutsideInput() throws Throwable {
         copyStringToClipboard("SampleTextToCopy");
         DOMUtils.longPressNode(this, mContentViewCore, "empty_input_text");
@@ -179,8 +199,12 @@
         waitForPastePopupStatus(false);
     }
 
+    /*
     @SmallTest
     @Feature({"TextInput"})
+    https://crbug.com/592428
+    */
+    @FlakyTest
     public void testPastePopupNotShownOnLongPressingDisabledInput() throws Throwable {
         copyStringToClipboard("SampleTextToCopy");
         DOMUtils.longPressNode(this, mContentViewCore, "empty_input_text");
@@ -191,8 +215,12 @@
         assertFalse(mContentViewCore.hasInsertion());
     }
 
+    /*
     @SmallTest
     @Feature({"TextInput"})
+    https://crbug.com/592428
+    */
+    @FlakyTest
     public void testPastePopupDismissedOnDestroy() throws Throwable {
         copyStringToClipboard("SampleTextToCopy");
         DOMUtils.longPressNode(this, mContentViewCore, "empty_input_text");
diff --git a/content/public/browser/push_messaging_service.h b/content/public/browser/push_messaging_service.h
index 993e2816..86aa34e 100644
--- a/content/public/browser/push_messaging_service.h
+++ b/content/public/browser/push_messaging_service.h
@@ -19,7 +19,6 @@
 
 class BrowserContext;
 class ServiceWorkerContext;
-struct PushSubscriptionOptions;
 
 // A push service-agnostic interface that the Push API uses for talking to
 // push messaging services like GCM. Must only be used on the UI thread.
@@ -50,22 +49,24 @@
   // origins and push registrations.
   virtual GURL GetPushEndpoint() = 0;
 
-  // Subscribe the given |options.sender_info| with the push messaging service
-  // in a document context. The frame is known and a permission UI may be
-  // displayed to the user.
+  // Subscribe the given |sender_id| with the push messaging service in a
+  // document context. The frame is known and a permission UI may be displayed
+  // to the user.
   virtual void SubscribeFromDocument(const GURL& requesting_origin,
                                      int64_t service_worker_registration_id,
+                                     const std::string& sender_id,
                                      int renderer_id,
                                      int render_frame_id,
-                                     const PushSubscriptionOptions& options,
+                                     bool user_visible,
                                      const RegisterCallback& callback) = 0;
 
-  // Subscribe the given |options.sender_info| with the push messaging service.
-  // The frame is not known so if permission was not previously granted by the
-  // user this request should fail.
+  // Subscribe the given |sender_id| with the push messaging service. The frame
+  // is not known so if permission was not previously granted by the user this
+  // request should fail.
   virtual void SubscribeFromWorker(const GURL& requesting_origin,
                                    int64_t service_worker_registration_id,
-                                   const PushSubscriptionOptions& options,
+                                   const std::string& sender_id,
+                                   bool user_visible,
                                    const RegisterCallback& callback) = 0;
 
   // Retrieves the encryption information associated with the subscription
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 50b2d6f..01a3a57 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -222,6 +222,10 @@
 // Disables the Web Notification and the Push APIs.
 const char kDisableNotifications[]          = "disable-notifications";
 
+// Disable partial raster in renderer. Disabling this switch also disables
+// the use of persistent gpu memory buffers.
+const char kDisablePartialRaster[] = "disable-partial-raster";
+
 // Disable Pepper3D.
 const char kDisablePepper3d[]               = "disable-pepper-3d";
 
@@ -395,10 +399,6 @@
 const char kEnableNotificationActionIcons[] =
     "enable-notification-action-icons";
 
-// Enables partial raster. Enabling this switch also enables the use of
-// persistent gpu memory buffers.
-const char kEnablePartialRaster[] = "enable-partial-raster";
-
 // Enables compositor-accelerated touch-screen pinch gestures.
 const char kEnablePinch[]                   = "enable-pinch";
 
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 3a1b104..c5843ffa 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -73,6 +73,7 @@
 CONTENT_EXPORT extern const char kDisableNamespaceSandbox[];
 CONTENT_EXPORT extern const char kDisableNativeGpuMemoryBuffers[];
 CONTENT_EXPORT extern const char kDisableNotifications[];
+CONTENT_EXPORT extern const char kDisablePartialRaster[];
 extern const char kDisablePepper3d[];
 CONTENT_EXPORT extern const char kDisablePermissionsAPI[];
 CONTENT_EXPORT extern const char kDisablePinch[];
@@ -122,7 +123,6 @@
 extern const char kEnableMemoryBenchmarking[];
 CONTENT_EXPORT extern const char kEnableNetworkInformation[];
 CONTENT_EXPORT extern const char kEnableNotificationActionIcons[];
-CONTENT_EXPORT extern const char kEnablePartialRaster[];
 CONTENT_EXPORT extern const char kEnablePinch[];
 CONTENT_EXPORT extern const char kEnablePluginPlaceholderTesting[];
 CONTENT_EXPORT extern const char kEnablePreciseMemoryInfo[];
diff --git a/content/public/common/push_subscription_options.h b/content/public/common/push_subscription_options.h
deleted file mode 100644
index 1a2da0a..0000000
--- a/content/public/common/push_subscription_options.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_PUBLIC_COMMON_PUSH_SUBSCRIPTION_OPTIONS_H_
-#define CONTENT_PUBLIC_COMMON_PUSH_SUBSCRIPTION_OPTIONS_H_
-
-#include <string>
-
-#include "content/common/content_export.h"
-
-namespace content {
-
-// Structure to hold the options provided from the web app developer as
-// part of asking for a new push subscription.
-struct CONTENT_EXPORT PushSubscriptionOptions {
-  PushSubscriptionOptions() {}
-  ~PushSubscriptionOptions() {}
-
-  // Whether or not the app developer agrees to provide user visible
-  // notifications whenever they receive a push message.
-  bool user_visible_only = false;
-
-  // The unique identifier of the application service which is used to
-  // verify the push message before delivery. This could either be an ID
-  // assigned by the developer console or the app server's public key.
-  std::string sender_info;
-};
-
-}  // namespace content
-
-#endif  // CONTENT_PUBLIC_COMMON_CONTENT_PUSH_SUBSCRIPTION_OPTIONS_H_
diff --git a/content/public/test/test_mojo_app.cc b/content/public/test/test_mojo_app.cc
index 7c5fdb9..253c64f 100644
--- a/content/public/test/test_mojo_app.cc
+++ b/content/public/test/test_mojo_app.cc
@@ -22,7 +22,7 @@
 }
 
 bool TestMojoApp::AcceptConnection(mojo::Connection* connection) {
-  requestor_name_ = connection->GetRemoteApplicationName();
+  requestor_name_ = connection->GetRemoteIdentity().name();
   connection->AddInterface<TestMojoService>(this);
   return true;
 }
diff --git a/content/renderer/media/android/webmediaplayer_android.cc b/content/renderer/media/android/webmediaplayer_android.cc
index 7252043..8831cf0 100644
--- a/content/renderer/media/android/webmediaplayer_android.cc
+++ b/content/renderer/media/android/webmediaplayer_android.cc
@@ -794,14 +794,14 @@
   return 0;
 }
 
-unsigned WebMediaPlayerAndroid::audioDecodedByteCount() const {
+size_t WebMediaPlayerAndroid::audioDecodedByteCount() const {
   if (media_source_delegate_)
     return media_source_delegate_->AudioDecodedByteCount();
   NOTIMPLEMENTED();
   return 0;
 }
 
-unsigned WebMediaPlayerAndroid::videoDecodedByteCount() const {
+size_t WebMediaPlayerAndroid::videoDecodedByteCount() const {
   if (media_source_delegate_)
     return media_source_delegate_->VideoDecodedByteCount();
   NOTIMPLEMENTED();
diff --git a/content/renderer/media/android/webmediaplayer_android.h b/content/renderer/media/android/webmediaplayer_android.h
index a25a75d..932b521 100644
--- a/content/renderer/media/android/webmediaplayer_android.h
+++ b/content/renderer/media/android/webmediaplayer_android.h
@@ -174,8 +174,8 @@
   // Provide statistics.
   unsigned decodedFrameCount() const override;
   unsigned droppedFrameCount() const override;
-  unsigned audioDecodedByteCount() const override;
-  unsigned videoDecodedByteCount() const override;
+  size_t audioDecodedByteCount() const override;
+  size_t videoDecodedByteCount() const override;
 
   // cc::VideoFrameProvider implementation. These methods are running on the
   // compositor thread.
diff --git a/content/renderer/media/html_video_element_capturer_source_unittest.cc b/content/renderer/media/html_video_element_capturer_source_unittest.cc
index 89e518bf..56401b8 100644
--- a/content/renderer/media/html_video_element_capturer_source_unittest.cc
+++ b/content/renderer/media/html_video_element_capturer_source_unittest.cc
@@ -67,8 +67,8 @@
   unsigned decodedFrameCount() const override { return 0; }
   unsigned droppedFrameCount() const override { return 0; }
   unsigned corruptedFrameCount() const override { return 0; }
-  unsigned audioDecodedByteCount() const override { return 0; }
-  unsigned videoDecodedByteCount() const override { return 0; }
+  size_t audioDecodedByteCount() const override { return 0; }
+  size_t videoDecodedByteCount() const override { return 0; }
 
   void paint(blink::WebCanvas* canvas,
              const blink::WebRect& paint_rectangle,
diff --git a/content/renderer/media/rtc_video_decoder.cc b/content/renderer/media/rtc_video_decoder.cc
index 7274869..069f4182 100644
--- a/content/renderer/media/rtc_video_decoder.cc
+++ b/content/renderer/media/rtc_video_decoder.cc
@@ -508,7 +508,7 @@
     // Create a BitstreamBuffer and send to VDA to decode.
     media::BitstreamBuffer bitstream_buffer(
         buffer_data.bitstream_buffer_id, shm_buffer->handle(), buffer_data.size,
-        base::TimeDelta::FromInternalValue(buffer_data.timestamp));
+        0, base::TimeDelta::FromInternalValue(buffer_data.timestamp));
     const bool inserted =
         bitstream_buffers_in_decoder_.insert(
             std::make_pair(bitstream_buffer.id(), shm_buffer.release())).second;
diff --git a/content/renderer/media/webmediaplayer_ms.cc b/content/renderer/media/webmediaplayer_ms.cc
index 0a726303..9f59a76 100644
--- a/content/renderer/media/webmediaplayer_ms.cc
+++ b/content/renderer/media/webmediaplayer_ms.cc
@@ -368,13 +368,13 @@
   return compositor_->dropped_frame_count();
 }
 
-unsigned WebMediaPlayerMS::audioDecodedByteCount() const {
+size_t WebMediaPlayerMS::audioDecodedByteCount() const {
   DCHECK(thread_checker_.CalledOnValidThread());
   NOTIMPLEMENTED();
   return 0;
 }
 
-unsigned WebMediaPlayerMS::videoDecodedByteCount() const {
+size_t WebMediaPlayerMS::videoDecodedByteCount() const {
   DCHECK(thread_checker_.CalledOnValidThread());
   NOTIMPLEMENTED();
   return 0;
diff --git a/content/renderer/media/webmediaplayer_ms.h b/content/renderer/media/webmediaplayer_ms.h
index e43afba3..28e7a160 100644
--- a/content/renderer/media/webmediaplayer_ms.h
+++ b/content/renderer/media/webmediaplayer_ms.h
@@ -131,8 +131,8 @@
 
   unsigned decodedFrameCount() const override;
   unsigned droppedFrameCount() const override;
-  unsigned audioDecodedByteCount() const override;
-  unsigned videoDecodedByteCount() const override;
+  size_t audioDecodedByteCount() const override;
+  size_t videoDecodedByteCount() const override;
 
   // WebMediaPlayerDelegate::Observer implementation.
   void OnHidden(bool must_suspend) override;
diff --git a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
index c513c11..eb49d9d 100644
--- a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
+++ b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
@@ -473,9 +473,9 @@
               switches::kEnforceWebRtcIPPermissionCheck);
       create_media_permission =
           create_media_permission ||
-          StartsWith(base::FieldTrialList::FindFullName(
-                         "WebRTC-LocalIPPermissionCheck"),
-                     "Enabled", base::CompareCase::SENSITIVE);
+          !StartsWith(base::FieldTrialList::FindFullName(
+                          "WebRTC-LocalIPPermissionCheck"),
+                      "Disabled", base::CompareCase::SENSITIVE);
       if (create_media_permission) {
         content::RenderFrameImpl* render_frame =
             content::RenderFrameImpl::FromWebFrame(web_frame);
diff --git a/content/renderer/pepper/v8_var_converter_unittest.cc b/content/renderer/pepper/v8_var_converter_unittest.cc
index e030ffdb..cd07abb 100644
--- a/content/renderer/pepper/v8_var_converter_unittest.cc
+++ b/content/renderer/pepper/v8_var_converter_unittest.cc
@@ -29,7 +29,6 @@
 #include "ppapi/shared_impl/var.h"
 #include "ppapi/shared_impl/var_tracker.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h"
 #include "v8/include/v8.h"
 
 using ppapi::ArrayBufferVar;
@@ -404,7 +403,6 @@
     v8::Local<v8::Context> context =
         v8::Local<v8::Context>::New(isolate_, context_);
     v8::Context::Scope context_scope(context);
-    blink::WebScopedMicrotaskSuppression microtasks_scope;
 
     const char* source =
         "(function() {"
diff --git a/content/renderer/push_messaging/push_messaging_dispatcher.cc b/content/renderer/push_messaging/push_messaging_dispatcher.cc
index ef35db5..d1070432 100644
--- a/content/renderer/push_messaging/push_messaging_dispatcher.cc
+++ b/content/renderer/push_messaging/push_messaging_dispatcher.cc
@@ -44,63 +44,46 @@
     blink::WebPushSubscriptionCallbacks* callbacks) {
   DCHECK(service_worker_registration);
   DCHECK(callbacks);
-  // If a developer provided an application server key in |options|, skip
-  // fetching the manifest.
-  if (options.applicationServerKey.isEmpty()) {
-    RenderFrameImpl::FromRoutingID(routing_id())
-        ->manifest_manager()
-        ->GetManifest(base::Bind(
-            &PushMessagingDispatcher::DidGetManifest, base::Unretained(this),
-            service_worker_registration, options, callbacks));
-  } else {
-    PushSubscriptionOptions content_options;
-    content_options.user_visible_only = options.userVisibleOnly;
-    content_options.sender_info = options.applicationServerKey.utf8();
-    DoSubscribe(service_worker_registration, content_options, callbacks);
-  }
-}
-
-void PushMessagingDispatcher::DidGetManifest(
-    blink::WebServiceWorkerRegistration* service_worker_registration,
-    const blink::WebPushSubscriptionOptions& options,
-    blink::WebPushSubscriptionCallbacks* callbacks,
-    const Manifest& manifest) {
-  int request_id = subscription_callbacks_.Add(callbacks);
-  // Get the sender_info from the manifest since it wasn't provided by
-  // the caller.
-  if (manifest.IsEmpty()) {
-    OnSubscribeFromDocumentError(
-        request_id, PUSH_REGISTRATION_STATUS_MANIFEST_EMPTY_OR_MISSING);
-    return;
-  }
-
-  PushSubscriptionOptions content_options;
-  content_options.user_visible_only = options.userVisibleOnly;
-  if (!manifest.gcm_sender_id.is_null()) {
-    content_options.sender_info =
-        base::UTF16ToUTF8(manifest.gcm_sender_id.string());
-  }
-
-  DoSubscribe(service_worker_registration, content_options, callbacks);
+  RenderFrameImpl::FromRoutingID(routing_id())
+      ->manifest_manager()
+      ->GetManifest(base::Bind(
+          &PushMessagingDispatcher::DoSubscribe, base::Unretained(this),
+          service_worker_registration, options, callbacks));
 }
 
 void PushMessagingDispatcher::DoSubscribe(
     blink::WebServiceWorkerRegistration* service_worker_registration,
-    const PushSubscriptionOptions& options,
-    blink::WebPushSubscriptionCallbacks* callbacks) {
+    const blink::WebPushSubscriptionOptions& options,
+    blink::WebPushSubscriptionCallbacks* callbacks,
+    const Manifest& manifest) {
   int request_id = subscription_callbacks_.Add(callbacks);
   int64_t service_worker_registration_id =
       static_cast<WebServiceWorkerRegistrationImpl*>(
           service_worker_registration)
           ->registration_id();
 
-  if (options.sender_info.empty()) {
+  if (manifest.IsEmpty()) {
+    OnSubscribeFromDocumentError(
+        request_id, PUSH_REGISTRATION_STATUS_MANIFEST_EMPTY_OR_MISSING);
+    return;
+  }
+
+  std::string sender_id =
+      manifest.gcm_sender_id.is_null()
+          ? std::string()
+          : base::UTF16ToUTF8(manifest.gcm_sender_id.string());
+  if (sender_id.empty()) {
     OnSubscribeFromDocumentError(request_id,
                                  PUSH_REGISTRATION_STATUS_NO_SENDER_ID);
     return;
   }
+
   Send(new PushMessagingHostMsg_SubscribeFromDocument(
-      routing_id(), request_id, options, service_worker_registration_id));
+      routing_id(), request_id,
+      manifest.gcm_sender_id.is_null()
+          ? std::string()
+          : base::UTF16ToUTF8(manifest.gcm_sender_id.string()),
+      options.userVisibleOnly, service_worker_registration_id));
 }
 
 void PushMessagingDispatcher::OnSubscribeFromDocumentSuccess(
diff --git a/content/renderer/push_messaging/push_messaging_dispatcher.h b/content/renderer/push_messaging/push_messaging_dispatcher.h
index 71294e2..ca6610b 100644
--- a/content/renderer/push_messaging/push_messaging_dispatcher.h
+++ b/content/renderer/push_messaging/push_messaging_dispatcher.h
@@ -29,7 +29,6 @@
 namespace content {
 
 struct Manifest;
-struct PushSubscriptionOptions;
 
 class PushMessagingDispatcher : public RenderFrameObserver,
                                 public blink::WebPushClient {
@@ -47,17 +46,12 @@
       const blink::WebPushSubscriptionOptions& options,
       blink::WebPushSubscriptionCallbacks* callbacks) override;
 
-  void DidGetManifest(
+  void DoSubscribe(
       blink::WebServiceWorkerRegistration* service_worker_registration,
       const blink::WebPushSubscriptionOptions& options,
       blink::WebPushSubscriptionCallbacks* callbacks,
       const Manifest& manifest);
 
-  void DoSubscribe(
-      blink::WebServiceWorkerRegistration* service_worker_registration,
-      const PushSubscriptionOptions& options,
-      blink::WebPushSubscriptionCallbacks* callbacks);
-
   void OnSubscribeFromDocumentSuccess(int32_t request_id,
                                       const GURL& endpoint,
                                       const std::vector<uint8_t>& p256dh,
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 82e5f3c7..6b89e3b6 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -6088,8 +6088,11 @@
   if (!connector_)
     GetServiceRegistry()->ConnectToRemoteService(mojo::GetProxy(&connector_));
   mojo::shell::mojom::InterfaceProviderPtr interface_provider;
-  connector_->Connect(url.spec(), mojo::shell::mojom::kInheritUserID,
-                      GetProxy(&interface_provider), nullptr,
+  mojo::shell::mojom::IdentityPtr target(mojo::shell::mojom::Identity::New());
+  target->name = url.spec();
+  target->user_id = mojo::shell::mojom::kInheritUserID;
+  target->instance = "";
+  connector_->Connect(std::move(target), GetProxy(&interface_provider), nullptr,
                       base::Bind(&OnGotInstanceID));
   return interface_provider;
 }
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 24a12685..8a45ff8 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -743,7 +743,7 @@
 
   is_zero_copy_enabled_ = command_line.HasSwitch(switches::kEnableZeroCopy);
   is_partial_raster_enabled_ =
-      command_line.HasSwitch(switches::kEnablePartialRaster);
+      !command_line.HasSwitch(switches::kDisablePartialRaster);
   is_gpu_memory_buffer_compositor_resources_enabled_ = command_line.HasSwitch(
       switches::kEnableGpuMemoryBufferCompositorResources);
 
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index 78360857..be020d4c 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -1419,7 +1419,6 @@
       // Retrieve the content of this page and compare it with the expected
       // result.
       const int kMaxOutputCharacters = 128;
-      view()->GetWebView()->updateAllLifecyclePhases();
       base::string16 output = WebFrameContentDumper::dumpFrameTreeAsText(
           GetMainFrame(), kMaxOutputCharacters);
       EXPECT_EQ(base::WideToUTF16(ime_message->result), output);
@@ -1470,7 +1469,6 @@
     // Copy the document content to std::wstring and compare with the
     // expected result.
     const int kMaxOutputCharacters = 16;
-    view()->GetWebView()->updateAllLifecyclePhases();
     base::string16 output = WebFrameContentDumper::dumpFrameTreeAsText(
         GetMainFrame(), kMaxOutputCharacters);
     EXPECT_EQ(base::WideToUTF16(kTextDirection[i].expected_result), output);
@@ -1801,7 +1799,6 @@
   // Copy the document content to std::wstring and compare with the
   // expected result.
   const int kMaxOutputCharacters = 256;
-  view()->GetWebView()->updateAllLifecyclePhases();
   std::string output = base::UTF16ToUTF8(
       base::StringPiece16(WebFrameContentDumper::dumpFrameTreeAsText(
           GetMainFrame(), kMaxOutputCharacters)));
@@ -1924,7 +1921,6 @@
   main_frame->didFailProvisionalLoad(web_frame, error,
                                      blink::WebStandardCommit);
   const int kMaxOutputCharacters = 22;
-  view()->GetWebView()->updateAllLifecyclePhases();
   EXPECT_EQ("", base::UTF16ToASCII(base::StringPiece16(
                     WebFrameContentDumper::dumpFrameTreeAsText(
                         web_frame, kMaxOutputCharacters))));
@@ -1960,7 +1956,6 @@
   // The error page itself is loaded asynchronously.
   FrameLoadWaiter(main_frame).Wait();
   const int kMaxOutputCharacters = 22;
-  view()->GetWebView()->updateAllLifecyclePhases();
   EXPECT_EQ("A suffusion of yellow.",
             base::UTF16ToASCII(
                 base::StringPiece16(WebFrameContentDumper::dumpFrameTreeAsText(
@@ -1996,7 +1991,6 @@
   // The error page itself is loaded asynchronously.
   FrameLoadWaiter(main_frame).Wait();
   const int kMaxOutputCharacters = 22;
-  view()->GetWebView()->updateAllLifecyclePhases();
   EXPECT_EQ("A suffusion of yellow.",
             base::UTF16ToASCII(
                 base::StringPiece16(WebFrameContentDumper::dumpFrameTreeAsText(
diff --git a/content/renderer/render_view_browsertest_mac.mm b/content/renderer/render_view_browsertest_mac.mm
index ce96f13..2b89084 100644
--- a/content/renderer/render_view_browsertest_mac.mm
+++ b/content/renderer/render_view_browsertest_mac.mm
@@ -12,7 +12,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/web/WebFrameContentDumper.h"
 #include "third_party/WebKit/public/web/WebLocalFrame.h"
-#include "third_party/WebKit/public/web/WebView.h"
 
 #include <Carbon/Carbon.h>  // for the kVK_* constants.
 #include <Cocoa/Cocoa.h>
@@ -108,7 +107,6 @@
   SendNativeKeyEvent(NativeWebKeyboardEvent(arrowDownKeyDown));
   ProcessPendingMessages();
   ExecuteJavaScriptForTests("scroll.textContent = window.pageYOffset");
-  view->GetWebView()->updateAllLifecyclePhases();
   output = WebFrameContentDumper::dumpFrameTreeAsText(GetMainFrame(),
                                                       kMaxOutputCharacters);
   EXPECT_EQ(kArrowDownScrollDown, base::UTF16ToASCII(output));
@@ -119,7 +117,6 @@
   SendNativeKeyEvent(NativeWebKeyboardEvent(arrowUpKeyDown));
   ProcessPendingMessages();
   ExecuteJavaScriptForTests("scroll.textContent = window.pageYOffset");
-  view->GetWebView()->updateAllLifecyclePhases();
   output = WebFrameContentDumper::dumpFrameTreeAsText(GetMainFrame(),
                                                       kMaxOutputCharacters);
   EXPECT_EQ(kArrowUpScrollUp, base::UTF16ToASCII(output));
@@ -135,7 +132,6 @@
   SendNativeKeyEvent(NativeWebKeyboardEvent(arrowDownKeyDown));
   ProcessPendingMessages();
   ExecuteJavaScriptForTests("scroll.textContent = window.pageYOffset");
-  view->GetWebView()->updateAllLifecyclePhases();
   output = WebFrameContentDumper::dumpFrameTreeAsText(GetMainFrame(),
                                                       kMaxOutputCharacters);
   EXPECT_EQ(kArrowDownNoScroll, base::UTF16ToASCII(output));
@@ -146,7 +142,6 @@
   SendNativeKeyEvent(NativeWebKeyboardEvent(arrowUpKeyDown));
   ProcessPendingMessages();
   ExecuteJavaScriptForTests("scroll.textContent = window.pageYOffset");
-  view->GetWebView()->updateAllLifecyclePhases();
   output = WebFrameContentDumper::dumpFrameTreeAsText(GetMainFrame(),
                                                       kMaxOutputCharacters);
   EXPECT_EQ(kArrowUpNoScroll, base::UTF16ToASCII(output));
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 9ce9869..4014147b 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -1254,7 +1254,6 @@
   // sends text in the wrong order. See http://crbug.com/584798.
   // TODO(dglazkov): WebFrameContentDumper should only be used for
   // testing purposes. See http://crbug.com/585164.
-  webview()->updateAllLifecyclePhases();
   std::string text =
       WebFrameContentDumper::dumpFrameTreeAsText(
           webview()->mainFrame()->toWebLocalFrame(), kMaximumMessageSize)
diff --git a/content/shell/browser/layout_test/layout_test_push_messaging_service.cc b/content/shell/browser/layout_test/layout_test_push_messaging_service.cc
index c346a08..11554e94 100644
--- a/content/shell/browser/layout_test/layout_test_push_messaging_service.cc
+++ b/content/shell/browser/layout_test/layout_test_push_messaging_service.cc
@@ -8,7 +8,6 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "content/public/browser/permission_type.h"
-#include "content/public/common/push_subscription_options.h"
 #include "content/shell/browser/layout_test/layout_test_browser_context.h"
 #include "content/shell/browser/layout_test/layout_test_content_browser_client.h"
 #include "content/shell/browser/layout_test/layout_test_permission_manager.h"
@@ -68,20 +67,22 @@
 void LayoutTestPushMessagingService::SubscribeFromDocument(
     const GURL& requesting_origin,
     int64_t service_worker_registration_id,
+    const std::string& sender_id,
     int renderer_id,
     int render_frame_id,
-    const PushSubscriptionOptions& options,
+    bool user_visible,
     const PushMessagingService::RegisterCallback& callback) {
   SubscribeFromWorker(requesting_origin, service_worker_registration_id,
-                      options, callback);
+                      sender_id, user_visible, callback);
 }
 
 void LayoutTestPushMessagingService::SubscribeFromWorker(
     const GURL& requesting_origin,
     int64_t service_worker_registration_id,
-    const PushSubscriptionOptions& options,
+    const std::string& sender_id,
+    bool user_visible,
     const PushMessagingService::RegisterCallback& callback) {
-  if (GetPermissionStatus(requesting_origin, options.user_visible_only) ==
+  if (GetPermissionStatus(requesting_origin, user_visible) ==
       blink::WebPushPermissionStatusGranted) {
     std::vector<uint8_t> p256dh(
         kTestP256Key, kTestP256Key + arraysize(kTestP256Key));
diff --git a/content/shell/browser/layout_test/layout_test_push_messaging_service.h b/content/shell/browser/layout_test/layout_test_push_messaging_service.h
index 5e5a7a48..eb5e7e4 100644
--- a/content/shell/browser/layout_test/layout_test_push_messaging_service.h
+++ b/content/shell/browser/layout_test/layout_test_push_messaging_service.h
@@ -17,8 +17,6 @@
 
 namespace content {
 
-struct PushSubscriptionOptions;
-
 class LayoutTestPushMessagingService : public PushMessagingService {
  public:
   LayoutTestPushMessagingService();
@@ -29,14 +27,16 @@
   void SubscribeFromDocument(
       const GURL& requesting_origin,
       int64_t service_worker_registration_id,
+      const std::string& sender_id,
       int renderer_id,
       int render_frame_id,
-      const PushSubscriptionOptions& options,
+      bool user_visible,
       const PushMessagingService::RegisterCallback& callback) override;
   void SubscribeFromWorker(
       const GURL& requesting_origin,
       int64_t service_worker_registration_id,
-      const PushSubscriptionOptions& options,
+      const std::string& sender_id,
+      bool user_visible,
       const PushMessagingService::RegisterCallback& callback) override;
   void GetEncryptionInfo(
       const GURL& origin,
diff --git a/content/test/data/web_ui_mojo_shell_test.js b/content/test/data/web_ui_mojo_shell_test.js
index ab0661d5..b43a4f4c 100644
--- a/content/test/data/web_ui_mojo_shell_test.js
+++ b/content/test/data/web_ui_mojo_shell_test.js
@@ -34,8 +34,12 @@
     var connector = new connectorMojom.Connector.proxyClass(
         new router.Router(connectorPipe));
 
+    var identity = {};
+    identity.name = TEST_APP_URL;
+    identity.user_id = connectorMojom.kInheritUserID;
+    identity.instance = "";
     connector.connect(
-        TEST_APP_URL, connectorMojom.kInheritUserID,
+        identity,
         function (services) {
           var test = connectToService(services, testMojom.TestMojoService);
           test.getRequestorName().then(function(response) {
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index 9d9b366..7ff3f55b 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -1169,6 +1169,8 @@
   ENTERPRISE_PLATFORMKEYS_CHALLENGEMACHINEKEY,
   ENTERPRISE_PLATFORMKEYS_CHALLENGEUSERKEY,
   INPUTMETHODPRIVATE_NOTIFYIMEMENUITEMACTIVATED,
+  INPUT_IME_SHOWWINDOW,
+  INPUT_IME_HIDEWINDOW,
   // Last entry: Add new entries above, then run:
   // python tools/metrics/histograms/update_extension_histograms.py
   ENUM_BOUNDARY
diff --git a/extensions/common/features/base_feature_provider.cc b/extensions/common/features/base_feature_provider.cc
index 8bcec82c..069de38 100644
--- a/extensions/common/features/base_feature_provider.cc
+++ b/extensions/common/features/base_feature_provider.cc
@@ -149,19 +149,12 @@
 BaseFeatureProvider::~BaseFeatureProvider() {
 }
 
-const std::vector<std::string>& BaseFeatureProvider::GetAllFeatureNames()
-    const {
-  if (feature_names_.empty()) {
-    for (const auto& feature : features_)
-      feature_names_.push_back(feature.first);
-    // A std::map is sorted by its keys, so we don't need to sort feature_names_
-    // now.
-  }
-  return feature_names_;
+const FeatureMap& BaseFeatureProvider::GetAllFeatures() const {
+  return features_;
 }
 
 Feature* BaseFeatureProvider::GetFeature(const std::string& name) const {
-  const auto iter = features_.find(name);
+  FeatureMap::const_iterator iter = features_.find(name);
   if (iter != features_.end())
     return iter->second.get();
   else
@@ -186,15 +179,17 @@
 std::vector<Feature*> BaseFeatureProvider::GetChildren(const Feature& parent)
     const {
   std::string prefix = parent.name() + ".";
-  const auto first_child = features_.lower_bound(prefix);
+  const FeatureMap::const_iterator first_child = features_.lower_bound(prefix);
 
   // All children have names before (parent.name() + ('.'+1)).
   ++prefix[prefix.size() - 1];
-  const auto after_children = features_.lower_bound(prefix);
+  const FeatureMap::const_iterator after_children =
+      features_.lower_bound(prefix);
 
   std::vector<Feature*> result;
   result.reserve(std::distance(first_child, after_children));
-  for (auto it = first_child; it != after_children; ++it) {
+  for (FeatureMap::const_iterator it = first_child; it != after_children;
+       ++it) {
     result.push_back(it->second.get());
   }
   return result;
diff --git a/extensions/common/features/base_feature_provider.h b/extensions/common/features/base_feature_provider.h
index 3b766c8..0d61292 100644
--- a/extensions/common/features/base_feature_provider.h
+++ b/extensions/common/features/base_feature_provider.h
@@ -35,7 +35,7 @@
   Feature* GetParent(Feature* feature) const override;
   std::vector<Feature*> GetChildren(const Feature& parent) const override;
 
-  const std::vector<std::string>& GetAllFeatureNames() const override;
+  const FeatureMap& GetAllFeatures() const override;
 
  private:
   std::map<std::string, scoped_ptr<Feature>> features_;
diff --git a/extensions/common/features/feature_provider.h b/extensions/common/features/feature_provider.h
index 40d8ab8..ae97513 100644
--- a/extensions/common/features/feature_provider.h
+++ b/extensions/common/features/feature_provider.h
@@ -5,13 +5,18 @@
 #ifndef EXTENSIONS_COMMON_FEATURES_FEATURE_PROVIDER_H_
 #define EXTENSIONS_COMMON_FEATURES_FEATURE_PROVIDER_H_
 
+#include <map>
 #include <string>
 #include <vector>
 
+#include "base/memory/scoped_ptr.h"
+
 namespace extensions {
 
 class Feature;
 
+using FeatureMap = std::map<std::string, scoped_ptr<Feature>>;
+
 // Implemented by classes that can vend features.
 class FeatureProvider {
  public:
@@ -52,8 +57,8 @@
   // Returns the features inside the |parent| namespace, recursively.
   virtual std::vector<Feature*> GetChildren(const Feature& parent) const = 0;
 
-  // Returns all features described by this instance, in asciibetical order.
-  virtual const std::vector<std::string>& GetAllFeatureNames() const = 0;
+  // Returns a map containing all features described by this instance.
+  virtual const FeatureMap& GetAllFeatures() const = 0;
 };
 
 }  // namespace extensions
diff --git a/extensions/common/manifest.cc b/extensions/common/manifest.cc
index 112628f7..8bc2e28 100644
--- a/extensions/common/manifest.cc
+++ b/extensions/common/manifest.cc
@@ -146,20 +146,15 @@
 
   const FeatureProvider* manifest_feature_provider =
       FeatureProvider::GetManifestFeatures();
-  const std::vector<std::string>& feature_names =
-      manifest_feature_provider->GetAllFeatureNames();
-  for (std::vector<std::string>::const_iterator feature_name =
-           feature_names.begin();
-       feature_name != feature_names.end(); ++feature_name) {
+  for (const auto& map_entry : manifest_feature_provider->GetAllFeatures()) {
     // Use Get instead of HasKey because the former uses path expansion.
-    if (!value_->Get(*feature_name, NULL))
+    if (!value_->Get(map_entry.first, nullptr))
       continue;
 
-    Feature* feature = manifest_feature_provider->GetFeature(*feature_name);
-    Feature::Availability result = feature->IsAvailableToManifest(
+    Feature::Availability result = map_entry.second->IsAvailableToManifest(
         extension_id_, type_, location_, GetManifestVersion());
     if (!result.is_available())
-      warnings->push_back(InstallWarning(result.message(), *feature_name));
+      warnings->push_back(InstallWarning(result.message(), map_entry.first));
   }
 
   // Also generate warnings for keys that are not features.
diff --git a/extensions/renderer/activity_log_converter_strategy_unittest.cc b/extensions/renderer/activity_log_converter_strategy_unittest.cc
index aa80447..9237cad 100644
--- a/extensions/renderer/activity_log_converter_strategy_unittest.cc
+++ b/extensions/renderer/activity_log_converter_strategy_unittest.cc
@@ -6,7 +6,6 @@
 #include "base/values.h"
 #include "extensions/renderer/activity_log_converter_strategy.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h"
 #include "v8/include/v8.h"
 
 using content::V8ValueConverter;
@@ -123,7 +122,6 @@
       "};"
       "})();";
 
-  blink::WebScopedMicrotaskSuppression microtasks_scope;
   v8::Local<v8::Script> script(
       v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source)));
   v8::Local<v8::Object> v8_object = script->Run().As<v8::Object>();
diff --git a/extensions/renderer/api_definitions_natives.cc b/extensions/renderer/api_definitions_natives.cc
index 61ea7109..96f1f2c 100644
--- a/extensions/renderer/api_definitions_natives.cc
+++ b/extensions/renderer/api_definitions_natives.cc
@@ -24,14 +24,10 @@
     const v8::FunctionCallbackInfo<v8::Value>& args) {
   std::vector<std::string> apis;
   const FeatureProvider* feature_provider = FeatureProvider::GetAPIFeatures();
-  const std::vector<std::string>& feature_names =
-      feature_provider->GetAllFeatureNames();
-  for (std::vector<std::string>::const_iterator i = feature_names.begin();
-       i != feature_names.end();
-       ++i) {
-    if (!feature_provider->GetParent(feature_provider->GetFeature(*i)) &&
-        context()->GetAvailability(*i).is_available()) {
-      apis.push_back(*i);
+  for (const auto& map_entry : feature_provider->GetAllFeatures()) {
+    if (!feature_provider->GetParent(map_entry.second.get()) &&
+        context()->GetAvailability(map_entry.first).is_available()) {
+      apis.push_back(map_entry.first);
     }
   }
   args.GetReturnValue().Set(
diff --git a/extensions/renderer/api_test_base.cc b/extensions/renderer/api_test_base.cc
index 79f95e27..abf868b 100644
--- a/extensions/renderer/api_test_base.cc
+++ b/extensions/renderer/api_test_base.cc
@@ -214,7 +214,7 @@
 }
 
 void ApiTestEnvironment::RunPromisesAgain() {
-  v8::MicrotasksScope::PerformCheckpoint(env()->isolate());
+  env()->isolate()->RunMicrotasks();
   base::MessageLoop::current()->PostTask(
       FROM_HERE, base::Bind(&ApiTestEnvironment::RunPromisesAgain,
                             base::Unretained(this)));
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc
index c3718d9..5ff2616e 100644
--- a/extensions/renderer/dispatcher.cc
+++ b/extensions/renderer/dispatcher.cc
@@ -1345,31 +1345,26 @@
       // ones.
       const FeatureProvider* api_feature_provider =
           FeatureProvider::GetAPIFeatures();
-      const std::vector<std::string>& apis =
-          api_feature_provider->GetAllFeatureNames();
-      for (const std::string& api_name : apis) {
-        Feature* feature = api_feature_provider->GetFeature(api_name);
-        DCHECK(feature);
-
+      for (const auto& map_entry : api_feature_provider->GetAllFeatures()) {
         // Internal APIs are included via require(api_name) from internal code
         // rather than chrome[api_name].
-        if (feature->IsInternal())
+        if (map_entry.second->IsInternal())
           continue;
 
         // If this API has a parent feature (and isn't marked 'noparent'),
         // then this must be a function or event, so we should not register.
-        if (api_feature_provider->GetParent(feature) != NULL)
+        if (api_feature_provider->GetParent(map_entry.second.get()) != nullptr)
           continue;
 
         // Skip chrome.test if this isn't a test.
-        if (api_name == "test" &&
+        if (map_entry.first == "test" &&
             !base::CommandLine::ForCurrentProcess()->HasSwitch(
                 ::switches::kTestType)) {
           continue;
         }
 
-        if (context->IsAnyFeatureAvailableToContext(*feature))
-          RegisterBinding(api_name, context);
+        if (context->IsAnyFeatureAvailableToContext(*map_entry.second.get()))
+          RegisterBinding(map_entry.first, context);
       }
       break;
     }
diff --git a/extensions/renderer/module_system_test.cc b/extensions/renderer/module_system_test.cc
index 06a4d55..68c4bd1 100644
--- a/extensions/renderer/module_system_test.cc
+++ b/extensions/renderer/module_system_test.cc
@@ -253,7 +253,7 @@
 }
 
 void ModuleSystemTest::RunResolvedPromises() {
-  v8::MicrotasksScope::PerformCheckpoint(isolate_);
+  isolate_->RunMicrotasks();
 }
 
 }  // namespace extensions
diff --git a/extensions/renderer/safe_builtins.cc b/extensions/renderer/safe_builtins.cc
index 3a66eaf1..3bfa01a 100644
--- a/extensions/renderer/safe_builtins.cc
+++ b/extensions/renderer/safe_builtins.cc
@@ -9,7 +9,6 @@
 #include "base/strings/stringprintf.h"
 #include "extensions/renderer/script_context.h"
 #include "extensions/renderer/v8_helpers.h"
-#include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h"
 
 namespace extensions {
 
@@ -201,7 +200,6 @@
         return;
     }
 
-    blink::WebScopedMicrotaskSuppression microtasks_scope;
     v8::Local<v8::Value> return_value;
     if (function->Call(context, recv, argc, argv.get()).ToLocal(&return_value))
       info.GetReturnValue().Set(return_value);
diff --git a/gin/run_microtasks_observer.cc b/gin/run_microtasks_observer.cc
index 0ca0078..f453a66 100644
--- a/gin/run_microtasks_observer.cc
+++ b/gin/run_microtasks_observer.cc
@@ -15,7 +15,7 @@
 
 void RunMicrotasksObserver::DidProcessTask(const base::PendingTask& task) {
   v8::Isolate::Scope scope(isolate_);
-  v8::MicrotasksScope::PerformCheckpoint(isolate_);
+  isolate_->RunMicrotasks();
 }
 
 }  // namespace gin
diff --git a/gin/run_microtasks_observer.h b/gin/run_microtasks_observer.h
index ca160be..7f1431f 100644
--- a/gin/run_microtasks_observer.h
+++ b/gin/run_microtasks_observer.h
@@ -12,7 +12,7 @@
 
 // Runs any pending v8 Microtasks each time a task is completed.
 // TODO(hansmuller); At some point perhaps this can be replaced with
-// the (currently experimental) v8::MicrotasksPolicy::kAuto method.
+// the (currently experimental) Isolate::SetAutorunMicrotasks() method.
 
 class RunMicrotasksObserver : public base::MessageLoop::TaskObserver {
  public:
diff --git a/ipc/attachment_broker_mac_unittest.cc b/ipc/attachment_broker_mac_unittest.cc
index 9736c025..9442324 100644
--- a/ipc/attachment_broker_mac_unittest.cc
+++ b/ipc/attachment_broker_mac_unittest.cc
@@ -9,6 +9,8 @@
 #include <stddef.h>
 #include <sys/mman.h>
 
+#include <tuple>
+
 #include "base/command_line.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_file.h"
@@ -111,7 +113,7 @@
     return base::SharedMemoryHandle();
   }
 
-  return base::get<1>(p);
+  return std::get<1>(p);
 }
 
 // |message| must be deserializable as a TestSharedMemoryHandleMsg2. Returns
@@ -132,8 +134,8 @@
     return false;
   }
 
-  *handle1 = base::get<0>(p);
-  *handle2 = base::get<1>(p);
+  *handle1 = std::get<0>(p);
+  *handle2 = std::get<1>(p);
   return true;
 }
 
@@ -868,16 +870,16 @@
     return;
   }
 
-  base::SharedMemoryHandle handle1 = base::get<1>(p);
-  base::SharedMemoryHandle handle2 = base::get<3>(p);
+  base::SharedMemoryHandle handle1 = std::get<1>(p);
+  base::SharedMemoryHandle handle2 = std::get<3>(p);
   bool success1 = CheckContentsOfSharedMemoryHandle(handle1, kDataBuffer1) &&
                   CheckContentsOfSharedMemoryHandle(handle2, kDataBuffer2);
   if (!success1)
     LOG(ERROR) << "SharedMemoryHandles have wrong contents.";
 
   bool success2 =
-      CheckContentsOfFileDescriptor(base::get<0>(p), kDataBuffer3) &&
-      CheckContentsOfFileDescriptor(base::get<2>(p), kDataBuffer4);
+      CheckContentsOfFileDescriptor(std::get<0>(p), kDataBuffer3) &&
+      CheckContentsOfFileDescriptor(std::get<2>(p), kDataBuffer4);
   if (!success2)
     LOG(ERROR) << "FileDescriptors have wrong contents.";
 
diff --git a/ipc/attachment_broker_privileged_mac.cc b/ipc/attachment_broker_privileged_mac.cc
index c5bed27c..725085b 100644
--- a/ipc/attachment_broker_privileged_mac.cc
+++ b/ipc/attachment_broker_privileged_mac.cc
@@ -6,6 +6,8 @@
 
 #include <stdint.h>
 
+#include <tuple>
+
 #include "base/mac/scoped_mach_port.h"
 #include "base/memory/shared_memory.h"
 #include "base/process/port_provider_mac.h"
@@ -183,7 +185,7 @@
     return;
   }
   IPC::internal::MachPortAttachmentMac::WireFormat wire_format =
-      base::get<0>(param);
+      std::get<0>(param);
 
   if (wire_format.destination_process == base::kNullProcessId) {
     LogError(NO_DESTINATION);
diff --git a/ipc/attachment_broker_privileged_win.cc b/ipc/attachment_broker_privileged_win.cc
index c749a09..3ce3ec5 100644
--- a/ipc/attachment_broker_privileged_win.cc
+++ b/ipc/attachment_broker_privileged_win.cc
@@ -6,6 +6,8 @@
 
 #include <windows.h>
 
+#include <tuple>
+
 #include "base/process/process.h"
 #include "ipc/attachment_broker_messages.h"
 #include "ipc/brokerable_attachment.h"
@@ -59,7 +61,7 @@
   if (!AttachmentBrokerMsg_DuplicateWinHandle::Read(&message, &param))
     return;
   IPC::internal::HandleAttachmentWin::WireFormat wire_format =
-      base::get<0>(param);
+      std::get<0>(param);
 
   if (wire_format.destination_process == base::kNullProcessId) {
     LogError(NO_DESTINATION);
diff --git a/ipc/attachment_broker_privileged_win_unittest.cc b/ipc/attachment_broker_privileged_win_unittest.cc
index 870e262..9f720c8 100644
--- a/ipc/attachment_broker_privileged_win_unittest.cc
+++ b/ipc/attachment_broker_privileged_win_unittest.cc
@@ -6,6 +6,8 @@
 
 #include <windows.h>
 
+#include <tuple>
+
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
@@ -76,7 +78,7 @@
     return ScopedHandle(nullptr);
   }
 
-  IPC::HandleWin handle_win = base::get<1>(p);
+  IPC::HandleWin handle_win = std::get<1>(p);
   return ScopedHandle(handle_win.get_handle());
 }
 
@@ -97,7 +99,7 @@
     return nullptr;
   }
 
-  base::SharedMemoryHandle handle = base::get<0>(p);
+  base::SharedMemoryHandle handle = std::get<0>(p);
   scoped_ptr<base::SharedMemory> shared_memory(
       new base::SharedMemory(handle, false));
 
@@ -123,9 +125,9 @@
     return false;
   }
 
-  IPC::HandleWin handle_win = base::get<0>(p);
+  IPC::HandleWin handle_win = std::get<0>(p);
   *h1 = handle_win.get_handle();
-  handle_win = base::get<1>(p);
+  handle_win = std::get<1>(p);
   *h2 = handle_win.get_handle();
   return true;
 }
diff --git a/ipc/ipc_message_macros.h b/ipc/ipc_message_macros.h
index 6126b59..ea28d0c 100644
--- a/ipc/ipc_message_macros.h
+++ b/ipc/ipc_message_macros.h
@@ -201,8 +201,9 @@
 
 #include <stdint.h>
 
+#include <tuple>
+
 #include "base/profiler/scoped_profile.h"
-#include "base/tuple.h"
 #include "ipc/export_template.h"
 #include "ipc/ipc_message_templates.h"
 #include "ipc/ipc_message_utils.h"
@@ -248,7 +249,7 @@
 #define IPC_SYNC_MESSAGE_ROUTED(msg_class, in, out) \
   IPC_MESSAGE_DECL(msg_class, ROUTED, IPC_TUPLE in, IPC_TUPLE out)
 
-#define IPC_TUPLE(...) base::Tuple<__VA_ARGS__>
+#define IPC_TUPLE(...) std::tuple<__VA_ARGS__>
 
 #define IPC_MESSAGE_DECL(msg_name, kind, in_tuple, out_tuple)       \
   struct IPC_MESSAGE_EXPORT msg_name##_Meta {                       \
diff --git a/ipc/ipc_message_templates.h b/ipc/ipc_message_templates.h
index 17dfc1b..ac627dd5 100644
--- a/ipc/ipc_message_templates.h
+++ b/ipc/ipc_message_templates.h
@@ -7,6 +7,7 @@
 
 #include <stdint.h>
 
+#include <tuple>
 #include <type_traits>
 
 #include "base/logging.h"
@@ -35,7 +36,7 @@
                           const Tuple& tuple,
                           base::IndexSequence<Ns...>) {
   // TODO(mdempsky): Apply UnwrapTraits like base::DispatchToMethod?
-  (obj->*method)(parameter, base::get<Ns>(tuple)...);
+  (obj->*method)(parameter, std::get<Ns>(tuple)...);
 }
 
 // The following function is for async IPCs which have a dispatcher with an
@@ -45,7 +46,7 @@
 DispatchToMethod(ObjT* obj,
                  void (ObjT::*method)(P*, Args...),
                  P* parameter,
-                 const base::Tuple<Ts...>& tuple) {
+                 const std::tuple<Ts...>& tuple) {
   DispatchToMethodImpl(obj, method, parameter, tuple,
                        base::MakeIndexSequence<sizeof...(Ts)>());
 }
@@ -84,9 +85,9 @@
 
 // Asynchronous message partial specialization.
 template <typename Meta, typename... Ins>
-class MessageT<Meta, base::Tuple<Ins...>, void> : public Message {
+class MessageT<Meta, std::tuple<Ins...>, void> : public Message {
  public:
-  using Param = base::Tuple<Ins...>;
+  using Param = std::tuple<Ins...>;
   enum { ID = Meta::ID };
 
   // TODO(mdempsky): Remove.  Uses of MyMessage::Schema::Param can be replaced
@@ -127,11 +128,11 @@
 
 // Synchronous message partial specialization.
 template <typename Meta, typename... Ins, typename... Outs>
-class MessageT<Meta, base::Tuple<Ins...>, base::Tuple<Outs...>>
+class MessageT<Meta, std::tuple<Ins...>, std::tuple<Outs...>>
     : public SyncMessage {
  public:
-  using SendParam = base::Tuple<Ins...>;
-  using ReplyParam = base::Tuple<Outs...>;
+  using SendParam = std::tuple<Ins...>;
+  using ReplyParam = std::tuple<Outs...>;
   enum { ID = Meta::ID };
 
   // TODO(mdempsky): Remove.  Uses of MyMessage::Schema::{Send,Reply}Param can
@@ -186,7 +187,7 @@
     bool ok = ReadSendParam(msg, &send_params);
     Message* reply = SyncMessage::GenerateReply(msg);
     if (ok) {
-      base::Tuple<Message&> t = base::MakeRefTuple(*reply);
+      std::tuple<Message&> t = std::tie(*reply);
       ConnectMessageAndReply(msg, reply);
       base::DispatchToMethod(obj, func, send_params, &t);
     } else {
diff --git a/ipc/ipc_message_templates_impl.h b/ipc/ipc_message_templates_impl.h
index bfcdad0..192d2efb 100644
--- a/ipc/ipc_message_templates_impl.h
+++ b/ipc/ipc_message_templates_impl.h
@@ -5,37 +5,39 @@
 #ifndef IPC_IPC_MESSAGE_TEMPLATES_IMPL_H_
 #define IPC_IPC_MESSAGE_TEMPLATES_IMPL_H_
 
+#include <tuple>
+
 namespace IPC {
 
 template <typename... Ts>
 class ParamDeserializer : public MessageReplyDeserializer {
  public:
-  explicit ParamDeserializer(const base::Tuple<Ts&...>& out) : out_(out) {}
+  explicit ParamDeserializer(const std::tuple<Ts&...>& out) : out_(out) {}
 
   bool SerializeOutputParameters(const IPC::Message& msg,
                                  base::PickleIterator iter) override {
     return ReadParam(&msg, &iter, &out_);
   }
 
-  base::Tuple<Ts&...> out_;
+  std::tuple<Ts&...> out_;
 };
 
 template <typename Meta, typename... Ins>
-MessageT<Meta, base::Tuple<Ins...>, void>::MessageT(Routing routing,
+MessageT<Meta, std::tuple<Ins...>, void>::MessageT(Routing routing,
                                                     const Ins&... ins)
     : Message(routing.id, ID, PRIORITY_NORMAL) {
-  WriteParam(this, base::MakeRefTuple(ins...));
+  WriteParam(this, std::tie(ins...));
 }
 
 template <typename Meta, typename... Ins>
-bool MessageT<Meta, base::Tuple<Ins...>, void>::Read(const Message* msg,
+bool MessageT<Meta, std::tuple<Ins...>, void>::Read(const Message* msg,
                                                      Param* p) {
   base::PickleIterator iter(*msg);
   return ReadParam(msg, &iter, p);
 }
 
 template <typename Meta, typename... Ins>
-void MessageT<Meta, base::Tuple<Ins...>, void>::Log(std::string* name,
+void MessageT<Meta, std::tuple<Ins...>, void>::Log(std::string* name,
                                                     const Message* msg,
                                                     std::string* l) {
   if (name)
@@ -48,7 +50,7 @@
 }
 
 template <typename Meta, typename... Ins, typename... Outs>
-MessageT<Meta, base::Tuple<Ins...>, base::Tuple<Outs...>>::MessageT(
+MessageT<Meta, std::tuple<Ins...>, std::tuple<Outs...>>::MessageT(
     Routing routing,
     const Ins&... ins,
     Outs*... outs)
@@ -56,12 +58,12 @@
           routing.id,
           ID,
           PRIORITY_NORMAL,
-          new ParamDeserializer<Outs...>(base::MakeRefTuple(*outs...))) {
-  WriteParam(this, base::MakeRefTuple(ins...));
+          new ParamDeserializer<Outs...>(std::tie(*outs...))) {
+  WriteParam(this, std::tie(ins...));
 }
 
 template <typename Meta, typename... Ins, typename... Outs>
-bool MessageT<Meta, base::Tuple<Ins...>, base::Tuple<Outs...>>::ReadSendParam(
+bool MessageT<Meta, std::tuple<Ins...>, std::tuple<Outs...>>::ReadSendParam(
     const Message* msg,
     SendParam* p) {
   base::PickleIterator iter = SyncMessage::GetDataIterator(msg);
@@ -69,7 +71,7 @@
 }
 
 template <typename Meta, typename... Ins, typename... Outs>
-bool MessageT<Meta, base::Tuple<Ins...>, base::Tuple<Outs...>>::ReadReplyParam(
+bool MessageT<Meta, std::tuple<Ins...>, std::tuple<Outs...>>::ReadReplyParam(
     const Message* msg,
     ReplyParam* p) {
   base::PickleIterator iter = SyncMessage::GetDataIterator(msg);
@@ -78,14 +80,14 @@
 
 template <typename Meta, typename... Ins, typename... Outs>
 void MessageT<Meta,
-              base::Tuple<Ins...>,
-              base::Tuple<Outs...>>::WriteReplyParams(Message* reply,
+              std::tuple<Ins...>,
+              std::tuple<Outs...>>::WriteReplyParams(Message* reply,
                                                       const Outs&... outs) {
-  WriteParam(reply, base::MakeRefTuple(outs...));
+  WriteParam(reply, std::tie(outs...));
 }
 
 template <typename Meta, typename... Ins, typename... Outs>
-void MessageT<Meta, base::Tuple<Ins...>, base::Tuple<Outs...>>::Log(
+void MessageT<Meta, std::tuple<Ins...>, std::tuple<Outs...>>::Log(
     std::string* name,
     const Message* msg,
     std::string* l) {
diff --git a/ipc/ipc_message_utils.h b/ipc/ipc_message_utils.h
index 971370a2..d92d833 100644
--- a/ipc/ipc_message_utils.h
+++ b/ipc/ipc_message_utils.h
@@ -13,6 +13,7 @@
 #include <map>
 #include <set>
 #include <string>
+#include <tuple>
 #include <vector>
 
 #include "base/containers/small_map.h"
@@ -24,7 +25,6 @@
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
-#include "base/tuple.h"
 #include "build/build_config.h"
 #include "ipc/brokerable_attachment.h"
 #include "ipc/ipc_message_start.h"
@@ -666,18 +666,18 @@
 struct ParamTraits<std::tuple<A>> {
   typedef std::tuple<A> param_type;
   static void GetSize(base::PickleSizer* sizer, const param_type& p) {
-    GetParamSize(sizer, base::get<0>(p));
+    GetParamSize(sizer, std::get<0>(p));
   }
   static void Write(base::Pickle* m, const param_type& p) {
-    WriteParam(m, base::get<0>(p));
+    WriteParam(m, std::get<0>(p));
   }
   static bool Read(const base::Pickle* m,
                    base::PickleIterator* iter,
                    param_type* r) {
-    return ReadParam(m, iter, &base::get<0>(*r));
+    return ReadParam(m, iter, &std::get<0>(*r));
   }
   static void Log(const param_type& p, std::string* l) {
-    LogParam(base::get<0>(p), l);
+    LogParam(std::get<0>(p), l);
   }
 };
 
@@ -685,23 +685,23 @@
 struct ParamTraits<std::tuple<A, B>> {
   typedef std::tuple<A, B> param_type;
   static void GetSize(base::PickleSizer* sizer, const param_type& p) {
-    GetParamSize(sizer, base::get<0>(p));
-    GetParamSize(sizer, base::get<1>(p));
+    GetParamSize(sizer, std::get<0>(p));
+    GetParamSize(sizer, std::get<1>(p));
   }
   static void Write(base::Pickle* m, const param_type& p) {
-    WriteParam(m, base::get<0>(p));
-    WriteParam(m, base::get<1>(p));
+    WriteParam(m, std::get<0>(p));
+    WriteParam(m, std::get<1>(p));
   }
   static bool Read(const base::Pickle* m,
                    base::PickleIterator* iter,
                    param_type* r) {
-    return (ReadParam(m, iter, &base::get<0>(*r)) &&
-            ReadParam(m, iter, &base::get<1>(*r)));
+    return (ReadParam(m, iter, &std::get<0>(*r)) &&
+            ReadParam(m, iter, &std::get<1>(*r)));
   }
   static void Log(const param_type& p, std::string* l) {
-    LogParam(base::get<0>(p), l);
+    LogParam(std::get<0>(p), l);
     l->append(", ");
-    LogParam(base::get<1>(p), l);
+    LogParam(std::get<1>(p), l);
   }
 };
 
@@ -709,28 +709,28 @@
 struct ParamTraits<std::tuple<A, B, C>> {
   typedef std::tuple<A, B, C> param_type;
   static void GetSize(base::PickleSizer* sizer, const param_type& p) {
-    GetParamSize(sizer, base::get<0>(p));
-    GetParamSize(sizer, base::get<1>(p));
-    GetParamSize(sizer, base::get<2>(p));
+    GetParamSize(sizer, std::get<0>(p));
+    GetParamSize(sizer, std::get<1>(p));
+    GetParamSize(sizer, std::get<2>(p));
   }
   static void Write(base::Pickle* m, const param_type& p) {
-    WriteParam(m, base::get<0>(p));
-    WriteParam(m, base::get<1>(p));
-    WriteParam(m, base::get<2>(p));
+    WriteParam(m, std::get<0>(p));
+    WriteParam(m, std::get<1>(p));
+    WriteParam(m, std::get<2>(p));
   }
   static bool Read(const base::Pickle* m,
                    base::PickleIterator* iter,
                    param_type* r) {
-    return (ReadParam(m, iter, &base::get<0>(*r)) &&
-            ReadParam(m, iter, &base::get<1>(*r)) &&
-            ReadParam(m, iter, &base::get<2>(*r)));
+    return (ReadParam(m, iter, &std::get<0>(*r)) &&
+            ReadParam(m, iter, &std::get<1>(*r)) &&
+            ReadParam(m, iter, &std::get<2>(*r)));
   }
   static void Log(const param_type& p, std::string* l) {
-    LogParam(base::get<0>(p), l);
+    LogParam(std::get<0>(p), l);
     l->append(", ");
-    LogParam(base::get<1>(p), l);
+    LogParam(std::get<1>(p), l);
     l->append(", ");
-    LogParam(base::get<2>(p), l);
+    LogParam(std::get<2>(p), l);
   }
 };
 
@@ -738,33 +738,33 @@
 struct ParamTraits<std::tuple<A, B, C, D>> {
   typedef std::tuple<A, B, C, D> param_type;
   static void GetSize(base::PickleSizer* sizer, const param_type& p) {
-    GetParamSize(sizer, base::get<0>(p));
-    GetParamSize(sizer, base::get<1>(p));
-    GetParamSize(sizer, base::get<2>(p));
-    GetParamSize(sizer, base::get<3>(p));
+    GetParamSize(sizer, std::get<0>(p));
+    GetParamSize(sizer, std::get<1>(p));
+    GetParamSize(sizer, std::get<2>(p));
+    GetParamSize(sizer, std::get<3>(p));
   }
   static void Write(base::Pickle* m, const param_type& p) {
-    WriteParam(m, base::get<0>(p));
-    WriteParam(m, base::get<1>(p));
-    WriteParam(m, base::get<2>(p));
-    WriteParam(m, base::get<3>(p));
+    WriteParam(m, std::get<0>(p));
+    WriteParam(m, std::get<1>(p));
+    WriteParam(m, std::get<2>(p));
+    WriteParam(m, std::get<3>(p));
   }
   static bool Read(const base::Pickle* m,
                    base::PickleIterator* iter,
                    param_type* r) {
-    return (ReadParam(m, iter, &base::get<0>(*r)) &&
-            ReadParam(m, iter, &base::get<1>(*r)) &&
-            ReadParam(m, iter, &base::get<2>(*r)) &&
-            ReadParam(m, iter, &base::get<3>(*r)));
+    return (ReadParam(m, iter, &std::get<0>(*r)) &&
+            ReadParam(m, iter, &std::get<1>(*r)) &&
+            ReadParam(m, iter, &std::get<2>(*r)) &&
+            ReadParam(m, iter, &std::get<3>(*r)));
   }
   static void Log(const param_type& p, std::string* l) {
-    LogParam(base::get<0>(p), l);
+    LogParam(std::get<0>(p), l);
     l->append(", ");
-    LogParam(base::get<1>(p), l);
+    LogParam(std::get<1>(p), l);
     l->append(", ");
-    LogParam(base::get<2>(p), l);
+    LogParam(std::get<2>(p), l);
     l->append(", ");
-    LogParam(base::get<3>(p), l);
+    LogParam(std::get<3>(p), l);
   }
 };
 
@@ -772,38 +772,38 @@
 struct ParamTraits<std::tuple<A, B, C, D, E>> {
   typedef std::tuple<A, B, C, D, E> param_type;
   static void GetSize(base::PickleSizer* sizer, const param_type& p) {
-    GetParamSize(sizer, base::get<0>(p));
-    GetParamSize(sizer, base::get<1>(p));
-    GetParamSize(sizer, base::get<2>(p));
-    GetParamSize(sizer, base::get<3>(p));
-    GetParamSize(sizer, base::get<4>(p));
+    GetParamSize(sizer, std::get<0>(p));
+    GetParamSize(sizer, std::get<1>(p));
+    GetParamSize(sizer, std::get<2>(p));
+    GetParamSize(sizer, std::get<3>(p));
+    GetParamSize(sizer, std::get<4>(p));
   }
   static void Write(base::Pickle* m, const param_type& p) {
-    WriteParam(m, base::get<0>(p));
-    WriteParam(m, base::get<1>(p));
-    WriteParam(m, base::get<2>(p));
-    WriteParam(m, base::get<3>(p));
-    WriteParam(m, base::get<4>(p));
+    WriteParam(m, std::get<0>(p));
+    WriteParam(m, std::get<1>(p));
+    WriteParam(m, std::get<2>(p));
+    WriteParam(m, std::get<3>(p));
+    WriteParam(m, std::get<4>(p));
   }
   static bool Read(const base::Pickle* m,
                    base::PickleIterator* iter,
                    param_type* r) {
-    return (ReadParam(m, iter, &base::get<0>(*r)) &&
-            ReadParam(m, iter, &base::get<1>(*r)) &&
-            ReadParam(m, iter, &base::get<2>(*r)) &&
-            ReadParam(m, iter, &base::get<3>(*r)) &&
-            ReadParam(m, iter, &base::get<4>(*r)));
+    return (ReadParam(m, iter, &std::get<0>(*r)) &&
+            ReadParam(m, iter, &std::get<1>(*r)) &&
+            ReadParam(m, iter, &std::get<2>(*r)) &&
+            ReadParam(m, iter, &std::get<3>(*r)) &&
+            ReadParam(m, iter, &std::get<4>(*r)));
   }
   static void Log(const param_type& p, std::string* l) {
-    LogParam(base::get<0>(p), l);
+    LogParam(std::get<0>(p), l);
     l->append(", ");
-    LogParam(base::get<1>(p), l);
+    LogParam(std::get<1>(p), l);
     l->append(", ");
-    LogParam(base::get<2>(p), l);
+    LogParam(std::get<2>(p), l);
     l->append(", ");
-    LogParam(base::get<3>(p), l);
+    LogParam(std::get<3>(p), l);
     l->append(", ");
-    LogParam(base::get<4>(p), l);
+    LogParam(std::get<4>(p), l);
   }
 };
 
diff --git a/mash/browser_driver/browser_driver_application_delegate.cc b/mash/browser_driver/browser_driver_application_delegate.cc
index 1e14d16..64ee8e4 100644
--- a/mash/browser_driver/browser_driver_application_delegate.cc
+++ b/mash/browser_driver/browser_driver_application_delegate.cc
@@ -50,10 +50,10 @@
 
 BrowserDriverApplicationDelegate::~BrowserDriverApplicationDelegate() {}
 
-void BrowserDriverApplicationDelegate::Initialize(mojo::Connector* connector,
-                                                  const std::string& url,
-                                                  const std::string& user_id,
-                                                  uint32_t id) {
+void BrowserDriverApplicationDelegate::Initialize(
+    mojo::Connector* connector,
+    const mojo::Identity& identity,
+    uint32_t id) {
   connector_ = connector;
   AddAccelerators();
 }
diff --git a/mash/browser_driver/browser_driver_application_delegate.h b/mash/browser_driver/browser_driver_application_delegate.h
index 03d67d38..2d722f4 100644
--- a/mash/browser_driver/browser_driver_application_delegate.h
+++ b/mash/browser_driver/browser_driver_application_delegate.h
@@ -27,8 +27,8 @@
 
  private:
   // mojo::ShellClient:
-  void Initialize(mojo::Connector* connector, const std::string& url,
-                  const std::string& user_id, uint32_t id) override;
+  void Initialize(mojo::Connector* connector, const mojo::Identity& identity,
+                  uint32_t id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
   // mus::mojom::AcceleratorHandler:
diff --git a/mash/example/views_examples/views_examples_application_delegate.cc b/mash/example/views_examples/views_examples_application_delegate.cc
index b3b87e9..8bc5678d 100644
--- a/mash/example/views_examples/views_examples_application_delegate.cc
+++ b/mash/example/views_examples/views_examples_application_delegate.cc
@@ -16,11 +16,11 @@
 ViewsExamplesApplicationDelegate::~ViewsExamplesApplicationDelegate() {
 }
 
-void ViewsExamplesApplicationDelegate::Initialize(mojo::Connector* connector,
-                                                  const std::string& url,
-                                                  const std::string& user_id,
-                                                  uint32_t id) {
-  tracing_.Initialize(connector, url);
+void ViewsExamplesApplicationDelegate::Initialize(
+    mojo::Connector* connector,
+    const mojo::Identity& identity,
+    uint32_t id) {
+  tracing_.Initialize(connector, identity.name());
   aura_init_.reset(new views::AuraInit(connector, "views_mus_resources.pak"));
 
   views::WindowManagerConnection::Create(connector);
diff --git a/mash/example/views_examples/views_examples_application_delegate.h b/mash/example/views_examples/views_examples_application_delegate.h
index cb1ab50c..3b4fb112 100644
--- a/mash/example/views_examples/views_examples_application_delegate.h
+++ b/mash/example/views_examples/views_examples_application_delegate.h
@@ -21,8 +21,8 @@
 
  private:
   // mojo::ShellClient:
-  void Initialize(mojo::Connector* connector, const std::string& url,
-                  const std::string& user_id, uint32_t id) override;
+  void Initialize(mojo::Connector* connector, const mojo::Identity& identity,
+                  uint32_t id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
   mojo::TracingImpl tracing_;
diff --git a/mash/example/window_type_launcher/window_type_launcher.cc b/mash/example/window_type_launcher/window_type_launcher.cc
index 141bb3f..106dfc10 100644
--- a/mash/example/window_type_launcher/window_type_launcher.cc
+++ b/mash/example/window_type_launcher/window_type_launcher.cc
@@ -356,8 +356,7 @@
 WindowTypeLauncher::~WindowTypeLauncher() {}
 
 void WindowTypeLauncher::Initialize(mojo::Connector* connector,
-                                    const std::string& url,
-                                    const std::string& user_id,
+                                    const mojo::Identity& identity,
                                     uint32_t id) {
   aura_init_.reset(new views::AuraInit(connector, "views_mus_resources.pak"));
 
diff --git a/mash/example/window_type_launcher/window_type_launcher.h b/mash/example/window_type_launcher/window_type_launcher.h
index c5bad8a..dbbf40f 100644
--- a/mash/example/window_type_launcher/window_type_launcher.h
+++ b/mash/example/window_type_launcher/window_type_launcher.h
@@ -20,8 +20,8 @@
 
  private:
   // mojo::ShellClient:
-  void Initialize(mojo::Connector* connector, const std::string& url,
-                  const std::string& user_id, uint32_t id) override;
+  void Initialize(mojo::Connector* connector, const mojo::Identity& identity,
+                  uint32_t id) override;
 
   scoped_ptr<views::AuraInit> aura_init_;
 
diff --git a/mash/init/init.cc b/mash/init/init.cc
index c7197dd..98aea78 100644
--- a/mash/init/init.cc
+++ b/mash/init/init.cc
@@ -15,8 +15,9 @@
 Init::Init() : connector_(nullptr) {}
 Init::~Init() {}
 
-void Init::Initialize(mojo::Connector* connector, const std::string& url,
-                      const std::string& user_id, uint32_t id) {
+void Init::Initialize(mojo::Connector* connector,
+                      const mojo::Identity& identity,
+                      uint32_t id) {
   connector_ = connector;
   mus_connection_ = connector_->Connect("mojo:mus");
   StartWindowManager();
@@ -26,8 +27,8 @@
 void Init::LoginAs(const mojo::String& user_id) {
   connections_["mojo:mash_login"].reset();
   connections_["mojo:desktop_wm"].reset();
-  mojo::Connector::ConnectParams params("mojo:mash_shell");
-  params.set_user_id(user_id);
+  mojo::Connector::ConnectParams params(
+      mojo::Identity("mojo:mash_shell", user_id));
   connector_->Connect(&params);
 }
 
@@ -36,16 +37,14 @@
 }
 
 void Init::StartWindowManager() {
-  mojo::Connector::ConnectParams params("mojo:desktop_wm");
-  params.set_user_id("2");
+  mojo::Connector::ConnectParams params(mojo::Identity("mojo:desktop_wm", "2"));
   StartRestartableService(
       &params,
       base::Bind(&Init::StartWindowManager, base::Unretained(this)));
 }
 
 void Init::StartLogin() {
-  mojo::Connector::ConnectParams params("mojo:mash_login");
-  params.set_user_id("2");
+  mojo::Connector::ConnectParams params(mojo::Identity("mojo:mash_login", "2"));
   StartRestartableService(
       &params,
       base::Bind(&Init::StartLogin, base::Unretained(this)));
@@ -60,7 +59,7 @@
   if (connection) {
     connection->SetConnectionLostClosure(restart_callback);
     connection->AddInterface<mojom::Login>(this);
-    connections_[params->name()] = std::move(connection);
+    connections_[params->target().name()] = std::move(connection);
   }
 }
 
diff --git a/mash/init/init.h b/mash/init/init.h
index 812967a..04812c10 100644
--- a/mash/init/init.h
+++ b/mash/init/init.h
@@ -31,8 +31,8 @@
 
  private:
   // mojo::ShellClient:
-  void Initialize(mojo::Connector* connector, const std::string& url,
-                  const std::string& user_id, uint32_t id) override;
+  void Initialize(mojo::Connector* connector, const mojo::Identity& identity,
+                  uint32_t id) override;
 
   // mojom::Login:
   void LoginAs(const mojo::String& user_id) override;
diff --git a/mash/login/login.cc b/mash/login/login.cc
index 2e26b4a..49bfd34 100644
--- a/mash/login/login.cc
+++ b/mash/login/login.cc
@@ -93,9 +93,10 @@
 Login::Login() {}
 Login::~Login() {}
 
-void Login::Initialize(mojo::Connector* connector, const std::string& url,
-                       const std::string& user_id, uint32_t id) {
-  tracing_.Initialize(connector, url);
+void Login::Initialize(mojo::Connector* connector,
+                       const mojo::Identity& identity,
+                       uint32_t id) {
+  tracing_.Initialize(connector, identity.name());
 
   aura_init_.reset(new views::AuraInit(connector, "views_mus_resources.pak"));
   views::WindowManagerConnection::Create(connector);
@@ -118,7 +119,7 @@
 }
 
 bool Login::AcceptConnection(mojo::Connection* connection) {
-  if (connection->GetRemoteApplicationName() == "mojo:mash_init") {
+  if (connection->GetRemoteIdentity().name() == "mojo:mash_init") {
     connection->GetInterface(&login_);
     return true;
   }
diff --git a/mash/login/login.h b/mash/login/login.h
index 53fcbf6..88216b3 100644
--- a/mash/login/login.h
+++ b/mash/login/login.h
@@ -29,8 +29,8 @@
 
  private:
   // mojo::ShellClient:
-  void Initialize(mojo::Connector* connector, const std::string& url,
-                  const std::string& user_id, uint32_t id) override;
+  void Initialize(mojo::Connector* connector, const mojo::Identity& identity,
+                  uint32_t id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
   mojo::TracingImpl tracing_;
diff --git a/mash/quick_launch/quick_launch_application.cc b/mash/quick_launch/quick_launch_application.cc
index d00baf3..c4887a49 100644
--- a/mash/quick_launch/quick_launch_application.cc
+++ b/mash/quick_launch/quick_launch_application.cc
@@ -89,10 +89,9 @@
 QuickLaunchApplication::~QuickLaunchApplication() {}
 
 void QuickLaunchApplication::Initialize(mojo::Connector* connector,
-                                        const std::string& url,
-                                        const std::string& user_id,
+                                        const mojo::Identity& identity,
                                         uint32_t id) {
-  tracing_.Initialize(connector, url);
+  tracing_.Initialize(connector, identity.name());
 
   aura_init_.reset(new views::AuraInit(connector, "views_mus_resources.pak"));
   views::WindowManagerConnection::Create(connector);
diff --git a/mash/quick_launch/quick_launch_application.h b/mash/quick_launch/quick_launch_application.h
index 8fbd6508..130a1dd 100644
--- a/mash/quick_launch/quick_launch_application.h
+++ b/mash/quick_launch/quick_launch_application.h
@@ -25,8 +25,7 @@
  private:
   // mojo::ShellClient:
   void Initialize(mojo::Connector* connector,
-                  const std::string& url,
-                  const std::string& user_id,
+                  const mojo::Identity& identity,
                   uint32_t id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
diff --git a/mash/screenlock/screenlock.cc b/mash/screenlock/screenlock.cc
index 42f2b04..60f6f1e 100644
--- a/mash/screenlock/screenlock.cc
+++ b/mash/screenlock/screenlock.cc
@@ -75,9 +75,10 @@
 Screenlock::Screenlock() {}
 Screenlock::~Screenlock() {}
 
-void Screenlock::Initialize(mojo::Connector* connector, const std::string& url,
-                            const std::string& user_id, uint32_t id) {
-  tracing_.Initialize(connector, url);
+void Screenlock::Initialize(mojo::Connector* connector,
+                            const mojo::Identity& identity,
+                            uint32_t id) {
+  tracing_.Initialize(connector, identity.name());
 
   mash::shell::mojom::ShellPtr mash_shell;
   connector->ConnectToInterface("mojo:mash_shell", &mash_shell);
diff --git a/mash/screenlock/screenlock.h b/mash/screenlock/screenlock.h
index e6c0611..f1d2755 100644
--- a/mash/screenlock/screenlock.h
+++ b/mash/screenlock/screenlock.h
@@ -29,8 +29,9 @@
 
  private:
   // mojo::ShellClient:
-  void Initialize(mojo::Connector* connector, const std::string& url,
-                  const std::string& user_id, uint32_t id) override;
+  void Initialize(mojo::Connector* connector,
+                  const mojo::Identity& identity,
+                  uint32_t id) override;
 
   // mash::shell::mojom::ScreenlockStateListener:
   void ScreenlockStateChanged(bool locked) override;
diff --git a/mash/shell/shell_application_delegate.cc b/mash/shell/shell_application_delegate.cc
index ff472e79..8c217bc 100644
--- a/mash/shell/shell_application_delegate.cc
+++ b/mash/shell/shell_application_delegate.cc
@@ -18,8 +18,7 @@
 ShellApplicationDelegate::~ShellApplicationDelegate() {}
 
 void ShellApplicationDelegate::Initialize(mojo::Connector* connector,
-                                          const std::string& url,
-                                          const std::string& user_id,
+                                          const mojo::Identity& identity,
                                           uint32_t id) {
   connector_ = connector;
   StartBrowserDriver();
diff --git a/mash/shell/shell_application_delegate.h b/mash/shell/shell_application_delegate.h
index 99b24eda..ba692e87 100644
--- a/mash/shell/shell_application_delegate.h
+++ b/mash/shell/shell_application_delegate.h
@@ -33,8 +33,9 @@
 
  private:
   // mojo::ShellClient:
-  void Initialize(mojo::Connector* connector, const std::string& url,
-                  const std::string& user_id, uint32_t id) override;
+  void Initialize(mojo::Connector* connector,
+                  const mojo::Identity& identity,
+                  uint32_t id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
   // mash::shell::mojom::Shell:
diff --git a/mash/task_viewer/task_viewer.cc b/mash/task_viewer/task_viewer.cc
index e3af3da..4a26c4f 100644
--- a/mash/task_viewer/task_viewer.cc
+++ b/mash/task_viewer/task_viewer.cc
@@ -142,8 +142,9 @@
     DCHECK(instances_.empty());
     mojo::Array<mojo::String> names;
     for (size_t i = 0; i < instances.size(); ++i) {
-      InsertInstance(instances[i]->id, instances[i]->name, instances[i]->pid);
-      names.push_back(instances[i]->name);
+      InsertInstance(instances[i]->id, instances[i]->identity->name,
+                     instances[i]->pid);
+      names.push_back(instances[i]->identity->name);
     }
     catalog_->GetEntries(std::move(names),
                          base::Bind(&TaskViewerContents::OnGotCatalogEntries,
@@ -151,10 +152,10 @@
   }
   void InstanceCreated(InstanceInfoPtr instance) override {
     DCHECK(!ContainsId(instance->id));
-    InsertInstance(instance->id, instance->name, instance->pid);
+    InsertInstance(instance->id, instance->identity->name, instance->pid);
     observer_->OnItemsAdded(static_cast<int>(instances_.size()), 1);
     mojo::Array<mojo::String> names;
-    names.push_back(instance->name);
+    names.push_back(instance->identity->name);
     catalog_->GetEntries(std::move(names),
                          base::Bind(&TaskViewerContents::OnGotCatalogEntries,
                                     weak_ptr_factory_.GetWeakPtr()));
@@ -259,10 +260,9 @@
 TaskViewer::~TaskViewer() {}
 
 void TaskViewer::Initialize(mojo::Connector* connector,
-                            const std::string& url,
-                            const std::string& user_id,
+                            const mojo::Identity& identity,
                             uint32_t id) {
-  tracing_.Initialize(connector, url);
+  tracing_.Initialize(connector, identity.name());
 
   aura_init_.reset(new views::AuraInit(connector, "views_mus_resources.pak"));
   views::WindowManagerConnection::Create(connector);
diff --git a/mash/task_viewer/task_viewer.h b/mash/task_viewer/task_viewer.h
index 0a696cd..e5eeae09 100644
--- a/mash/task_viewer/task_viewer.h
+++ b/mash/task_viewer/task_viewer.h
@@ -27,8 +27,9 @@
 
  private:
   // mojo::ShellClient:
-  void Initialize(mojo::Connector* connector, const std::string& url,
-                  const std::string& user_id, uint32_t id) override;
+  void Initialize(mojo::Connector* connector,
+                  const mojo::Identity& identity,
+                  uint32_t id) override;
 
   mojo::TracingImpl tracing_;
   scoped_ptr<views::AuraInit> aura_init_;
diff --git a/mash/wm/window_manager_application.cc b/mash/wm/window_manager_application.cc
index 6511c94..91fb08e 100644
--- a/mash/wm/window_manager_application.cc
+++ b/mash/wm/window_manager_application.cc
@@ -104,11 +104,10 @@
 }
 
 void WindowManagerApplication::Initialize(mojo::Connector* connector,
-                                          const std::string& url,
-                                          const std::string& user_id,
+                                          const mojo::Identity& identity,
                                           uint32_t id) {
   connector_ = connector;
-  tracing_.Initialize(connector, url);
+  tracing_.Initialize(connector, identity.name());
 
   mus::mojom::WindowManagerFactoryServicePtr wm_factory_service;
   connector_->ConnectToInterface("mojo:mus", &wm_factory_service);
@@ -121,7 +120,7 @@
 bool WindowManagerApplication::AcceptConnection(mojo::Connection* connection) {
   connection->AddInterface<mash::wm::mojom::UserWindowController>(this);
   connection->AddInterface<mus::mojom::AcceleratorRegistrar>(this);
-  if (connection->GetRemoteApplicationName() == "mojo:mash_shell")
+  if (connection->GetRemoteIdentity().name() == "mojo:mash_shell")
     connection->GetInterface(&mash_shell_);
   return true;
 }
diff --git a/mash/wm/window_manager_application.h b/mash/wm/window_manager_application.h
index 0eedaab..bb517dcd 100644
--- a/mash/wm/window_manager_application.h
+++ b/mash/wm/window_manager_application.h
@@ -83,8 +83,8 @@
   void OnAcceleratorRegistrarDestroyed(AcceleratorRegistrarImpl* registrar);
 
   // mojo::ShellClient:
-  void Initialize(mojo::Connector* connector, const std::string& url,
-                  const std::string& user_id, uint32_t id) override;
+  void Initialize(mojo::Connector* connector, const mojo::Identity& identity,
+                  uint32_t id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
   // InterfaceFactory<mash::wm::mojom::UserWindowController>:
diff --git a/media/BUILD.gn b/media/BUILD.gn
index 01d09d1..100df8b 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -417,8 +417,6 @@
       "formats/mp4/box_definitions.h",
       "formats/mp4/box_reader.cc",
       "formats/mp4/box_reader.h",
-      "formats/mp4/cenc.cc",
-      "formats/mp4/cenc.h",
       "formats/mp4/es_descriptor.cc",
       "formats/mp4/es_descriptor.h",
       "formats/mp4/mp4_stream_parser.cc",
diff --git a/media/audio/mac/audio_low_latency_input_mac.cc b/media/audio/mac/audio_low_latency_input_mac.cc
index 1aa4ae4..9e9df76 100644
--- a/media/audio/mac/audio_low_latency_input_mac.cc
+++ b/media/audio/mac/audio_low_latency_input_mac.cc
@@ -32,15 +32,6 @@
 // if input callbacks have started, and false otherwise.
 const int kInputCallbackStartTimeoutInSeconds = 5;
 
-// Replaces AudioManagerMac::kStartDelayInSecsForPowerEvents to allow for a
-// longer delay when calling Start() in conjunction to a power resume event.
-// If it is detected that Start() should be deferred, we wait this amount of
-// time before trying Start() again. The default value in AudioManagerMac is
-// 2 seconds.
-// TODO(henrika): investigate if an increase results in a lower frequency of
-// detecting no input callbacks at startup.
-const int kStartDelayInSecsForPowerEvents = 4;
-
 // Returns true if the format flags in |format_flags| has the "non-interleaved"
 // flag (kAudioFormatFlagIsNonInterleaved) cleared (set to 0).
 static bool FormatIsInterleaved(UInt32 format_flags) {
@@ -485,7 +476,8 @@
         &AUAudioInputStream::Start, base::Unretained(this), callback));
     manager_->GetTaskRunner()->PostDelayedTask(
         FROM_HERE, deferred_start_cb_.callback(),
-        base::TimeDelta::FromSeconds(kStartDelayInSecsForPowerEvents));
+        base::TimeDelta::FromSeconds(
+            AudioManagerMac::kStartDelayInSecsForPowerEvents));
     return;
   }
 
diff --git a/media/audio/mac/audio_manager_mac.h b/media/audio/mac/audio_manager_mac.h
index b82aa60..2112a883 100644
--- a/media/audio/mac/audio_manager_mac.h
+++ b/media/audio/mac/audio_manager_mac.h
@@ -71,7 +71,9 @@
   // Streams should consult ShouldDeferStreamStart() and if true check the value
   // again after |kStartDelayInSecsForPowerEvents| has elapsed. If false, the
   // stream may be started immediately.
-  enum { kStartDelayInSecsForPowerEvents = 2 };
+  // TOOD(henrika): track UMA statistics related to defer start to come up with
+  // a suitable delay value.
+  enum { kStartDelayInSecsForPowerEvents = 5 };
   bool ShouldDeferStreamStart() const;
 
   // True if the device is on battery power.
diff --git a/media/base/bitstream_buffer.cc b/media/base/bitstream_buffer.cc
index 3378170..5a1907db 100644
--- a/media/base/bitstream_buffer.cc
+++ b/media/base/bitstream_buffer.cc
@@ -7,23 +7,17 @@
 namespace media {
 
 BitstreamBuffer::BitstreamBuffer()
-    : id_(-1), size_(0), presentation_timestamp_(kNoTimestamp()) {}
-
-BitstreamBuffer::BitstreamBuffer(int32_t id,
-                                 base::SharedMemoryHandle handle,
-                                 size_t size)
-    : id_(id),
-      handle_(handle),
-      size_(size),
-      presentation_timestamp_(kNoTimestamp()) {}
+    : BitstreamBuffer(-1, base::SharedMemoryHandle(), 0) {}
 
 BitstreamBuffer::BitstreamBuffer(int32_t id,
                                  base::SharedMemoryHandle handle,
                                  size_t size,
+                                 off_t offset,
                                  base::TimeDelta presentation_timestamp)
     : id_(id),
       handle_(handle),
       size_(size),
+      offset_(offset),
       presentation_timestamp_(presentation_timestamp) {}
 
 BitstreamBuffer::BitstreamBuffer(const BitstreamBuffer& other) = default;
diff --git a/media/base/bitstream_buffer.h b/media/base/bitstream_buffer.h
index 42451cc..c8983f2 100644
--- a/media/base/bitstream_buffer.h
+++ b/media/base/bitstream_buffer.h
@@ -24,12 +24,17 @@
  public:
   BitstreamBuffer();
 
-  BitstreamBuffer(int32_t id, base::SharedMemoryHandle handle, size_t size);
-
+  // Constructs a new BitstreamBuffer. The content of the bitstream is located
+  // at |offset| bytes away from the start of the shared memory and the payload
+  // is |size| bytes. When not provided, the default value for |offset| is 0.
+  // |presentation_timestamp| is when the decoded frame should be displayed.
+  // When not provided, |presentation_timestamp| will be
+  // |media::kNoTimestamp()|.
   BitstreamBuffer(int32_t id,
                   base::SharedMemoryHandle handle,
                   size_t size,
-                  base::TimeDelta presentation_timestamp);
+                  off_t offset = 0,
+                  base::TimeDelta presentation_timestamp = kNoTimestamp());
 
   BitstreamBuffer(const BitstreamBuffer& other);
 
@@ -39,15 +44,21 @@
 
   int32_t id() const { return id_; }
   base::SharedMemoryHandle handle() const { return handle_; }
+
+  // The number of bytes of the actual bitstream data. It is the size of the
+  // content instead of the whole shared memory.
   size_t size() const { return size_; }
 
-  void set_handle(const base::SharedMemoryHandle& handle) { handle_ = handle; }
+  // The offset to the start of actual bitstream data in the shared memory.
+  off_t offset() const { return offset_; }
 
   // The timestamp is only valid if it's not equal to |media::kNoTimestamp()|.
   base::TimeDelta presentation_timestamp() const {
     return presentation_timestamp_;
   }
 
+  void set_handle(const base::SharedMemoryHandle& handle) { handle_ = handle; }
+
   // The following methods come from DecryptConfig.
 
   const std::string& key_id() const { return key_id_; }
@@ -58,6 +69,7 @@
   int32_t id_;
   base::SharedMemoryHandle handle_;
   size_t size_;
+  off_t offset_;
 
   // This is only set when necessary. For example, AndroidVideoDecodeAccelerator
   // needs the timestamp because the underlying decoder may require it to
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index 3d466526..07e2aad 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -717,14 +717,14 @@
   return stats.video_frames_dropped;
 }
 
-unsigned WebMediaPlayerImpl::audioDecodedByteCount() const {
+size_t WebMediaPlayerImpl::audioDecodedByteCount() const {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
 
   PipelineStatistics stats = pipeline_.GetStatistics();
   return stats.audio_bytes_decoded;
 }
 
-unsigned WebMediaPlayerImpl::videoDecodedByteCount() const {
+size_t WebMediaPlayerImpl::videoDecodedByteCount() const {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
 
   PipelineStatistics stats = pipeline_.GetStatistics();
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h
index 5ae347c..9cba070 100644
--- a/media/blink/webmediaplayer_impl.h
+++ b/media/blink/webmediaplayer_impl.h
@@ -147,8 +147,8 @@
 
   unsigned decodedFrameCount() const override;
   unsigned droppedFrameCount() const override;
-  unsigned audioDecodedByteCount() const override;
-  unsigned videoDecodedByteCount() const override;
+  size_t audioDecodedByteCount() const override;
+  size_t videoDecodedByteCount() const override;
 
   bool copyVideoTextureToPlatformTexture(
       blink::WebGraphicsContext3D* web_graphics_context,
diff --git a/media/filters/gpu_video_decoder.cc b/media/filters/gpu_video_decoder.cc
index 260bfaab..aa052dd 100644
--- a/media/filters/gpu_video_decoder.cc
+++ b/media/filters/gpu_video_decoder.cc
@@ -334,7 +334,7 @@
   // AndroidVideoDecodeAccelerator needs the timestamp to output frames in
   // presentation order.
   BitstreamBuffer bitstream_buffer(next_bitstream_buffer_id_,
-                                   shm_buffer->shm->handle(), size,
+                                   shm_buffer->shm->handle(), size, 0,
                                    buffer->timestamp());
 
   if (buffer->decrypt_config())
diff --git a/media/formats/mp4/box_definitions.cc b/media/formats/mp4/box_definitions.cc
index a792c90..705232f4e 100644
--- a/media/formats/mp4/box_definitions.cc
+++ b/media/formats/mp4/box_definitions.cc
@@ -138,6 +138,65 @@
   return true;
 }
 
+SampleEncryptionEntry::SampleEncryptionEntry() {}
+SampleEncryptionEntry::~SampleEncryptionEntry() {}
+
+bool SampleEncryptionEntry::Parse(BufferReader* reader,
+                                  uint8_t iv_size,
+                                  bool has_subsamples) {
+  // According to ISO/IEC FDIS 23001-7: CENC spec, IV should be either
+  // 64-bit (8-byte) or 128-bit (16-byte).
+  RCHECK(iv_size == 8 || iv_size == 16);
+
+  memset(initialization_vector, 0, sizeof(initialization_vector));
+  for (uint8_t i = 0; i < iv_size; i++)
+    RCHECK(reader->Read1(initialization_vector + i));
+
+  if (!has_subsamples) {
+    subsamples.clear();
+    return true;
+  }
+
+  uint16_t subsample_count;
+  RCHECK(reader->Read2(&subsample_count));
+  RCHECK(subsample_count > 0);
+  subsamples.resize(subsample_count);
+  for (SubsampleEntry& subsample : subsamples) {
+    uint16_t clear_bytes;
+    uint32_t cypher_bytes;
+    RCHECK(reader->Read2(&clear_bytes) && reader->Read4(&cypher_bytes));
+    subsample.clear_bytes = clear_bytes;
+    subsample.cypher_bytes = cypher_bytes;
+  }
+  return true;
+}
+
+bool SampleEncryptionEntry::GetTotalSizeOfSubsamples(size_t* total_size) const {
+  size_t size = 0;
+  for (const SubsampleEntry& subsample : subsamples) {
+    size += subsample.clear_bytes;
+    RCHECK(size >= subsample.clear_bytes);  // overflow
+    size += subsample.cypher_bytes;
+    RCHECK(size >= subsample.cypher_bytes);  // overflow
+  }
+  *total_size = size;
+  return true;
+}
+
+SampleEncryption::SampleEncryption() : use_subsample_encryption(false) {}
+SampleEncryption::~SampleEncryption() {}
+FourCC SampleEncryption::BoxType() const {
+  return FOURCC_SENC;
+}
+
+bool SampleEncryption::Parse(BoxReader* reader) {
+  RCHECK(reader->ReadFullBoxHeader());
+  use_subsample_encryption = (reader->flags() & kUseSubsampleEncryption) != 0;
+  sample_encryption_data.assign(reader->data() + reader->pos(),
+                                reader->data() + reader->size());
+  return true;
+}
+
 OriginalFormat::OriginalFormat() : format(FOURCC_NULL) {}
 OriginalFormat::~OriginalFormat() {}
 FourCC OriginalFormat::BoxType() const { return FOURCC_FRMA; }
diff --git a/media/formats/mp4/box_definitions.h b/media/formats/mp4/box_definitions.h
index e6a62bba..542f4de 100644
--- a/media/formats/mp4/box_definitions.h
+++ b/media/formats/mp4/box_definitions.h
@@ -12,6 +12,7 @@
 #include <vector>
 
 #include "base/compiler_specific.h"
+#include "media/base/decrypt_config.h"
 #include "media/base/media_export.h"
 #include "media/base/media_log.h"
 #include "media/base/video_codecs.h"
@@ -78,6 +79,39 @@
   std::vector<uint8_t> sample_info_sizes;
 };
 
+// Represent an entry in SampleEncryption box or CENC auxiliary info.
+struct MEDIA_EXPORT SampleEncryptionEntry {
+  SampleEncryptionEntry();
+  ~SampleEncryptionEntry();
+
+  // Parse SampleEncryptionEntry from |reader|.
+  // |iv_size| specifies the size of initialization vector. |has_subsamples|
+  // indicates whether this sample encryption entry constains subsamples.
+  // Returns false if parsing fails.
+  bool Parse(BufferReader* reader, uint8_t iv_size, bool has_subsamples);
+
+  // Get accumulated size of subsamples. Returns false if there is an overflow
+  // anywhere.
+  bool GetTotalSizeOfSubsamples(size_t* total_size) const;
+
+  uint8_t initialization_vector[16];
+  std::vector<SubsampleEntry> subsamples;
+};
+
+// ISO/IEC 23001-7:2015 8.1.1.
+struct MEDIA_EXPORT SampleEncryption : Box {
+  enum SampleEncryptionFlags {
+    kUseSubsampleEncryption = 2,
+  };
+
+  DECLARE_BOX_METHODS(SampleEncryption);
+
+  bool use_subsample_encryption;
+  // We may not know |iv_size| before reading this box, so we store the box
+  // data for parsing later when |iv_size| is known.
+  std::vector<uint8_t> sample_encryption_data;
+};
+
 struct MEDIA_EXPORT OriginalFormat : Box {
   DECLARE_BOX_METHODS(OriginalFormat);
 
@@ -425,6 +459,7 @@
   IndependentAndDisposableSamples sdtp;
   SampleGroupDescription sample_group_description;
   SampleToGroup sample_to_group;
+  SampleEncryption sample_encryption;
 };
 
 struct MEDIA_EXPORT MovieFragment : Box {
diff --git a/media/formats/mp4/cenc.cc b/media/formats/mp4/cenc.cc
deleted file mode 100644
index 3a7b592..0000000
--- a/media/formats/mp4/cenc.cc
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/formats/mp4/cenc.h"
-
-#include <cstring>
-
-#include "media/formats/mp4/box_reader.h"
-#include "media/formats/mp4/rcheck.h"
-
-namespace media {
-namespace mp4 {
-
-FrameCENCInfo::FrameCENCInfo() {}
-FrameCENCInfo::~FrameCENCInfo() {}
-
-bool FrameCENCInfo::Parse(int iv_size, BufferReader* reader) {
-  const int kEntrySize = 6;
-  // Mandated by CENC spec
-  RCHECK(iv_size == 8 || iv_size == 16);
-
-  memset(iv, 0, sizeof(iv));
-  for (int i = 0; i < iv_size; i++)
-    RCHECK(reader->Read1(&iv[i]));
-
-  if (!reader->HasBytes(1)) return true;
-
-  uint16_t subsample_count;
-  RCHECK(reader->Read2(&subsample_count) &&
-         reader->HasBytes(subsample_count * kEntrySize));
-
-  subsamples.resize(subsample_count);
-  for (int i = 0; i < subsample_count; i++) {
-    uint16_t clear_bytes;
-    uint32_t cypher_bytes;
-    RCHECK(reader->Read2(&clear_bytes) &&
-           reader->Read4(&cypher_bytes));
-    subsamples[i].clear_bytes = clear_bytes;
-    subsamples[i].cypher_bytes = cypher_bytes;
-  }
-  return true;
-}
-
-bool FrameCENCInfo::GetTotalSizeOfSubsamples(size_t* total_size) const {
-  size_t size = 0;
-  for (size_t i = 0; i < subsamples.size(); i++) {
-    size += subsamples[i].clear_bytes;
-    RCHECK(size >= subsamples[i].clear_bytes);  // overflow
-    size += subsamples[i].cypher_bytes;
-    RCHECK(size >= subsamples[i].cypher_bytes);  // overflow
-  }
-  *total_size = size;
-  return true;
-}
-
-}  // namespace mp4
-}  // namespace media
diff --git a/media/formats/mp4/cenc.h b/media/formats/mp4/cenc.h
deleted file mode 100644
index 6e3b3805..0000000
--- a/media/formats/mp4/cenc.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_FORMATS_MP4_CENC_H_
-#define MEDIA_FORMATS_MP4_CENC_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <vector>
-
-#include "media/base/decrypt_config.h"
-
-namespace media {
-namespace mp4 {
-
-class BufferReader;
-
-struct FrameCENCInfo {
-  uint8_t iv[16];
-  std::vector<SubsampleEntry> subsamples;
-
-  FrameCENCInfo();
-  ~FrameCENCInfo();
-  bool Parse(int iv_size, BufferReader* r) WARN_UNUSED_RESULT;
-  bool GetTotalSizeOfSubsamples(size_t* total_size) const WARN_UNUSED_RESULT;
-};
-
-
-}  // namespace mp4
-}  // namespace media
-
-#endif  // MEDIA_FORMATS_MP4_CENC_H_
diff --git a/media/formats/mp4/fourccs.h b/media/formats/mp4/fourccs.h
index ad5f4a3..ac39bd4 100644
--- a/media/formats/mp4/fourccs.h
+++ b/media/formats/mp4/fourccs.h
@@ -69,6 +69,7 @@
   FOURCC_SCHM = 0x7363686d,
   FOURCC_SDTP = 0x73647470,
   FOURCC_SEIG = 0x73656967,
+  FOURCC_SENC = 0x73656e63,
   FOURCC_SGPD = 0x73677064,
   FOURCC_SIDX = 0x73696478,
   FOURCC_SINF = 0x73696e66,
diff --git a/media/formats/mp4/mp4_stream_parser_unittest.cc b/media/formats/mp4/mp4_stream_parser_unittest.cc
index 1fd2b75..c7d41fe 100644
--- a/media/formats/mp4/mp4_stream_parser_unittest.cc
+++ b/media/formats/mp4/mp4_stream_parser_unittest.cc
@@ -45,8 +45,8 @@
   return CONTAINS_STRING(arg, "Audio codec: " + std::string(codec_string));
 }
 
-MATCHER(AuxInfoUnavailableLog, "") {
-  return CONTAINS_STRING(arg, "Aux Info is not available.");
+MATCHER(SampleEncryptionInfoUnavailableLog, "") {
+  return CONTAINS_STRING(arg, "Sample encryption info is not available.");
 }
 
 MATCHER_P(ErrorLog, error_string, "") {
@@ -284,9 +284,10 @@
 }
 
 // Test an invalid file where there are encrypted samples, but
-// SampleAuxiliaryInformation{Sizes|Offsets}Box (saiz|saio) are missing.
+// SampleEncryptionBox (senc) and SampleAuxiliaryInformation{Sizes|Offsets}Box
+// (saiz|saio) are missing.
 // The parser should fail instead of crash. See http://crbug.com/361347
-TEST_F(MP4StreamParserTest, MissingSampleAuxInfo) {
+TEST_F(MP4StreamParserTest, MissingSampleEncryptionInfo) {
   InSequence s;
 
   // Encrypted test mp4 files have non-zero duration and are treated as
@@ -296,7 +297,7 @@
   scoped_refptr<DecoderBuffer> buffer =
       ReadTestDataFile("bear-1280x720-a_frag-cenc_missing-saiz-saio.mp4");
   EXPECT_MEDIA_LOG(AudioCodecLog("mp4a.40.2")).Times(2);
-  EXPECT_MEDIA_LOG(AuxInfoUnavailableLog());
+  EXPECT_MEDIA_LOG(SampleEncryptionInfoUnavailableLog());
   EXPECT_FALSE(AppendDataInPieces(buffer->data(), buffer->data_size(), 512));
 }
 
@@ -321,7 +322,9 @@
             AppendDataInPieces(buffer->data(), buffer->data_size(), 512));
 }
 
-TEST_F(MP4StreamParserTest, CENC) {
+// Sample encryption information is stored as CencSampleAuxiliaryDataFormat
+// (ISO/IEC 23001-7:2015 8) inside 'mdat' box. No SampleEncryption ('senc') box.
+TEST_F(MP4StreamParserTest, CencWithEncryptionInfoStoredAsAuxDataInMdat) {
   // Encrypted test mp4 files have non-zero duration and are treated as
   // recorded streams.
   InitializeParserAndExpectLiveness(DemuxerStream::LIVENESS_RECORDED);
@@ -332,6 +335,17 @@
   EXPECT_TRUE(AppendDataInPieces(buffer->data(), buffer->data_size(), 512));
 }
 
+TEST_F(MP4StreamParserTest, CencWithSampleEncryptionBox) {
+  // Encrypted test mp4 files have non-zero duration and are treated as
+  // recorded streams.
+  InitializeParserAndExpectLiveness(DemuxerStream::LIVENESS_RECORDED);
+
+  scoped_refptr<DecoderBuffer> buffer =
+      ReadTestDataFile("bear-640x360-v_frag-cenc-senc.mp4");
+  EXPECT_MEDIA_LOG(VideoCodecLog("avc1.64001E"));
+  EXPECT_TRUE(AppendDataInPieces(buffer->data(), buffer->data_size(), 512));
+}
+
 TEST_F(MP4StreamParserTest, NaturalSizeWithoutPASP) {
   InitializeParserAndExpectLiveness(DemuxerStream::LIVENESS_RECORDED);
 
diff --git a/media/formats/mp4/track_run_iterator.cc b/media/formats/mp4/track_run_iterator.cc
index c47b8a3a..7dae938 100644
--- a/media/formats/mp4/track_run_iterator.cc
+++ b/media/formats/mp4/track_run_iterator.cc
@@ -35,6 +35,12 @@
   const VideoSampleEntry* video_description;
   const SampleGroupDescription* track_sample_encryption_group;
 
+  // Stores sample encryption entries, which is populated from 'senc' box if it
+  // is available, otherwise will try to load from cenc auxiliary information.
+  std::vector<SampleEncryptionEntry> sample_encryption_entries;
+
+  // These variables are useful to load |sample_encryption_entries| from cenc
+  // auxiliary information when 'senc' box is not available.
   int64_t aux_info_start_offset;  // Only valid if aux_info_total_size > 0.
   int aux_info_default_size;
   std::vector<uint8_t> aux_info_sizes;  // Populated if default_size == 0.
@@ -272,6 +278,16 @@
     RCHECK(desc_idx > 0);  // Descriptions are one-indexed in the file
     desc_idx -= 1;
 
+    const std::vector<uint8_t>& sample_encryption_data =
+        traf.sample_encryption.sample_encryption_data;
+    scoped_ptr<BufferReader> sample_encryption_reader;
+    uint32_t sample_encrytion_entries_count = 0;
+    if (!sample_encryption_data.empty()) {
+      sample_encryption_reader.reset(new BufferReader(
+          sample_encryption_data.data(), sample_encryption_data.size()));
+      RCHECK(sample_encryption_reader->Read4(&sample_encrytion_entries_count));
+    }
+
     // Process edit list to remove CTS offset introduced in the presence of
     // B-frames (those that contain a single edit with a nonnegative media
     // time). Other uses of edit lists are not supported, as they are
@@ -306,23 +322,30 @@
       tri.fragment_sample_encryption_info =
           traf.sample_group_description.entries;
 
+      uint8_t default_iv_size = 0;
       tri.is_audio = (stsd.type == kAudio);
       if (tri.is_audio) {
         RCHECK(!stsd.audio_entries.empty());
         if (desc_idx > stsd.audio_entries.size())
           desc_idx = 0;
         tri.audio_description = &stsd.audio_entries[desc_idx];
+        default_iv_size =
+            tri.audio_description->sinf.info.track_encryption.default_iv_size;
       } else {
         RCHECK(!stsd.video_entries.empty());
         if (desc_idx > stsd.video_entries.size())
           desc_idx = 0;
         tri.video_description = &stsd.video_entries[desc_idx];
+        default_iv_size =
+            tri.video_description->sinf.info.track_encryption.default_iv_size;
       }
 
-      // Collect information from the auxiliary_offset entry with the same index
-      // in the 'saiz' container as the current run's index in the 'trun'
-      // container, if it is present.
-      if (traf.auxiliary_offset.offsets.size() > j) {
+      // Initialize aux_info variables only if no sample encryption entries.
+      if (sample_encrytion_entries_count == 0 &&
+          traf.auxiliary_offset.offsets.size() > j) {
+        // Collect information from the auxiliary_offset entry with the same
+        // index in the 'saiz' container as the current run's index in the
+        // 'trun' container, if it is present.
         // There should be an auxiliary info entry corresponding to each sample
         // in the auxiliary offset entry's corresponding track run.
         RCHECK(traf.auxiliary_size.sample_count >=
@@ -333,8 +356,8 @@
         if (tri.aux_info_default_size == 0) {
           const std::vector<uint8_t>& sizes =
               traf.auxiliary_size.sample_info_sizes;
-          tri.aux_info_sizes.insert(tri.aux_info_sizes.begin(),
-              sizes.begin() + sample_count_sum,
+          tri.aux_info_sizes.insert(
+              tri.aux_info_sizes.begin(), sizes.begin() + sample_count_sum,
               sizes.begin() + sample_count_sum + trun.sample_count);
         }
 
@@ -378,6 +401,20 @@
           RCHECK(GetSampleEncryptionInfoEntry(tri, index));
         is_sample_to_group_valid = sample_to_group_itr.Advance();
       }
+      if (sample_encrytion_entries_count > 0) {
+        RCHECK(sample_encrytion_entries_count >=
+               sample_count_sum + trun.sample_count);
+        tri.sample_encryption_entries.resize(trun.sample_count);
+        for (size_t k = 0; k < trun.sample_count; k++) {
+          uint32_t index = tri.samples[k].cenc_group_description_index;
+          const uint8_t iv_size =
+              index == 0 ? default_iv_size
+                         : GetSampleEncryptionInfoEntry(tri, index)->iv_size;
+          RCHECK(tri.sample_encryption_entries[k].Parse(
+              sample_encryption_reader.get(), iv_size,
+              traf.sample_encryption.use_subsample_encryption));
+        }
+      }
       runs_.push_back(tri);
       sample_count_sum += trun.sample_count;
     }
@@ -402,7 +439,6 @@
   sample_dts_ = run_itr_->start_dts;
   sample_offset_ = run_itr_->sample_start_offset;
   sample_itr_ = run_itr_->samples.begin();
-  cenc_info_.clear();
 }
 
 void TrackRunIterator::AdvanceSample() {
@@ -416,14 +452,17 @@
 // info is available in the stream.
 bool TrackRunIterator::AuxInfoNeedsToBeCached() {
   DCHECK(IsRunValid());
-  return aux_info_size() > 0 && cenc_info_.size() == 0;
+  return is_encrypted() && aux_info_size() > 0 &&
+         run_itr_->sample_encryption_entries.size() == 0;
 }
 
 // This implementation currently only caches CENC auxiliary info.
 bool TrackRunIterator::CacheAuxInfo(const uint8_t* buf, int buf_size) {
   RCHECK(AuxInfoNeedsToBeCached() && buf_size >= aux_info_size());
 
-  cenc_info_.resize(run_itr_->samples.size());
+  std::vector<SampleEncryptionEntry>& sample_encryption_entries =
+      runs_[run_itr_ - runs_.begin()].sample_encryption_entries;
+  sample_encryption_entries.resize(run_itr_->samples.size());
   int64_t pos = 0;
   for (size_t i = 0; i < run_itr_->samples.size(); i++) {
     int info_size = run_itr_->aux_info_default_size;
@@ -432,7 +471,10 @@
 
     if (IsSampleEncrypted(i)) {
       BufferReader reader(buf + pos, info_size);
-      RCHECK(cenc_info_[i].Parse(GetIvSize(i), &reader));
+      const uint8_t iv_size = GetIvSize(i);
+      const bool has_subsamples = info_size > iv_size;
+      RCHECK(
+          sample_encryption_entries[i].Parse(&reader, iv_size, has_subsamples));
     }
     pos += info_size;
   }
@@ -550,19 +592,20 @@
 scoped_ptr<DecryptConfig> TrackRunIterator::GetDecryptConfig() {
   DCHECK(is_encrypted());
 
-  if (cenc_info_.empty()) {
+  if (run_itr_->sample_encryption_entries.empty()) {
     DCHECK_EQ(0, aux_info_size());
-    MEDIA_LOG(ERROR, media_log_) << "Aux Info is not available.";
+    MEDIA_LOG(ERROR, media_log_) << "Sample encryption info is not available.";
     return scoped_ptr<DecryptConfig>();
   }
 
   size_t sample_idx = sample_itr_ - run_itr_->samples.begin();
-  DCHECK_LT(sample_idx, cenc_info_.size());
-  const FrameCENCInfo& cenc_info = cenc_info_[sample_idx];
+  DCHECK_LT(sample_idx, run_itr_->sample_encryption_entries.size());
+  const SampleEncryptionEntry& sample_encryption_entry =
+      run_itr_->sample_encryption_entries[sample_idx];
 
   size_t total_size = 0;
-  if (!cenc_info.subsamples.empty() &&
-      (!cenc_info.GetTotalSizeOfSubsamples(&total_size) ||
+  if (!sample_encryption_entry.subsamples.empty() &&
+      (!sample_encryption_entry.GetTotalSizeOfSubsamples(&total_size) ||
        total_size != static_cast<size_t>(sample_size()))) {
     MEDIA_LOG(ERROR, media_log_) << "Incorrect CENC subsample size.";
     return scoped_ptr<DecryptConfig>();
@@ -571,9 +614,10 @@
   const std::vector<uint8_t>& kid = GetKeyId(sample_idx);
   return scoped_ptr<DecryptConfig>(new DecryptConfig(
       std::string(reinterpret_cast<const char*>(&kid[0]), kid.size()),
-      std::string(reinterpret_cast<const char*>(cenc_info.iv),
-                  arraysize(cenc_info.iv)),
-      cenc_info.subsamples));
+      std::string(reinterpret_cast<const char*>(
+                      sample_encryption_entry.initialization_vector),
+                  arraysize(sample_encryption_entry.initialization_vector)),
+      sample_encryption_entry.subsamples));
 }
 
 uint32_t TrackRunIterator::GetGroupDescriptionIndex(
diff --git a/media/formats/mp4/track_run_iterator.h b/media/formats/mp4/track_run_iterator.h
index bab090e6..4903f76 100644
--- a/media/formats/mp4/track_run_iterator.h
+++ b/media/formats/mp4/track_run_iterator.h
@@ -17,7 +17,6 @@
 #include "media/base/media_log.h"
 #include "media/base/stream_parser_buffer.h"
 #include "media/formats/mp4/box_definitions.h"
-#include "media/formats/mp4/cenc.h"
 
 namespace media {
 
@@ -108,8 +107,6 @@
   std::vector<TrackRunInfo>::const_iterator run_itr_;
   std::vector<SampleInfo>::const_iterator sample_itr_;
 
-  std::vector<FrameCENCInfo> cenc_info_;
-
   int64_t sample_dts_;
   int64_t sample_offset_;
 
diff --git a/media/formats/mp4/track_run_iterator_unittest.cc b/media/formats/mp4/track_run_iterator_unittest.cc
index 3ac4a41..20023b4 100644
--- a/media/formats/mp4/track_run_iterator_unittest.cc
+++ b/media/formats/mp4/track_run_iterator_unittest.cc
@@ -18,34 +18,84 @@
 
 using ::testing::StrictMock;
 
+namespace {
+
 // The sum of the elements in a vector initialized with SumAscending,
 // less the value of the last element.
-static const int kSumAscending1 = 45;
+const int kSumAscending1 = 45;
 
-static const int kAudioScale = 48000;
-static const int kVideoScale = 25;
+const int kAudioScale = 48000;
+const int kVideoScale = 25;
 
-static const uint8_t kAuxInfo[] = {
+const uint8_t kAuxInfo[] = {
     0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x31, 0x41, 0x54,
     0x65, 0x73, 0x74, 0x49, 0x76, 0x32, 0x00, 0x02, 0x00, 0x01,
-    0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04};
-
-static const char kIv1[] = {
-  0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x31,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+    0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04,
 };
 
-static const uint8_t kKeyId[] = {0x41, 0x47, 0x6f, 0x6f, 0x67, 0x6c,
-                                 0x65, 0x54, 0x65, 0x73, 0x74, 0x4b,
-                                 0x65, 0x79, 0x49, 0x44};
+// Sample encryption data for two samples, one with 8 byte IV, one with 16 byte
+// IV. This data is generated for testing. It should be very unlikely to see
+// IV of mixed size in actual media files, though it is permitted by spec.
+const uint8_t kSampleEncryptionDataWithSubsamples[] = {
+    // Sample count.
+    0x00, 0x00, 0x00, 0x02,
+    // Sample 1: IV (8 Bytes).
+    0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x31,
+    // Sample 1: Subsample count.
+    0x00, 0x01,
+    // Sample 1: Subsample 1.
+    0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
+    // Sample 2: IV (16 bytes).
+    0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x32, 0x41, 0x42, 0x43, 0x44,
+    0x45, 0x46, 0x47, 0x48,
+    // Sample 2: Subsample count.
+    0x00, 0x02,
+    // Sample 2: Subsample 1.
+    0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
+    // Sample 2: Subsample 2.
+    0x00, 0x03, 0x00, 0x00, 0x00, 0x04,
+};
 
-static const uint8_t kTrackCencSampleGroupKeyId[] = {
+const uint8_t kSampleEncryptionDataWithoutSubsamples[] = {
+    // Sample count.
+    0x00, 0x00, 0x00, 0x02,
+    // Sample 1: IV.
+    0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x31,
+    // Sample 2: IV.
+    0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x32,
+};
+
+// Size of these two IVs are 8 bytes. They are padded with 0 to 16 bytes.
+const char kIv1[] = {
+    0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x31,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+const char kIv2[] = {
+    0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x32,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+// Size of this IV is 16 bytes.
+const char kIv3[] = {
+    0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x32,
+    0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+};
+
+const uint8_t kKeyId[] = {
+    0x41, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x54,
+    0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x49, 0x44,
+};
+
+const uint8_t kTrackCencSampleGroupKeyId[] = {
     0x46, 0x72, 0x61, 0x67, 0x53, 0x61, 0x6d, 0x70,
-    0x6c, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4b};
+    0x6c, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4b,
+};
 
-static const uint8_t kFragmentCencSampleGroupKeyId[] = {
+const uint8_t kFragmentCencSampleGroupKeyId[] = {
     0x6b, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e,
-    0x74, 0x43, 0x65, 0x6e, 0x63, 0x53, 0x61, 0x6d};
+    0x74, 0x43, 0x65, 0x6e, 0x63, 0x53, 0x61, 0x6d,
+};
+
+}  // namespace
 
 namespace media {
 namespace mp4 {
@@ -241,7 +291,7 @@
         kTrackCencSampleGroupKeyId + arraysize(kTrackCencSampleGroupKeyId));
 
     frag->sample_group_description.grouping_type = FOURCC_SEIG;
-    frag->sample_group_description.entries.resize(2);
+    frag->sample_group_description.entries.resize(3);
     frag->sample_group_description.entries[0].is_encrypted = false;
     frag->sample_group_description.entries[0].iv_size = 0;
     frag->sample_group_description.entries[1].is_encrypted = true;
@@ -250,6 +300,10 @@
         kFragmentCencSampleGroupKeyId,
         kFragmentCencSampleGroupKeyId +
             arraysize(kFragmentCencSampleGroupKeyId));
+    frag->sample_group_description.entries[2].is_encrypted = true;
+    frag->sample_group_description.entries[2].iv_size = 16;
+    frag->sample_group_description.entries[2].key_id.assign(
+        kKeyId, kKeyId + arraysize(kKeyId));
 
     frag->sample_to_group.grouping_type = FOURCC_SEIG;
     frag->sample_to_group.entries.assign(sample_to_group_entries,
@@ -267,6 +321,37 @@
     frag->runs[0].sample_sizes[1] = 10;
   }
 
+  void AddSampleEncryption(uint8_t use_subsample_flag, TrackFragment* frag) {
+    frag->sample_encryption.use_subsample_encryption = use_subsample_flag;
+    if (use_subsample_flag) {
+      frag->sample_encryption.sample_encryption_data.assign(
+          kSampleEncryptionDataWithSubsamples,
+          kSampleEncryptionDataWithSubsamples +
+              arraysize(kSampleEncryptionDataWithSubsamples));
+    } else {
+      frag->sample_encryption.sample_encryption_data.assign(
+          kSampleEncryptionDataWithoutSubsamples,
+          kSampleEncryptionDataWithoutSubsamples +
+              arraysize(kSampleEncryptionDataWithoutSubsamples));
+    }
+
+    // Update sample sizes and aux info header.
+    frag->runs.resize(1);
+    frag->runs[0].sample_count = 2;
+    frag->auxiliary_offset.offsets.push_back(0);
+    frag->auxiliary_size.sample_count = 2;
+    if (use_subsample_flag) {
+      // Update sample sizes to match with subsample entries above.
+      frag->runs[0].sample_sizes[0] = 3;
+      frag->runs[0].sample_sizes[1] = 10;
+      // Set aux info header.
+      frag->auxiliary_size.sample_info_sizes.push_back(16);
+      frag->auxiliary_size.sample_info_sizes.push_back(30);
+    } else {
+      frag->auxiliary_size.default_sample_info_size = 8;
+    }
+  }
+
   bool InitMoofWithArbitraryAuxInfo(MovieFragment* moof) {
     // Add aux info header (equal sized aux info for every sample).
     for (uint32_t i = 0; i < moof->tracks.size(); ++i) {
@@ -470,7 +555,89 @@
   EXPECT_FALSE(iter_->AuxInfoNeedsToBeCached());
 }
 
-TEST_F(TrackRunIteratorTest, DecryptConfigTest) {
+TEST_F(TrackRunIteratorTest,
+       DecryptConfigTestWithSampleEncryptionAndNoSubsample) {
+  AddEncryption(&moov_.tracks[1]);
+  iter_.reset(new TrackRunIterator(&moov_, media_log_));
+
+  MovieFragment moof = CreateFragment();
+  AddSampleEncryption(!SampleEncryption::kUseSubsampleEncryption,
+                      &moof.tracks[1]);
+
+  ASSERT_TRUE(iter_->Init(moof));
+  // The run for track 2 will be the second, which is parsed according to
+  // data_offset.
+  iter_->AdvanceRun();
+  EXPECT_EQ(iter_->track_id(), 2u);
+
+  EXPECT_TRUE(iter_->is_encrypted());
+  // No need to cache aux info as it is already available in SampleEncryption.
+  EXPECT_FALSE(iter_->AuxInfoNeedsToBeCached());
+  EXPECT_EQ(iter_->aux_info_size(), 0);
+  EXPECT_EQ(iter_->sample_offset(), 200);
+  EXPECT_EQ(iter_->GetMaxClearOffset(), moof.tracks[1].runs[0].data_offset);
+  scoped_ptr<DecryptConfig> config = iter_->GetDecryptConfig();
+  EXPECT_EQ(
+      std::string(reinterpret_cast<const char*>(kKeyId), arraysize(kKeyId)),
+      config->key_id());
+  EXPECT_EQ(std::string(reinterpret_cast<const char*>(kIv1), arraysize(kIv1)),
+            config->iv());
+  EXPECT_EQ(config->subsamples().size(), 0u);
+  iter_->AdvanceSample();
+  config = iter_->GetDecryptConfig();
+  EXPECT_EQ(std::string(reinterpret_cast<const char*>(kIv2), arraysize(kIv2)),
+            config->iv());
+  EXPECT_EQ(config->subsamples().size(), 0u);
+}
+
+TEST_F(TrackRunIteratorTest,
+       DecryptConfigTestWithSampleEncryptionAndSubsample) {
+  AddEncryption(&moov_.tracks[1]);
+  iter_.reset(new TrackRunIterator(&moov_, media_log_));
+
+  MovieFragment moof = CreateFragment();
+  AddSampleEncryption(SampleEncryption::kUseSubsampleEncryption,
+                      &moof.tracks[1]);
+  const SampleToGroupEntry kSampleToGroupTable[] = {
+      // Associated with the second entry in SampleGroupDescription Box.
+      // With Iv size 8 bytes.
+      {1, SampleToGroupEntry::kFragmentGroupDescriptionIndexBase + 2},
+      // Associated with the third entry in SampleGroupDescription Box.
+      // With Iv size 16 bytes.
+      {1, SampleToGroupEntry::kFragmentGroupDescriptionIndexBase + 3}};
+  AddCencSampleGroup(&moov_.tracks[1], &moof.tracks[1], kSampleToGroupTable,
+                     arraysize(kSampleToGroupTable));
+
+  ASSERT_TRUE(iter_->Init(moof));
+  // The run for track 2 will be the second, which is parsed according to
+  // data_offset.
+  iter_->AdvanceRun();
+  EXPECT_EQ(iter_->track_id(), 2u);
+
+  EXPECT_TRUE(iter_->is_encrypted());
+  // No need to cache aux info as it is already available in SampleEncryption.
+  EXPECT_FALSE(iter_->AuxInfoNeedsToBeCached());
+  EXPECT_EQ(iter_->aux_info_size(), 0);
+  EXPECT_EQ(iter_->sample_offset(), 200);
+  EXPECT_EQ(iter_->GetMaxClearOffset(), moof.tracks[1].runs[0].data_offset);
+  scoped_ptr<DecryptConfig> config = iter_->GetDecryptConfig();
+  EXPECT_EQ(std::string(reinterpret_cast<const char*>(kIv1), arraysize(kIv1)),
+            config->iv());
+  EXPECT_EQ(config->subsamples().size(), 1u);
+  EXPECT_EQ(config->subsamples()[0].clear_bytes, 1u);
+  EXPECT_EQ(config->subsamples()[0].cypher_bytes, 2u);
+  iter_->AdvanceSample();
+  config = iter_->GetDecryptConfig();
+  EXPECT_EQ(std::string(reinterpret_cast<const char*>(kIv3), arraysize(kIv3)),
+            config->iv());
+  EXPECT_EQ(config->subsamples().size(), 2u);
+  EXPECT_EQ(config->subsamples()[0].clear_bytes, 1u);
+  EXPECT_EQ(config->subsamples()[0].cypher_bytes, 2u);
+  EXPECT_EQ(config->subsamples()[1].clear_bytes, 3u);
+  EXPECT_EQ(config->subsamples()[1].cypher_bytes, 4u);
+}
+
+TEST_F(TrackRunIteratorTest, DecryptConfigTestWithAuxInfo) {
   AddEncryption(&moov_.tracks[1]);
   iter_.reset(new TrackRunIterator(&moov_, media_log_));
 
@@ -483,7 +650,7 @@
   // element in the file.
   EXPECT_EQ(iter_->track_id(), 2u);
   EXPECT_TRUE(iter_->is_encrypted());
-  EXPECT_TRUE(iter_->AuxInfoNeedsToBeCached());
+  ASSERT_TRUE(iter_->AuxInfoNeedsToBeCached());
   EXPECT_EQ(static_cast<uint32_t>(iter_->aux_info_size()), arraysize(kAuxInfo));
   EXPECT_EQ(iter_->aux_info_offset(), 50);
   EXPECT_EQ(iter_->GetMaxClearOffset(), 50);
@@ -495,11 +662,11 @@
   EXPECT_EQ(iter_->sample_offset(), 200);
   EXPECT_EQ(iter_->GetMaxClearOffset(), moof.tracks[0].runs[0].data_offset);
   scoped_ptr<DecryptConfig> config = iter_->GetDecryptConfig();
-  ASSERT_EQ(arraysize(kKeyId), config->key_id().size());
-  EXPECT_TRUE(!memcmp(kKeyId, config->key_id().data(),
-                      config->key_id().size()));
-  ASSERT_EQ(arraysize(kIv1), config->iv().size());
-  EXPECT_TRUE(!memcmp(kIv1, config->iv().data(), config->iv().size()));
+  EXPECT_EQ(
+      std::string(reinterpret_cast<const char*>(kKeyId), arraysize(kKeyId)),
+      config->key_id());
+  EXPECT_EQ(std::string(reinterpret_cast<const char*>(kIv1), arraysize(kIv1)),
+            config->iv());
   EXPECT_TRUE(config->subsamples().empty());
   iter_->AdvanceSample();
   config = iter_->GetDecryptConfig();
diff --git a/media/media.gyp b/media/media.gyp
index bdc7d5c..071444aa 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -1023,8 +1023,6 @@
             'formats/mp4/box_definitions.h',
             'formats/mp4/box_reader.cc',
             'formats/mp4/box_reader.h',
-            'formats/mp4/cenc.cc',
-            'formats/mp4/cenc.h',
             'formats/mp4/es_descriptor.cc',
             'formats/mp4/es_descriptor.h',
             'formats/mp4/mp4_stream_parser.cc',
diff --git a/media/mojo/services/mojo_media_application.cc b/media/mojo/services/mojo_media_application.cc
index 380d95f0..8925e99 100644
--- a/media/mojo/services/mojo_media_application.cc
+++ b/media/mojo/services/mojo_media_application.cc
@@ -26,8 +26,7 @@
 MojoMediaApplication::~MojoMediaApplication() {}
 
 void MojoMediaApplication::Initialize(mojo::Connector* connector,
-                                      const std::string& /* url */,
-                                      const std::string& user_id,
+                                      const mojo::Identity& identity,
                                       uint32_t /* id */) {
   connector_ = connector;
   mojo_media_client_->Initialize();
diff --git a/media/mojo/services/mojo_media_application.h b/media/mojo/services/mojo_media_application.h
index 9844ab13..c004e83 100644
--- a/media/mojo/services/mojo_media_application.h
+++ b/media/mojo/services/mojo_media_application.h
@@ -28,8 +28,7 @@
  private:
   // mojo::ShellClient implementation.
   void Initialize(mojo::Connector* connector,
-                  const std::string& url,
-                  const std::string& user_id,
+                  const mojo::Identity& identity,
                   uint32_t id) final;
   bool AcceptConnection(mojo::Connection* connection) final;
 
diff --git a/media/test/data/README b/media/test/data/README
index 4b85fe39..6f27250 100644
--- a/media/test/data/README
+++ b/media/test/data/README
@@ -68,7 +68,8 @@
 bear-320x240-opus-av_enc-v.webm - bear-vp9-opus.webm with video track encrypted using key ID [1] and key[2].
 bear-640x360-a_frag-cenc.mp4 - A fragmented MP4 version of the audio track of bear-640x360.mp4 encrypted (ISO CENC) using key ID [1] and key [2].
 bear-640x360-a_frag-cenc-key_rotation.mp4 - A fragmented MP4 version of the audio track of bear-640x360.mp4 encrypted (ISO CENC) using key ID [1] and key [2] with key rotation [3].
-bear-640x360-v_frag-cenc.mp4 - A fragmented MP4 version of the video track of bear-640x360.mp4 encrypted (ISO CENC) using key ID [1] and key [2].
+bear-640x360-v_frag-cenc.mp4 - A fragmented MP4 version of the video track of bear-640x360.mp4 encrypted (ISO CENC) using key ID [1] and key [2]  and with sample encryption auxiliary information in the beginning of mdat box.
+bear-640x360-v_frag-cenc-senc.mp4 - Same as above, but with sample encryption information stored in SampleEncryption ('senc') box.
 bear-640x360-v_frag-cenc-key_rotation.mp4 - A fragmented MP4 version of the video track of bear-640x360.mp4 encrypted (ISO CENC) using key ID [1] and key [2] with key rotation [3].
 bear-a_enc-a.webm - bear-320x240-audio-only.webm encrypted using key ID [1] and key [2].
 frame_size_change-av_enc-v.webm - third_party/WebKit/LayoutTests/media/resources/frame_size_change.webm encrypted using key ID [1] and key [2].
diff --git a/media/test/data/bear-640x360-v_frag-cenc-senc.mp4 b/media/test/data/bear-640x360-v_frag-cenc-senc.mp4
new file mode 100644
index 0000000..05761982
--- /dev/null
+++ b/media/test/data/bear-640x360-v_frag-cenc-senc.mp4
Binary files differ
diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc
index 9f4deaf..1f0c3a8 100644
--- a/media/test/pipeline_integration_test.cc
+++ b/media/test/pipeline_integration_test.cc
@@ -1708,6 +1708,23 @@
 }
 
 TEST_F(PipelineIntegrationTest,
+       MAYBE_EME(EncryptedPlayback_MP4_CENC_SENC_Video)) {
+  MockMediaSource source("bear-640x360-v_frag-cenc-senc.mp4", kMP4Video,
+                         kAppendWholeFile);
+  FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
+  StartPipelineWithEncryptedMedia(&source, &encrypted_media);
+
+  source.EndOfStream();
+  ASSERT_EQ(PIPELINE_OK, pipeline_status_);
+
+  Play();
+
+  ASSERT_TRUE(WaitUntilOnEnded());
+  source.Shutdown();
+  Stop();
+}
+
+TEST_F(PipelineIntegrationTest,
        MAYBE_EME(EncryptedPlayback_MP4_CENC_KeyRotation_Video)) {
   MockMediaSource source("bear-1280x720-v_frag-cenc-key_rotation.mp4",
                          kMP4Video, kAppendWholeFile);
diff --git a/mojo/edk/system/data_pipe_consumer_dispatcher.cc b/mojo/edk/system/data_pipe_consumer_dispatcher.cc
index 2dfddbc..10a8069 100644
--- a/mojo/edk/system/data_pipe_consumer_dispatcher.cc
+++ b/mojo/edk/system/data_pipe_consumer_dispatcher.cc
@@ -29,14 +29,24 @@
 
 namespace {
 
-struct MOJO_ALIGNAS(8) SerializedState {
+const uint8_t kFlagPeerClosed = 0x01;
+
+#pragma pack(push, 1)
+
+struct SerializedState {
   MojoCreateDataPipeOptions options;
   uint64_t pipe_id;
-  bool peer_closed;
   uint32_t read_offset;
   uint32_t bytes_available;
+  uint8_t flags;
+  char padding[7];
 };
 
+static_assert(sizeof(SerializedState) % 8 == 0,
+              "Invalid SerializedState size.");
+
+#pragma pack(pop)
+
 }  // namespace
 
 // A PortObserver which forwards to a DataPipeConsumerDispatcher. This owns a
@@ -324,13 +334,14 @@
     PlatformHandle* platform_handles) {
   SerializedState* state = static_cast<SerializedState*>(destination);
   memcpy(&state->options, &options_, sizeof(MojoCreateDataPipeOptions));
+  memset(state->padding, 0, sizeof(state->padding));
 
   base::AutoLock lock(lock_);
   DCHECK(in_transit_);
   state->pipe_id = pipe_id_;
-  state->peer_closed = peer_closed_;
   state->read_offset = read_offset_;
   state->bytes_available = bytes_available_;
+  state->flags = peer_closed_ ? kFlagPeerClosed : 0;
 
   ports[0] = control_port_.name();
 
@@ -405,9 +416,9 @@
 
   {
     base::AutoLock lock(dispatcher->lock_);
-    dispatcher->peer_closed_ = state->peer_closed;
     dispatcher->read_offset_ = state->read_offset;
     dispatcher->bytes_available_ = state->bytes_available;
+    dispatcher->peer_closed_ = state->flags & kFlagPeerClosed;
     dispatcher->InitializeNoLock();
   }
 
diff --git a/mojo/edk/system/data_pipe_producer_dispatcher.cc b/mojo/edk/system/data_pipe_producer_dispatcher.cc
index 0aa8f7e..9f6a72e1 100644
--- a/mojo/edk/system/data_pipe_producer_dispatcher.cc
+++ b/mojo/edk/system/data_pipe_producer_dispatcher.cc
@@ -28,14 +28,24 @@
 
 namespace {
 
+const uint8_t kFlagPeerClosed = 0x01;
+
+#pragma pack(push, 1)
+
 struct SerializedState {
   MojoCreateDataPipeOptions options;
   uint64_t pipe_id;
-  bool peer_closed;
   uint32_t write_offset;
   uint32_t available_capacity;
+  uint8_t flags;
+  char padding[7];
 };
 
+static_assert(sizeof(SerializedState) % 8 == 0,
+              "Invalid SerializedState size.");
+
+#pragma pack(pop)
+
 }  // namespace
 
 // A PortObserver which forwards to a DataPipeProducerDispatcher. This owns a
@@ -306,13 +316,14 @@
     PlatformHandle* platform_handles) {
   SerializedState* state = static_cast<SerializedState*>(destination);
   memcpy(&state->options, &options_, sizeof(MojoCreateDataPipeOptions));
+  memset(state->padding, 0, sizeof(state->padding));
 
   base::AutoLock lock(lock_);
   DCHECK(in_transit_);
   state->pipe_id = pipe_id_;
-  state->peer_closed = peer_closed_;
   state->write_offset = write_offset_;
   state->available_capacity = available_capacity_;
+  state->flags = peer_closed_ ? kFlagPeerClosed : 0;
 
   ports[0] = control_port_.name();
 
@@ -387,9 +398,9 @@
 
   {
     base::AutoLock lock(dispatcher->lock_);
-    dispatcher->peer_closed_ = state->peer_closed;
     dispatcher->write_offset_ = state->write_offset;
     dispatcher->available_capacity_ = state->available_capacity;
+    dispatcher->peer_closed_ = state->flags & kFlagPeerClosed;
     dispatcher->InitializeNoLock();
   }
 
diff --git a/mojo/edk/system/message_pipe_dispatcher.cc b/mojo/edk/system/message_pipe_dispatcher.cc
index ce35f64..c630b8b 100644
--- a/mojo/edk/system/message_pipe_dispatcher.cc
+++ b/mojo/edk/system/message_pipe_dispatcher.cc
@@ -14,15 +14,16 @@
 #include "mojo/edk/system/node_controller.h"
 #include "mojo/edk/system/ports_message.h"
 #include "mojo/edk/system/request_context.h"
-#include "mojo/public/c/system/macros.h"
 
 namespace mojo {
 namespace edk {
 
 namespace {
 
+#pragma pack(push, 1)
+
 // Header attached to every message sent over a message pipe.
-struct MOJO_ALIGNAS(8) MessageHeader {
+struct MessageHeader {
   // The number of serialized dispatchers included in this header.
   uint32_t num_dispatchers;
 
@@ -30,8 +31,10 @@
   uint32_t header_size;
 };
 
+static_assert(sizeof(MessageHeader) % 8 == 0, "Invalid MessageHeader size.");
+
 // Header for each dispatcher, immediately following the message header.
-struct MOJO_ALIGNAS(8) DispatcherHeader {
+struct DispatcherHeader {
   // The type of the dispatcher, correpsonding to the Dispatcher::Type enum.
   int32_t type;
 
@@ -45,11 +48,20 @@
   uint32_t num_platform_handles;
 };
 
-struct MOJO_ALIGNAS(8) SerializedState {
+static_assert(sizeof(DispatcherHeader) % 8 == 0,
+              "Invalid DispatcherHeader size.");
+
+struct SerializedState {
   uint64_t pipe_id;
   int8_t endpoint;
+  char padding[7];
 };
 
+static_assert(sizeof(SerializedState) % 8 == 0,
+              "Invalid SerializedState size.");
+
+#pragma pack(pop)
+
 }  // namespace
 
 // A PortObserver which forwards to a MessagePipeDispatcher. This owns a
@@ -503,6 +515,7 @@
   SerializedState* state = static_cast<SerializedState*>(destination);
   state->pipe_id = pipe_id_;
   state->endpoint = static_cast<int8_t>(endpoint_);
+  memset(state->padding, 0, sizeof(state->padding));
   ports[0] = port_.name();
   return true;
 }
diff --git a/mojo/edk/system/shared_buffer_dispatcher.cc b/mojo/edk/system/shared_buffer_dispatcher.cc
index 02ec902..4c548e0c 100644
--- a/mojo/edk/system/shared_buffer_dispatcher.cc
+++ b/mojo/edk/system/shared_buffer_dispatcher.cc
@@ -16,17 +16,23 @@
 #include "mojo/edk/system/configuration.h"
 #include "mojo/edk/system/node_controller.h"
 #include "mojo/edk/system/options_validation.h"
-#include "mojo/public/c/system/macros.h"
 
 namespace mojo {
 namespace edk {
 
 namespace {
 
-struct MOJO_ALIGNAS(8) SerializedSharedBufferDispatcher {
-  size_t num_bytes;
+#pragma pack(push, 1)
+
+struct SerializedState {
+  uint64_t num_bytes;
 };
 
+#pragma pack(pop)
+
+static_assert(sizeof(SerializedState) % 8 == 0,
+              "Invalid SerializedState size.");
+
 }  // namespace
 
 // static
@@ -108,13 +114,13 @@
     size_t num_ports,
     PlatformHandle* platform_handles,
     size_t num_platform_handles) {
-  if (num_bytes != sizeof(SerializedSharedBufferDispatcher)) {
+  if (num_bytes != sizeof(SerializedState)) {
     LOG(ERROR) << "Invalid serialized shared buffer dispatcher (bad size)";
     return nullptr;
   }
 
-  const SerializedSharedBufferDispatcher* serialization =
-      static_cast<const SerializedSharedBufferDispatcher*>(bytes);
+  const SerializedState* serialization =
+      static_cast<const SerializedState*>(bytes);
   if (!serialization->num_bytes) {
     LOG(ERROR)
         << "Invalid serialized shared buffer dispatcher (invalid num_bytes)";
@@ -137,7 +143,8 @@
   // closed even if creation fails.
   scoped_refptr<PlatformSharedBuffer> shared_buffer(
       PlatformSharedBuffer::CreateFromPlatformHandle(
-          serialization->num_bytes, ScopedPlatformHandle(platform_handle)));
+          static_cast<size_t>(serialization->num_bytes),
+          ScopedPlatformHandle(platform_handle)));
   if (!shared_buffer) {
     LOG(ERROR)
         << "Invalid serialized shared buffer dispatcher (invalid num_bytes?)";
@@ -217,7 +224,7 @@
 void SharedBufferDispatcher::StartSerialize(uint32_t* num_bytes,
                                             uint32_t* num_ports,
                                             uint32_t* num_platform_handles) {
-  *num_bytes = sizeof(SerializedSharedBufferDispatcher);
+  *num_bytes = sizeof(SerializedState);
   *num_ports = 0;
   *num_platform_handles = 1;
 }
@@ -225,10 +232,11 @@
 bool SharedBufferDispatcher::EndSerialize(void* destination,
                                           ports::PortName* ports,
                                           PlatformHandle* handles) {
-  SerializedSharedBufferDispatcher* serialization =
-      static_cast<SerializedSharedBufferDispatcher*>(destination);
+  SerializedState* serialization =
+      static_cast<SerializedState*>(destination);
   base::AutoLock lock(lock_);
-  serialization->num_bytes = shared_buffer_->GetNumBytes();
+  serialization->num_bytes =
+        static_cast<uint64_t>(shared_buffer_->GetNumBytes());
 
   handle_for_transit_ = shared_buffer_->DuplicatePlatformHandle();
   if (!handle_for_transit_.is_valid()) {
diff --git a/mojo/edk/test/mojo_test_base.h b/mojo/edk/test/mojo_test_base.h
index 71c9276..1dcadf1 100644
--- a/mojo/edk/test/mojo_test_base.h
+++ b/mojo/edk/test/mojo_test_base.h
@@ -188,14 +188,13 @@
   };                                                                        \
   MULTIPROCESS_TEST_MAIN_WITH_SETUP(                                        \
       client_name##TestChildMain,                                           \
-      test::MultiprocessTestHelper::ChildSetup) {                           \
-        client_name##_MainFixture test;                                     \
-        return test::MultiprocessTestHelper::RunClientMain(                 \
-            base::Bind(&client_name##_MainFixture::Main,                    \
-                       base::Unretained(&test)));                           \
-      }                                                                     \
-      int client_name##_MainFixture::Main(MojoHandle pipe_name)
-
+      ::mojo::edk::test::MultiprocessTestHelper::ChildSetup) {              \
+    client_name##_MainFixture test;                                         \
+    return ::mojo::edk::test::MultiprocessTestHelper::RunClientMain(        \
+        base::Bind(&client_name##_MainFixture::Main,                        \
+                   base::Unretained(&test)));                               \
+  }                                                                         \
+  int client_name##_MainFixture::Main(MojoHandle pipe_name)
 
 // This is a version of DEFINE_TEST_CLIENT_WITH_PIPE which can be used with
 // gtest ASSERT/EXPECT macros.
@@ -207,13 +206,13 @@
   };                                                                         \
   MULTIPROCESS_TEST_MAIN_WITH_SETUP(                                         \
       client_name##TestChildMain,                                            \
-      test::MultiprocessTestHelper::ChildSetup) {                            \
-        client_name##_MainFixture test;                                      \
-        return test::MultiprocessTestHelper::RunClientTestMain(              \
-            base::Bind(&client_name##_MainFixture::Main,                     \
-                       base::Unretained(&test)));                            \
-      }                                                                      \
-      void client_name##_MainFixture::Main(MojoHandle pipe_name)
+      ::mojo::edk::test::MultiprocessTestHelper::ChildSetup) {               \
+    client_name##_MainFixture test;                                          \
+    return ::mojo::edk::test::MultiprocessTestHelper::RunClientTestMain(     \
+        base::Bind(&client_name##_MainFixture::Main,                         \
+                   base::Unretained(&test)));                                \
+  }                                                                          \
+  void client_name##_MainFixture::Main(MojoHandle pipe_name)
 #else  // !defined(OS_IOS)
 #define DEFINE_TEST_CLIENT_WITH_PIPE(client_name, test_base, pipe_name)
 #define DEFINE_TEST_CLIENT_TEST_WITH_PIPE(client_name, test_base, pipe_name)
diff --git a/mojo/edk/test/scoped_ipc_support.cc b/mojo/edk/test/scoped_ipc_support.cc
index d7ff28b..7dc7c99b 100644
--- a/mojo/edk/test/scoped_ipc_support.cc
+++ b/mojo/edk/test/scoped_ipc_support.cc
@@ -13,6 +13,14 @@
 namespace edk {
 namespace test {
 
+namespace {
+base::TaskRunner* g_io_task_runner = nullptr;
+}
+
+base::TaskRunner* GetIoTaskRunner() {
+  return g_io_task_runner;
+}
+
 namespace internal {
 
 ScopedIPCSupportHelper::ScopedIPCSupportHelper() {
@@ -38,6 +46,7 @@
 
 ScopedIPCSupport::ScopedIPCSupport(
     scoped_refptr<base::TaskRunner> io_thread_task_runner) {
+  g_io_task_runner = io_thread_task_runner.get();
   helper_.Init(this, std::move(io_thread_task_runner));
 }
 
diff --git a/mojo/edk/test/scoped_ipc_support.h b/mojo/edk/test/scoped_ipc_support.h
index bb1f458..ff2f558 100644
--- a/mojo/edk/test/scoped_ipc_support.h
+++ b/mojo/edk/test/scoped_ipc_support.h
@@ -17,6 +17,8 @@
 namespace edk {
 namespace test {
 
+base::TaskRunner* GetIoTaskRunner();
+
 namespace internal {
 
 class ScopedIPCSupportHelper {
diff --git a/mojo/mojo_base.gyp b/mojo/mojo_base.gyp
index 532d44a..36c38cca 100644
--- a/mojo/mojo_base.gyp
+++ b/mojo/mojo_base.gyp
@@ -200,6 +200,7 @@
         'shell/public/cpp/connect.h',
         'shell/public/cpp/connection.h',
         'shell/public/cpp/connector.h',
+        'shell/public/cpp/identity.h',
         'shell/public/cpp/initialize_base_and_icu.cc',
         'shell/public/cpp/initialize_base_and_icu.h',
         'shell/public/cpp/interface_binder.h',
@@ -211,6 +212,7 @@
         'shell/public/cpp/lib/connection_impl.h',
         'shell/public/cpp/lib/connector_impl.cc',
         'shell/public/cpp/lib/connector_impl.h',
+        'shell/public/cpp/lib/identity.cc',
         'shell/public/cpp/lib/interface_factory_binder.h',
         'shell/public/cpp/lib/interface_registry.cc',
         'shell/public/cpp/lib/message_loop_ref.cc',
diff --git a/mojo/mojo_edk_tests.gyp b/mojo/mojo_edk_tests.gyp
index 0ace217..e2f92129 100644
--- a/mojo/mojo_edk_tests.gyp
+++ b/mojo/mojo_edk_tests.gyp
@@ -108,6 +108,7 @@
       'target_name': 'mojo_public_bindings_perftests',
       'type': 'executable',
       'dependencies': [
+        '../base/base.gyp:test_support_base',
         '../testing/gtest.gyp:gtest',
         'mojo_base.gyp:mojo_common_lib',
         'mojo_edk.gyp:mojo_run_all_perftests',
@@ -121,6 +122,7 @@
       ],
       'sources': [
         'public/cpp/bindings/tests/bindings_perftest.cc',
+        'public/cpp/bindings/tests/e2e_perftest.cc',
       ],
     },
     {
diff --git a/mojo/mojo_shell.gyp b/mojo/mojo_shell.gyp
index 7080eaa9..192c8ac5 100644
--- a/mojo/mojo_shell.gyp
+++ b/mojo/mojo_shell.gyp
@@ -16,8 +16,6 @@
       'shell/connect_params.h',
       'shell/connect_util.cc',
       'shell/connect_util.h',
-      'shell/identity.cc',
-      'shell/identity.h',
       'shell/native_runner.h',
       'shell/native_runner_delegate.h',
       'shell/shell.cc',
diff --git a/mojo/public/cpp/bindings/array.h b/mojo/public/cpp/bindings/array.h
index cb611c6..575ba77 100644
--- a/mojo/public/cpp/bindings/array.h
+++ b/mojo/public/cpp/bindings/array.h
@@ -88,6 +88,9 @@
   // Indicates whether the array is null (which is distinct from empty).
   bool is_null() const { return is_null_; }
 
+  // Indicates whether the array is empty (which is distinct from null).
+  bool empty() const { return vec_.empty() && !is_null_; }
+
   // Returns a reference to the first element of the array. Calling this on a
   // null or empty array causes undefined behavior.
   ConstRefType front() const { return vec_.front(); }
diff --git a/mojo/public/cpp/bindings/map.h b/mojo/public/cpp/bindings/map.h
index 4c64d48..6d0d57d 100644
--- a/mojo/public/cpp/bindings/map.h
+++ b/mojo/public/cpp/bindings/map.h
@@ -87,9 +87,14 @@
     return TypeConverter<U, Map>::Convert(*this);
   }
 
+  // Indicates whether the map is null (which is distinct from empty).
   bool is_null() const { return is_null_; }
 
-  // Indicates the number of keys in the map.
+  // Indicates whether the map is empty (which is distinct from null).
+  bool empty() const { return map_.empty() && !is_null_; }
+
+  // Indicates the number of keys in the map, which will be zero if the map is
+  // null.
   size_t size() const { return map_.size(); }
 
   // Inserts a key-value pair into the map. Like std::map, this does not insert
diff --git a/mojo/public/cpp/bindings/tests/BUILD.gn b/mojo/public/cpp/bindings/tests/BUILD.gn
index 78853674..5c661b4 100644
--- a/mojo/public/cpp/bindings/tests/BUILD.gn
+++ b/mojo/public/cpp/bindings/tests/BUILD.gn
@@ -74,9 +74,12 @@
 
   sources = [
     "bindings_perftest.cc",
+    "e2e_perftest.cc",
   ]
 
   deps = [
+    "//base/test:test_support",
+    "//mojo/edk/test:test_support",
     "//mojo/message_pump",
     "//mojo/public/cpp/bindings",
     "//mojo/public/cpp/bindings:callback",
diff --git a/mojo/public/cpp/bindings/tests/array_unittest.cc b/mojo/public/cpp/bindings/tests/array_unittest.cc
index c5a227e..f4dad7c 100644
--- a/mojo/public/cpp/bindings/tests/array_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/array_unittest.cc
@@ -26,6 +26,23 @@
 
 using ArrayTest = testing::Test;
 
+// Tests null and empty arrays.
+TEST_F(ArrayTest, NullAndEmpty) {
+  Array<char> array0;
+  EXPECT_TRUE(array0.empty());
+  EXPECT_FALSE(array0.is_null());
+  array0 = nullptr;
+  EXPECT_TRUE(array0.is_null());
+  EXPECT_FALSE(array0.empty());
+
+  Array<char> array1(nullptr);
+  EXPECT_TRUE(array1.is_null());
+  EXPECT_FALSE(array1.empty());
+  array1.SetToEmpty();
+  EXPECT_TRUE(array1.empty());
+  EXPECT_FALSE(array1.is_null());
+}
+
 // Tests that basic Array operations work.
 TEST_F(ArrayTest, Basic) {
   Array<char> array(8);
diff --git a/mojo/public/cpp/bindings/tests/e2e_perftest.cc b/mojo/public/cpp/bindings/tests/e2e_perftest.cc
new file mode 100644
index 0000000..cfa507b
--- /dev/null
+++ b/mojo/public/cpp/bindings/tests/e2e_perftest.cc
@@ -0,0 +1,196 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/perf_time_logger.h"
+#include "base/thread_task_runner_handle.h"
+#include "mojo/edk/test/mojo_test_base.h"
+#include "mojo/edk/test/scoped_ipc_support.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/interfaces/bindings/tests/ping_service.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace {
+
+class EchoServiceImpl : public test::EchoService {
+ public:
+  EchoServiceImpl(InterfaceRequest<EchoService> request,
+                  const base::Closure& quit_closure);
+  ~EchoServiceImpl() override;
+
+  // |EchoService| methods:
+  void Echo(const mojo::String& test_data,
+            const EchoCallback& callback) override;
+
+ private:
+  const StrongBinding<EchoService> binding_;
+  const base::Closure quit_closure_;
+};
+
+EchoServiceImpl::EchoServiceImpl(InterfaceRequest<EchoService> request,
+                                 const base::Closure& quit_closure)
+    : binding_(this, std::move(request)), quit_closure_(quit_closure) {}
+
+EchoServiceImpl::~EchoServiceImpl() {
+  quit_closure_.Run();
+}
+
+void EchoServiceImpl::Echo(const mojo::String& test_data,
+                           const EchoCallback& callback) {
+  callback.Run(test_data);
+}
+
+class PingPongTest {
+ public:
+  explicit PingPongTest(test::EchoServicePtr service);
+
+  void RunTest(int iterations, int batch_size, int message_size);
+
+ private:
+  void DoPing();
+  void OnPingDone(const mojo::String& reply);
+
+  test::EchoServicePtr service_;
+  const base::Callback<void(const mojo::String&)> ping_done_callback_;
+
+  int iterations_;
+  int batch_size_;
+  std::string message_;
+
+  int current_iterations_;
+  int calls_outstanding_;
+
+  base::Closure quit_closure_;
+};
+
+PingPongTest::PingPongTest(test::EchoServicePtr service)
+    : service_(std::move(service)),
+      ping_done_callback_(
+          base::Bind(&PingPongTest::OnPingDone, base::Unretained(this))) {}
+
+void PingPongTest::RunTest(int iterations, int batch_size, int message_size) {
+  iterations_ = iterations;
+  batch_size_ = batch_size;
+  message_ = std::string(message_size, 'a');
+  current_iterations_ = 0;
+  calls_outstanding_ = 0;
+
+  base::MessageLoop::current()->SetNestableTasksAllowed(true);
+  base::RunLoop run_loop;
+  quit_closure_ = run_loop.QuitClosure();
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&PingPongTest::DoPing, base::Unretained(this)));
+  run_loop.Run();
+}
+
+void PingPongTest::DoPing() {
+  DCHECK_EQ(0, calls_outstanding_);
+  current_iterations_++;
+  if (current_iterations_ > iterations_) {
+    quit_closure_.Run();
+    return;
+  }
+
+  calls_outstanding_ = batch_size_;
+  for (int i = 0; i < batch_size_; i++) {
+    service_->Echo(message_, ping_done_callback_);
+  }
+}
+
+void PingPongTest::OnPingDone(const mojo::String& reply) {
+  DCHECK_GT(calls_outstanding_, 0);
+  calls_outstanding_--;
+
+  if (!calls_outstanding_)
+    DoPing();
+}
+
+class MojoE2EPerftest : public edk::test::MojoTestBase {
+ public:
+  void RunTestOnTaskRunner(base::TaskRunner* runner,
+                           MojoHandle client_mp,
+                           const std::string& test_name) {
+    if (runner == base::ThreadTaskRunnerHandle::Get().get()) {
+      RunTests(client_mp, test_name);
+    } else {
+      base::RunLoop run_loop;
+      runner->PostTaskAndReply(
+          FROM_HERE, base::Bind(&MojoE2EPerftest::RunTests,
+                                base::Unretained(this), client_mp, test_name),
+          run_loop.QuitClosure());
+      run_loop.Run();
+    }
+  }
+
+ protected:
+  base::MessageLoop message_loop_;
+
+ private:
+  void RunTests(MojoHandle client_mp, const std::string& test_name) {
+    const int kMessages = 10000;
+    const int kBatchSizes[] = {1, 10, 100};
+    const int kMessageSizes[] = {8, 64, 512, 4096, 65536};
+
+    test::EchoServicePtr service;
+    service.Bind(InterfacePtrInfo<test::EchoService>(
+        ScopedMessagePipeHandle(MessagePipeHandle(client_mp)),
+        service.version()));
+    PingPongTest test(std::move(service));
+
+    for (int batch_size : kBatchSizes) {
+      for (int message_size : kMessageSizes) {
+        int num_messages = kMessages;
+        if (message_size == 65536)
+          num_messages /= 10;
+        std::string sub_test_name = base::StringPrintf(
+            "%s/%dx%d/%dbytes", test_name.c_str(), num_messages / batch_size,
+            batch_size, message_size);
+        base::PerfTimeLogger timer(sub_test_name.c_str());
+        test.RunTest(num_messages / batch_size, batch_size, message_size);
+      }
+    }
+  }
+};
+
+DEFINE_TEST_CLIENT_TEST_WITH_PIPE(PingService, MojoE2EPerftest, mp) {
+  MojoHandle service_mp;
+  EXPECT_EQ("hello", ReadMessageWithHandles(mp, &service_mp, 1));
+
+  InterfaceRequest<test::EchoService> request;
+  request.Bind(ScopedMessagePipeHandle(MessagePipeHandle(service_mp)));
+  base::RunLoop run_loop;
+  new EchoServiceImpl(std::move(request), run_loop.QuitClosure());
+  run_loop.Run();
+}
+
+TEST_F(MojoE2EPerftest, MultiProcessEchoMainThread) {
+  RUN_CHILD_ON_PIPE(PingService, mp)
+    MojoHandle client_mp, service_mp;
+    CreateMessagePipe(&client_mp, &service_mp);
+    WriteMessageWithHandles(mp, "hello", &service_mp, 1);
+    RunTestOnTaskRunner(message_loop_.task_runner().get(), client_mp,
+                        "MultiProcessEchoMainThread");
+  END_CHILD()
+}
+
+TEST_F(MojoE2EPerftest, MultiProcessEchoIoThread) {
+  RUN_CHILD_ON_PIPE(PingService, mp)
+    MojoHandle client_mp, service_mp;
+    CreateMessagePipe(&client_mp, &service_mp);
+    WriteMessageWithHandles(mp, "hello", &service_mp, 1);
+    RunTestOnTaskRunner(edk::test::GetIoTaskRunner(), client_mp,
+                        "MultiProcessEchoIoThread");
+  END_CHILD()
+}
+
+}  // namespace
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/tests/map_unittest.cc b/mojo/public/cpp/bindings/tests/map_unittest.cc
index 4ccd8c0e..e4d2bee 100644
--- a/mojo/public/cpp/bindings/tests/map_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/map_unittest.cc
@@ -42,6 +42,23 @@
 
 using MapTest = testing::Test;
 
+// Tests null and empty maps.
+TEST_F(MapTest, NullAndEmpty) {
+  Map<char, char> map0;
+  EXPECT_TRUE(map0.empty());
+  EXPECT_FALSE(map0.is_null());
+  map0 = nullptr;
+  EXPECT_TRUE(map0.is_null());
+  EXPECT_FALSE(map0.empty());
+
+  Map<char, char> map1(nullptr);
+  EXPECT_TRUE(map1.is_null());
+  EXPECT_FALSE(map1.empty());
+  map1.SetToEmpty();
+  EXPECT_TRUE(map1.empty());
+  EXPECT_FALSE(map1.is_null());
+}
+
 // Tests that basic Map operations work.
 TEST_F(MapTest, InsertWorks) {
   Map<String, int> map;
diff --git a/mojo/public/interfaces/bindings/tests/ping_service.mojom b/mojo/public/interfaces/bindings/tests/ping_service.mojom
index 3e1f1c4..ba6ad3d 100644
--- a/mojo/public/interfaces/bindings/tests/ping_service.mojom
+++ b/mojo/public/interfaces/bindings/tests/ping_service.mojom
@@ -8,3 +8,7 @@
 interface PingService {
   Ping() => ();
 };
+
+interface EchoService {
+  Echo(string test_data) => (string echo_data);
+};
diff --git a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
index 22e089c..c2d3a1c3 100644
--- a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
+++ b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
@@ -105,6 +105,9 @@
   return hasattr(kind, "name") and \
       GetFullMojomNameForKind(kind) in _current_typemap
 
+def IsCloneableKind(kind):
+  return mojom.IsCloneableKind(kind, IsTypemappedKind)
+
 def IsNativeOnlyKind(kind):
   return mojom.IsStructKind(kind) and kind.native_only
 
@@ -477,7 +480,7 @@
     "should_inline": ShouldInlineStruct,
     "should_inline_union": ShouldInlineUnion,
     "is_array_kind": mojom.IsArrayKind,
-    "is_cloneable_kind": mojom.IsCloneableKind,
+    "is_cloneable_kind": IsCloneableKind,
     "is_enum_kind": mojom.IsEnumKind,
     "is_integral_kind": mojom.IsIntegralKind,
     "is_move_only_kind": mojom.IsMoveOnlyKind,
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/module.py b/mojo/public/tools/bindings/pylib/mojom/generate/module.py
index 6a86f167..a673d8e 100644
--- a/mojo/public/tools/bindings/pylib/mojom/generate/module.py
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/module.py
@@ -607,7 +607,7 @@
       IsAnyHandleKind(kind) or IsInterfaceKind(kind) or IsAssociatedKind(kind)
 
 
-def IsCloneableKind(kind):
+def IsCloneableKind(kind, filter):
   def _IsCloneable(kind, visited_kinds):
     if kind in visited_kinds:
       # No need to examine the kind again.
@@ -618,7 +618,7 @@
     if IsArrayKind(kind):
       return _IsCloneable(kind.kind, visited_kinds)
     if IsStructKind(kind) or IsUnionKind(kind):
-      if IsStructKind(kind) and kind.native_only:
+      if IsStructKind(kind) and (kind.native_only or filter(kind)):
         return False
       for field in kind.fields:
         if not _IsCloneable(field.kind, visited_kinds):
diff --git a/mojo/services/network/network_service_delegate.cc b/mojo/services/network/network_service_delegate.cc
index aadc5cac..b257331 100644
--- a/mojo/services/network/network_service_delegate.cc
+++ b/mojo/services/network/network_service_delegate.cc
@@ -48,8 +48,7 @@
 }
 
 void NetworkServiceDelegate::Initialize(Connector* connector,
-                                        const std::string& name,
-                                        const std::string& user_id,
+                                        const Identity& identity,
                                         uint32_t id) {
   // TODO(erg): Find everything else that writes to the filesystem and
   // transition it to proxying mojo:filesystem. We shouldn't have any path
@@ -67,7 +66,7 @@
   }
 
   context_.reset(new NetworkContext(base_path, this));
-  tracing_.Initialize(connector, name);
+  tracing_.Initialize(connector, identity.name());
 }
 
 bool NetworkServiceDelegate::AcceptConnection(Connection* connection) {
diff --git a/mojo/services/network/network_service_delegate.h b/mojo/services/network/network_service_delegate.h
index 07e93b5..70989395 100644
--- a/mojo/services/network/network_service_delegate.h
+++ b/mojo/services/network/network_service_delegate.h
@@ -35,8 +35,8 @@
 
  private:
   // mojo::ShellClient implementation.
-  void Initialize(Connector* connector, const std::string& url,
-                  const std::string& user_id, uint32_t id) override;
+  void Initialize(Connector* connector, const Identity& identity,
+                  uint32_t id) override;
   bool AcceptConnection(Connection* connection) override;
 
   // InterfaceFactory<NetworkService> implementation.
diff --git a/mojo/services/package_manager/package_manager.cc b/mojo/services/package_manager/package_manager.cc
index 00d59c01..858cf9d 100644
--- a/mojo/services/package_manager/package_manager.cc
+++ b/mojo/services/package_manager/package_manager.cc
@@ -119,7 +119,7 @@
 bool PackageManager::AcceptConnection(mojo::Connection* connection) {
   connection->AddInterface<mojom::Catalog>(this);
   connection->AddInterface<mojom::Resolver>(this);
-  if (connection->GetRemoteApplicationName() == "mojo:shell")
+  if (connection->GetRemoteIdentity().name() == "mojo:shell")
     connection->AddInterface<mojom::ShellResolver>(this);
   return true;
 }
diff --git a/mojo/shell/BUILD.gn b/mojo/shell/BUILD.gn
index 51c6c215..504372acb 100644
--- a/mojo/shell/BUILD.gn
+++ b/mojo/shell/BUILD.gn
@@ -24,8 +24,6 @@
     "connect_params.h",
     "connect_util.cc",
     "connect_util.h",
-    "identity.cc",
-    "identity.h",
     "loader.h",
     "native_runner.h",
     "native_runner_delegate.h",
diff --git a/mojo/shell/background/background_shell.cc b/mojo/shell/background/background_shell.cc
index 1d31de7..24ec075 100644
--- a/mojo/shell/background/background_shell.cc
+++ b/mojo/shell/background/background_shell.cc
@@ -178,7 +178,8 @@
 mojom::ShellClientRequest BackgroundShell::CreateShellClientRequest(
     const std::string& name) {
   scoped_ptr<ConnectParams> params(new ConnectParams);
-  params->set_target(Identity(name, std::string(), mojom::kRootUserID));
+  params->set_source(CreateShellIdentity());
+  params->set_target(Identity(name, mojom::kRootUserID));
   mojom::ShellClientRequest request;
   base::WaitableEvent signal(true, false);
   thread_->message_loop()->task_runner()->PostTask(
diff --git a/mojo/shell/connect_params.h b/mojo/shell/connect_params.h
index b90ac32..3b28a50 100644
--- a/mojo/shell/connect_params.h
+++ b/mojo/shell/connect_params.h
@@ -11,7 +11,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
-#include "mojo/shell/identity.h"
+#include "mojo/shell/public/cpp/identity.h"
 #include "mojo/shell/public/interfaces/connector.mojom.h"
 #include "mojo/shell/public/interfaces/interface_provider.mojom.h"
 
@@ -22,8 +22,8 @@
 // application.
 class ConnectParams {
  public:
-   ConnectParams();
-   ~ConnectParams();
+  ConnectParams();
+  ~ConnectParams();
 
   void set_source(const Identity& source) { source_ = source;  }
   const Identity& source() const { return source_; }
diff --git a/mojo/shell/connect_util.h b/mojo/shell/connect_util.h
index 87df3d81..d7f629c 100644
--- a/mojo/shell/connect_util.h
+++ b/mojo/shell/connect_util.h
@@ -7,7 +7,7 @@
 
 #include "mojo/public/cpp/bindings/interface_ptr.h"
 #include "mojo/public/cpp/system/handle.h"
-#include "mojo/shell/identity.h"
+#include "mojo/shell/public/cpp/identity.h"
 #include "mojo/shell/public/interfaces/connector.mojom.h"
 
 namespace mojo {
@@ -39,7 +39,7 @@
                                const std::string& name,
                                InterfacePtr<Interface>* ptr) {
   ScopedMessagePipeHandle service_handle = ConnectToInterfaceByName(
-      shell, source, Identity(name, std::string(), mojom::kInheritUserID),
+      shell, source, Identity(name, mojom::kInheritUserID),
       Interface::Name_);
   ptr->Bind(InterfacePtrInfo<Interface>(std::move(service_handle), 0u));
 }
diff --git a/mojo/shell/identity.cc b/mojo/shell/identity.cc
deleted file mode 100644
index 243565a..0000000
--- a/mojo/shell/identity.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/shell/identity.h"
-
-#include "mojo/shell/public/cpp/names.h"
-#include "mojo/shell/public/interfaces/connector.mojom.h"
-
-namespace mojo {
-namespace shell {
-
-Identity::Identity() {}
-
-Identity::Identity(const std::string& name)
-    : Identity(name, GetNamePath(name), mojom::kRootUserID) {}
-
-Identity::Identity(const std::string& name, const std::string& qualifier,
-                   const std::string& user_id)
-    : name_(name),
-      qualifier_(qualifier.empty() ? GetNamePath(name_) : qualifier),
-      user_id_(user_id) {}
-
-Identity::Identity(const Identity& other) = default;
-
-Identity::~Identity() {}
-
-bool Identity::operator<(const Identity& other) const {
-  // We specifically don't include filter in the equivalence check because we
-  // don't quite know how this should work yet.
-  // TODO(beng): figure out how it should work.
-  if (name_ != other.name_)
-    return name_ < other.name_;
-  if (qualifier_ != other.qualifier_)
-    return qualifier_ < other.qualifier_;
-  return user_id_ < other.user_id_;
-}
-
-bool Identity::operator==(const Identity& other) const {
-  // We specifically don't include filter in the equivalence check because we
-  // don't quite know how this should work yet.
-  // TODO(beng): figure out how it should work.
-  return other.name_ == name_ && other.qualifier_ == qualifier_ &&
-         other.user_id_ == user_id_;
-}
-
-Identity CreateShellIdentity() {
-  Identity id = Identity("mojo:shell", "", mojom::kRootUserID);
-  id.set_filter(GetPermissiveCapabilityFilter());
-  return id;
-}
-
-CapabilityFilter GetPermissiveCapabilityFilter() {
-  CapabilityFilter filter;
-  AllowedInterfaces interfaces;
-  interfaces.insert("*");
-  filter["*"] = interfaces;
-  return filter;
-}
-
-AllowedInterfaces GetAllowedInterfaces(const CapabilityFilter& filter,
-                                       const Identity& identity) {
-  // Start by looking for interfaces specific to the supplied identity.
-  auto it = filter.find(identity.name());
-  if (it != filter.end())
-    return it->second;
-
-  // Fall back to looking for a wildcard rule.
-  it = filter.find("*");
-  if (filter.size() == 1 && it != filter.end())
-    return it->second;
-
-  // Finally, nothing is allowed.
-  return AllowedInterfaces();
-}
-
-}  // namespace shell
-}  // namespace mojo
diff --git a/mojo/shell/identity.h b/mojo/shell/identity.h
deleted file mode 100644
index 7d33295d..0000000
--- a/mojo/shell/identity.h
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_SHELL_IDENTITY_H_
-#define MOJO_SHELL_IDENTITY_H_
-
-#include <stdint.h>
-
-#include <map>
-#include <set>
-#include <string>
-
-namespace mojo {
-namespace shell {
-
-// A set of names of interfaces that may be exposed to an application.
-using AllowedInterfaces = std::set<std::string>;
-// A map of allowed applications to allowed interface sets. See shell.mojom for
-// more details.
-using CapabilityFilter = std::map<std::string, AllowedInterfaces>;
-
-// Represents the identity of an application.
-// |name| is the structured name of the application.
-// |qualifier| is a string that allows to tie a specific instance of an
-// application to another. A typical use case of qualifier is to control process
-// grouping for a given application name. For example, the core services are
-// grouped into "Core"/"Files"/"Network"/etc. using qualifier; content handler's
-// qualifier is derived from the origin of the content.
-class Identity {
- public:
-  Identity();
-  // Assumes user = mojom::kRootUserID.
-  // Used in tests or for shell-initiated connections.
-  explicit Identity(const std::string& in_name);
-  Identity(const std::string& in_name,
-           const std::string& in_qualifier,
-           const std::string& user_id);
-  Identity(const Identity& other);
-  ~Identity();
-
-  bool operator<(const Identity& other) const;
-  bool is_null() const { return name_.empty(); }
-  bool operator==(const Identity& other) const;
-
-  const std::string& name() const { return name_; }
-  const std::string& user_id() const { return user_id_; }
-  void set_user_id(const std::string& user_id) { user_id_ = user_id; }
-  const std::string& qualifier() const { return qualifier_; }
-  void set_filter(const CapabilityFilter& filter) { filter_ = filter; }
-  const CapabilityFilter& filter() const { return filter_; }
-
- private:
-  std::string name_;
-  std::string qualifier_;
-
-  std::string user_id_;
-
-  // TODO(beng): CapabilityFilter is not currently included in equivalence
-  //             checks for Identity since we're not currently clear on the
-  //             policy for instance disambiguation. Need to figure this out.
-  //             This field is supplied because it is logically part of the
-  //             instance identity of an application.
-  CapabilityFilter filter_;
-};
-
-// Creates an identity for the Shell, used when the Shell connects to
-// applications.
-Identity CreateShellIdentity();
-
-// Returns a capability filter that allows an application to connect to any
-// other application and any service exposed by other applications.
-CapabilityFilter GetPermissiveCapabilityFilter();
-
-// Returns the set of interfaces that an application instance with |filter| is
-// allowed to see from an instance with |identity|.
-AllowedInterfaces GetAllowedInterfaces(const CapabilityFilter& filter,
-                                       const Identity& identity);
-
-}  // namespace shell
-}  // namespace mojo
-
-#endif  // MOJO_SHELL_IDENTITY_H_
diff --git a/mojo/shell/native_runner.h b/mojo/shell/native_runner.h
index ce14f11..92c1adc 100644
--- a/mojo/shell/native_runner.h
+++ b/mojo/shell/native_runner.h
@@ -17,9 +17,9 @@
 }
 
 namespace mojo {
+class Identity;
 namespace shell {
 
-class Identity;
 
 // Shell requires implementations of NativeRunner and NativeRunnerFactory to run
 // native applications.
diff --git a/mojo/shell/native_runner_delegate.h b/mojo/shell/native_runner_delegate.h
index d2fe826..b732ec60 100644
--- a/mojo/shell/native_runner_delegate.h
+++ b/mojo/shell/native_runner_delegate.h
@@ -10,9 +10,8 @@
 }
 
 namespace mojo {
-namespace shell {
-
 class Identity;
+namespace shell {
 
 class NativeRunnerDelegate {
  public:
diff --git a/mojo/shell/public/cpp/BUILD.gn b/mojo/shell/public/cpp/BUILD.gn
index 576704c..e2cfbc8e 100644
--- a/mojo/shell/public/cpp/BUILD.gn
+++ b/mojo/shell/public/cpp/BUILD.gn
@@ -24,6 +24,7 @@
     "connect.h",
     "connection.h",
     "connector.h",
+    "identity.h",
     "initialize_base_and_icu.cc",
     "interface_binder.h",
     "interface_factory.h",
@@ -34,6 +35,7 @@
     "lib/connection_impl.h",
     "lib/connector_impl.cc",
     "lib/connector_impl.h",
+    "lib/identity.cc",
     "lib/interface_factory_binder.h",
     "lib/interface_registry.cc",
     "lib/message_loop_ref.cc",
diff --git a/mojo/shell/public/cpp/connection.h b/mojo/shell/public/cpp/connection.h
index ce1401c8..d3b3b8a 100644
--- a/mojo/shell/public/cpp/connection.h
+++ b/mojo/shell/public/cpp/connection.h
@@ -12,6 +12,7 @@
 
 #include "base/memory/weak_ptr.h"
 #include "mojo/shell/public/cpp/connect.h"
+#include "mojo/shell/public/cpp/identity.h"
 #include "mojo/shell/public/cpp/interface_registry.h"
 #include "mojo/shell/public/interfaces/connector.mojom.h"
 #include "mojo/shell/public/interfaces/interface_provider.mojom.h"
@@ -88,14 +89,12 @@
   // same as the value returned by GetRemoveApplicationName().
   virtual const std::string& GetConnectionName() = 0;
 
-  // Returns the name identifying the remote application on this connection.
-  virtual const std::string& GetRemoteApplicationName() = 0;
-
-  // Returns the User ID for the remote application. Prior to the Connect()
-  // callback being fired, this will return the value passed via Connect().
-  // After the Connect() callback (call AddRemoteIDCallback to register one)
-  // this will return the actual user id the shell ran the target as.
-  virtual const std::string& GetRemoteUserID() const = 0;
+  // Returns the remote identity. While the connection is in the pending state,
+  // the user_id() field will be the value passed via Connect(). After the
+  // connection is completed, it will change to the value assigned by the shell.
+  // Call AddConnectionCompletedClosure() to schedule a closure to be run when
+  // the resolved user id is available.
+  virtual const Identity& GetRemoteIdentity() const = 0;
 
   // Register a handler to receive an error notification on the pipe to the
   // remote application's InterfaceProvider.
diff --git a/mojo/shell/public/cpp/connector.h b/mojo/shell/public/cpp/connector.h
index 94fdc9a..be6ba43 100644
--- a/mojo/shell/public/cpp/connector.h
+++ b/mojo/shell/public/cpp/connector.h
@@ -6,6 +6,7 @@
 #define MOJO_SHELL_PUBLIC_CPP_CONNECTOR_H_
 
 #include "mojo/shell/public/cpp/connection.h"
+#include "mojo/shell/public/cpp/identity.h"
 #include "mojo/shell/public/interfaces/connector.mojom.h"
 
 namespace mojo {
@@ -30,16 +31,15 @@
 
   class ConnectParams {
    public:
+    explicit ConnectParams(const Identity& target);
     explicit ConnectParams(const std::string& name);
     ~ConnectParams();
 
-    const std::string& name() { return name_; }
-    void set_user_id(const std::string& user_id) { user_id_ = user_id; }
-    const std::string& user_id() const { return user_id_; }
+    const Identity& target() { return target_; }
+    void set_target(const Identity& target) { target_ = target; }
 
    private:
-    std::string name_;
-    std::string user_id_;
+    Identity target_;
 
     DISALLOW_COPY_AND_ASSIGN(ConnectParams);
   };
diff --git a/mojo/shell/public/cpp/identity.h b/mojo/shell/public/cpp/identity.h
new file mode 100644
index 0000000..90f4608
--- /dev/null
+++ b/mojo/shell/public/cpp/identity.h
@@ -0,0 +1,55 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_SHELL_PUBLIC_CPP_IDENTITY_H_
+#define MOJO_SHELL_PUBLIC_CPP_IDENTITY_H_
+
+#include <string>
+
+#include "mojo/shell/public/interfaces/connector.mojom.h"
+
+namespace mojo {
+
+// Represents the identity of an application.
+// |name| is the structured name of the application.
+// |instance| is a string that allows to tie a specific instance to another. A
+// typical use case of instance is to control process grouping for a given name.
+class Identity {
+ public:
+  Identity();
+  Identity(const std::string& name,
+           const std::string& user_id);
+  Identity(const std::string& name,
+           const std::string& user_id,
+           const std::string& instance);
+  Identity(const Identity& other);
+  ~Identity();
+
+  bool operator<(const Identity& other) const;
+  bool is_null() const { return name_.empty(); }
+  bool operator==(const Identity& other) const;
+
+  const std::string& name() const { return name_; }
+  const std::string& user_id() const { return user_id_; }
+  void set_user_id(const std::string& user_id) { user_id_ = user_id; }
+  const std::string& instance() const { return instance_; }
+
+ private:
+  std::string name_;
+  std::string user_id_;
+  std::string instance_;
+};
+
+template <>
+struct TypeConverter<shell::mojom::IdentityPtr, Identity> {
+  static shell::mojom::IdentityPtr Convert(const Identity& input);
+};
+template <>
+struct TypeConverter<Identity, shell::mojom::IdentityPtr> {
+  static Identity Convert(const shell::mojom::IdentityPtr& input);
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_SHELL_PUBLIC_CPP_IDENTITY_H_
diff --git a/mojo/shell/public/cpp/lib/application_test_base.cc b/mojo/shell/public/cpp/lib/application_test_base.cc
index 7f8f684..e2e5826 100644
--- a/mojo/shell/public/cpp/lib/application_test_base.cc
+++ b/mojo/shell/public/cpp/lib/application_test_base.cc
@@ -19,9 +19,8 @@
 
 namespace {
 // Share the application name with multiple application tests.
-String g_name;
+shell::mojom::IdentityPtr g_identity;
 uint32_t g_id = shell::mojom::kInvalidInstanceID;
-String g_user_id = shell::mojom::kRootUserID;
 
 // ShellClient request handle passed from the shell in MojoMain, stored in
 // between SetUp()/TearDown() so we can (re-)intialize new ShellConnections.
@@ -45,20 +44,17 @@
  private:
   // shell::mojom::ShellClient implementation.
   void Initialize(shell::mojom::ConnectorPtr connector,
-                  const String& name,
-                  const String& user_id,
+                  shell::mojom::IdentityPtr identity,
                   uint32_t id) override {
-    g_name = name;
+    g_identity = std::move(identity);
     g_id = id;
-    g_user_id = user_id;
     g_shell_client_request = binding_.Unbind();
     g_connector = std::move(connector);
   }
 
   void AcceptConnection(
-      const String& requestor_name,
-      const String& requestor_user_id,
-      uint32_t requestor_id,
+      shell::mojom::IdentityPtr source,
+      uint32_t source_id,
       shell::mojom::InterfaceProviderRequest local_interfaces,
       shell::mojom::InterfaceProviderPtr remote_interfaces,
       Array<String> allowed_interfaces,
@@ -118,12 +114,12 @@
     : shell_connection_(new ShellConnection(
           client == nullptr ? &default_shell_client_ : client,
           std::move(g_shell_client_request))),
-      name_(g_name),
-      userid_(g_user_id),
+      name_(g_identity->name),
+      userid_(g_identity->user_id),
       instance_id_(g_id) {
   // Fake ShellClient initialization.
   shell::mojom::ShellClient* shell_client = shell_connection_.get();
-  shell_client->Initialize(std::move(g_connector), g_name, g_user_id, g_id);
+  shell_client->Initialize(std::move(g_connector), std::move(g_identity), g_id);
 }
 
 TestHelper::~TestHelper() {
diff --git a/mojo/shell/public/cpp/lib/connection_impl.cc b/mojo/shell/public/cpp/lib/connection_impl.cc
index 3541f55..d3585e7 100644
--- a/mojo/shell/public/cpp/lib/connection_impl.cc
+++ b/mojo/shell/public/cpp/lib/connection_impl.cc
@@ -21,18 +21,16 @@
 
 ConnectionImpl::ConnectionImpl(
     const std::string& connection_name,
-    const std::string& remote_name,
+    const Identity& remote,
     uint32_t remote_id,
-    const std::string& remote_user_id,
     shell::mojom::InterfaceProviderPtr remote_interfaces,
     shell::mojom::InterfaceProviderRequest local_interfaces,
     const std::set<std::string>& allowed_interfaces,
     State initial_state)
     : connection_name_(connection_name),
-      remote_name_(remote_name),
-      state_(initial_state),
+      remote_(remote),
       remote_id_(remote_id),
-      remote_user_id_(remote_user_id),
+      state_(initial_state),
       local_registry_(std::move(local_interfaces), this),
       remote_interfaces_(std::move(remote_interfaces)),
       allowed_interfaces_(allowed_interfaces),
@@ -59,12 +57,8 @@
   return connection_name_;
 }
 
-const std::string& ConnectionImpl::GetRemoteApplicationName() {
-  return remote_name_;
-}
-
-const std::string& ConnectionImpl::GetRemoteUserID() const {
-  return remote_user_id_;
+const Identity& ConnectionImpl::GetRemoteIdentity() const {
+  return remote_;
 }
 
 void ConnectionImpl::SetConnectionLostClosure(const Closure& handler) {
@@ -118,7 +112,7 @@
   state_ = result_ == shell::mojom::ConnectResult::SUCCEEDED ?
       State::CONNECTED : State::DISCONNECTED;
   remote_id_ = target_application_id;
-  remote_user_id_= target_user_id;
+  remote_.set_user_id(target_user_id);
   std::vector<Closure> callbacks;
   callbacks.swap(connection_completed_callbacks_);
   for (auto callback : callbacks)
diff --git a/mojo/shell/public/cpp/lib/connection_impl.h b/mojo/shell/public/cpp/lib/connection_impl.h
index e0a03d4d..3247a5a 100644
--- a/mojo/shell/public/cpp/lib/connection_impl.h
+++ b/mojo/shell/public/cpp/lib/connection_impl.h
@@ -12,6 +12,7 @@
 
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/shell/public/cpp/connection.h"
+#include "mojo/shell/public/cpp/identity.h"
 #include "mojo/shell/public/interfaces/connector.mojom.h"
 #include "mojo/shell/public/interfaces/interface_provider.mojom.h"
 
@@ -28,9 +29,8 @@
   // an application to expose to another application. If this set contains only
   // the string value "*" all interfaces may be exposed.
   ConnectionImpl(const std::string& connection_name,
-                 const std::string& remote_name,
+                 const Identity& remote,
                  uint32_t remote_id,
-                 const std::string& remote_user_id,
                  shell::mojom::InterfaceProviderPtr remote_interfaces,
                  shell::mojom::InterfaceProviderRequest local_interfaces,
                  const std::set<std::string>& allowed_interfaces,
@@ -42,8 +42,7 @@
  private:
   // Connection:
   const std::string& GetConnectionName() override;
-  const std::string& GetRemoteApplicationName() override;
-  const std::string& GetRemoteUserID() const override;
+  const Identity& GetRemoteIdentity() const override;
   void SetConnectionLostClosure(const Closure& handler) override;
   shell::mojom::ConnectResult GetResult() const override;
   bool IsPending() const override;
@@ -59,13 +58,12 @@
                              uint32_t target_application_id);
 
   const std::string connection_name_;
-  const std::string remote_name_;
+  Identity remote_;
+  uint32_t remote_id_ = shell::mojom::kInvalidInstanceID;
 
   State state_;
   shell::mojom::ConnectResult result_ = shell::mojom::ConnectResult::SUCCEEDED;
-  uint32_t remote_id_ = shell::mojom::kInvalidInstanceID;
   std::vector<Closure> connection_completed_callbacks_;
-  std::string remote_user_id_ = shell::mojom::kInheritUserID;
 
   InterfaceRegistry local_registry_;
   shell::mojom::InterfaceProviderPtr remote_interfaces_;
diff --git a/mojo/shell/public/cpp/lib/connector_impl.cc b/mojo/shell/public/cpp/lib/connector_impl.cc
index 9adeebd..cc12dbb0 100644
--- a/mojo/shell/public/cpp/lib/connector_impl.cc
+++ b/mojo/shell/public/cpp/lib/connector_impl.cc
@@ -4,14 +4,15 @@
 
 #include "mojo/shell/public/cpp/lib/connector_impl.h"
 
+#include "mojo/shell/public/cpp/identity.h"
 #include "mojo/shell/public/cpp/lib/connection_impl.h"
 
 namespace mojo {
 
+Connector::ConnectParams::ConnectParams(const Identity& target)
+    : target_(target) {}
 Connector::ConnectParams::ConnectParams(const std::string& name)
-    : name_(name),
-      user_id_(shell::mojom::kInheritUserID) {
-}
+    : target_(name, shell::mojom::kInheritUserID) {}
 Connector::ConnectParams::~ConnectParams() {}
 
 ConnectorImpl::ConnectorImpl(shell::mojom::ConnectorPtrInfo unbound_state)
@@ -43,7 +44,6 @@
   DCHECK(thread_checker_->CalledOnValidThread());
 
   DCHECK(params);
-  std::string application_name = params->name();
   // We allow all interfaces on outgoing connections since we are presumably in
   // a position to know who we're talking to.
   // TODO(beng): We should filter outgoing interfaces also. The shell must pass
@@ -58,14 +58,13 @@
   shell::mojom::InterfaceProviderRequest remote_request =
       GetProxy(&remote_interfaces);
   scoped_ptr<internal::ConnectionImpl> registry(new internal::ConnectionImpl(
-      application_name, application_name, shell::mojom::kInvalidInstanceID,
-      params->user_id(), std::move(remote_interfaces), std::move(local_request),
-      allowed, Connection::State::PENDING));
-  connector_->Connect(application_name,
-                      params->user_id(),
-                      std::move(remote_request),
-                      std::move(local_interfaces),
-                      registry->GetConnectCallback());
+      params->target().name(), params->target(),
+      shell::mojom::kInvalidInstanceID, std::move(remote_interfaces),
+      std::move(local_request), allowed, Connection::State::PENDING));
+  connector_->Connect(
+      shell::mojom::Identity::From(params->target()),
+      std::move(remote_request), std::move(local_interfaces),
+      registry->GetConnectCallback());
   return std::move(registry);
 }
 
diff --git a/mojo/shell/public/cpp/lib/identity.cc b/mojo/shell/public/cpp/lib/identity.cc
new file mode 100644
index 0000000..85860a0
--- /dev/null
+++ b/mojo/shell/public/cpp/lib/identity.cc
@@ -0,0 +1,60 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mojo/shell/public/cpp/identity.h"
+
+#include "base/guid.h"
+#include "mojo/shell/public/cpp/names.h"
+
+namespace mojo {
+
+Identity::Identity() {}
+
+Identity::Identity(const std::string& name, const std::string& user_id)
+    : Identity(name, user_id, "") {}
+
+Identity::Identity(const std::string& name, const std::string& user_id,
+                   const std::string& instance)
+    : name_(name),
+      user_id_(user_id),
+      instance_(instance.empty() ? GetNamePath(name_) : instance) {
+  CHECK(!user_id.empty());
+  CHECK(base::IsValidGUID(user_id));
+}
+
+Identity::Identity(const Identity& other) = default;
+
+Identity::~Identity() {}
+
+bool Identity::operator<(const Identity& other) const {
+  if (name_ != other.name_)
+    return name_ < other.name_;
+  if (instance_ != other.instance_)
+    return instance_ < other.instance_;
+  return user_id_ < other.user_id_;
+}
+
+bool Identity::operator==(const Identity& other) const {
+  return other.name_ == name_ && other.instance_ == instance_ &&
+         other.user_id_ == user_id_;
+}
+
+// static
+shell::mojom::IdentityPtr
+    TypeConverter<shell::mojom::IdentityPtr, Identity>::Convert(
+        const Identity& input) {
+  shell::mojom::IdentityPtr identity(shell::mojom::Identity::New());
+  identity->name = input.name();
+  identity->user_id = input.user_id();
+  identity->instance = input.instance();
+  return identity;
+}
+
+// static
+Identity TypeConverter<Identity, shell::mojom::IdentityPtr>::Convert(
+    const shell::mojom::IdentityPtr& input) {
+  return Identity(input->name, input->user_id, input->instance);
+}
+
+}  // namespace mojo
diff --git a/mojo/shell/public/cpp/lib/interface_registry.cc b/mojo/shell/public/cpp/lib/interface_registry.cc
index 9333207..c8f9703b 100644
--- a/mojo/shell/public/cpp/lib/interface_registry.cc
+++ b/mojo/shell/public/cpp/lib/interface_registry.cc
@@ -53,7 +53,7 @@
   LOG(WARNING) << "Connection CapabilityFilter prevented binding to interface: "
                << interface_name << " connection_name:"
                << connection_->GetConnectionName() << " remote_name:"
-               << connection_->GetRemoteApplicationName();
+               << connection_->GetRemoteIdentity().name();
   return false;
 }
 
diff --git a/mojo/shell/public/cpp/lib/shell_client.cc b/mojo/shell/public/cpp/lib/shell_client.cc
index f5441ce1..c41999b 100644
--- a/mojo/shell/public/cpp/lib/shell_client.cc
+++ b/mojo/shell/public/cpp/lib/shell_client.cc
@@ -9,8 +9,8 @@
 ShellClient::ShellClient() {}
 ShellClient::~ShellClient() {}
 
-void ShellClient::Initialize(Connector* connector, const std::string& name,
-                             const std::string& user_id, uint32_t id) {
+void ShellClient::Initialize(Connector* connector, const Identity& identity,
+                             uint32_t id) {
 }
 
 bool ShellClient::AcceptConnection(Connection* connection) {
diff --git a/mojo/shell/public/cpp/lib/shell_connection.cc b/mojo/shell/public/cpp/lib/shell_connection.cc
index 0abac7e..8ee729d0 100644
--- a/mojo/shell/public/cpp/lib/shell_connection.cc
+++ b/mojo/shell/public/cpp/lib/shell_connection.cc
@@ -35,27 +35,25 @@
 // ShellConnection, shell::mojom::ShellClient implementation:
 
 void ShellConnection::Initialize(shell::mojom::ConnectorPtr connector,
-                                 const String& name,
-                                 const String& user_id,
+                                 shell::mojom::IdentityPtr identity,
                                  uint32_t id) {
   connector_.reset(new ConnectorImpl(std::move(connector)));
   binding_.set_connection_error_handler(
       base::Bind(&ShellConnection::OnConnectionError,
                  weak_factory_.GetWeakPtr()));
-  client_->Initialize(connector_.get(), name, user_id, id);
+  client_->Initialize(connector_.get(), identity.To<Identity>(), id);
 }
 
 void ShellConnection::AcceptConnection(
-    const String& requestor_name,
-    const String& requestor_user_id,
-    uint32_t requestor_id,
+    shell::mojom::IdentityPtr source,
+    uint32_t source_id,
     shell::mojom::InterfaceProviderRequest local_interfaces,
     shell::mojom::InterfaceProviderPtr remote_interfaces,
     Array<String> allowed_interfaces,
     const String& name) {
   scoped_ptr<Connection> registry(new internal::ConnectionImpl(
-      name, requestor_name, requestor_id, requestor_user_id,
-      std::move(remote_interfaces), std::move(local_interfaces),
+      name, source.To<Identity>(), source_id, std::move(remote_interfaces),
+      std::move(local_interfaces),
       allowed_interfaces.To<std::set<std::string>>(),
       Connection::State::CONNECTED));
   if (!client_->AcceptConnection(registry.get()))
diff --git a/mojo/shell/public/cpp/lib/shell_test.cc b/mojo/shell/public/cpp/lib/shell_test.cc
index 7f981fe8..624fdc5 100644
--- a/mojo/shell/public/cpp/lib/shell_test.cc
+++ b/mojo/shell/public/cpp/lib/shell_test.cc
@@ -14,9 +14,9 @@
 ShellTestClient::ShellTestClient(ShellTest* test) : test_(test) {}
 ShellTestClient::~ShellTestClient() {}
 
-void ShellTestClient::Initialize(Connector* connector, const std::string& name,
-                                 const std::string& user_id, uint32_t id) {
-  test_->InitializeCalled(connector, name, user_id, id);
+void ShellTestClient::Initialize(Connector* connector, const Identity& identity,
+                                 uint32_t id) {
+  test_->InitializeCalled(connector, identity.name(), identity.user_id(), id);
 }
 
 ShellTest::ShellTest() {}
diff --git a/mojo/shell/public/cpp/shell_client.h b/mojo/shell/public/cpp/shell_client.h
index 12c444a..5f60316 100644
--- a/mojo/shell/public/cpp/shell_client.h
+++ b/mojo/shell/public/cpp/shell_client.h
@@ -10,6 +10,7 @@
 
 #include "mojo/public/cpp/system/macros.h"
 #include "mojo/shell/public/cpp/connection.h"
+#include "mojo/shell/public/cpp/identity.h"
 
 namespace mojo {
 
@@ -26,14 +27,12 @@
   virtual ~ShellClient();
 
   // Called once a bidirectional connection with the shell has been established.
-  // |name| is the name used to start the application.
+  // |identity| is the identity of the instance.
   // |id| is a unique identifier the shell uses to identify this specific
   // instance of the application.
-  // |user_id| identifies the user this instance is run as.
   // Called exactly once before any other method.
   virtual void Initialize(Connector* connector,
-                          const std::string& name,
-                          const std::string& user_id,
+                          const Identity& identity,
                           uint32_t id);
 
   // Called when a connection to this client is brokered by the shell. Override
diff --git a/mojo/shell/public/cpp/shell_connection.h b/mojo/shell/public/cpp/shell_connection.h
index 8e2f980..7ec245b 100644
--- a/mojo/shell/public/cpp/shell_connection.h
+++ b/mojo/shell/public/cpp/shell_connection.h
@@ -59,13 +59,11 @@
  private:
   // shell::mojom::ShellClient:
   void Initialize(shell::mojom::ConnectorPtr connector,
-                  const String& name,
-                  const String& user_id,
+                  shell::mojom::IdentityPtr identity,
                   uint32_t id) override;
   void AcceptConnection(
-      const String& requestor_name,
-      const String& requestor_user_id,
-      uint32_t requestor_id,
+      shell::mojom::IdentityPtr source,
+      uint32_t source_id,
       shell::mojom::InterfaceProviderRequest remote_interfaces,
       shell::mojom::InterfaceProviderPtr local_interfaces,
       Array<String> allowed_interfaces,
diff --git a/mojo/shell/public/cpp/shell_test.h b/mojo/shell/public/cpp/shell_test.h
index aec85a9..c3ed59a 100644
--- a/mojo/shell/public/cpp/shell_test.h
+++ b/mojo/shell/public/cpp/shell_test.h
@@ -35,8 +35,7 @@
 
  protected:
   void Initialize(Connector* connector,
-                  const std::string& name,
-                  const std::string& user_id,
+                  const Identity& identity,
                   uint32_t id) override;
 
  private:
diff --git a/mojo/shell/public/interfaces/connector.mojom b/mojo/shell/public/interfaces/connector.mojom
index 524047c..94acb69 100644
--- a/mojo/shell/public/interfaces/connector.mojom
+++ b/mojo/shell/public/interfaces/connector.mojom
@@ -26,6 +26,37 @@
   ACCESS_DENIED
 };
 
+// A collection of metadata that disambiguates instances in the shell.
+struct Identity {
+  // A mojo: or exe: name identifying an application.
+  string name;
+
+  // The user id of the target application instance to connect to. If no such
+  // instance exists, the shell may start one. This user id will be passed to
+  // the new instance via Initialize().
+  // When connecting to other applications, applications must generally pass
+  // kInheritUserID for this value, and the shell will either connect to an
+  // existing instance matching the caller's user id, create a new instance
+  // matching the caller's user id, or connect to an existing instance running
+  // as kRootUserID. By default, applications do not have the ability to set
+  // arbitrary values to this field, and doing so will result in a connection
+  // error on the remote service provider. An application with the ability to
+  // launch applications with arbitrary user ids (e.g. a login app) may set this
+  // value to something meaningful to it. The user id string is a valid guid of
+  // the form "%08X-%04X-%04X-%04X-%012llX", and (aside from the root user whose
+  // guid is defined above) intended to be not-guessable.
+  // When an application is initialized or receives a connection from another
+  // application, this value is always the resolved user id, never
+  // kInheritUserID.
+  string user_id;
+
+  // An application may spawn multiple instances with the same name,user_id
+  // pair, provided they are started with unique values of this field.
+  // TODO(beng): enforce the emptiness of this parameter unless the client bears
+  //             the appropriate capability.
+  string instance;
+};
+
 // Encapsulates establishing connections with other Mojo applications.
 interface Connector {
   // Requests a connection with another application. The application originating
@@ -43,24 +74,8 @@
   //
   // Parameters:
   //
-  //  name
-  //    A mojo: or exe: name identifying the target application.
-  //
-  //  user_id
-  //    The user id of the target application instance to connect to. If no such
-  //    instance exists, the shell may start one. This user id will be passed
-  //    to the new instance via Initialize(). Applications must generally pass
-  //    kInheritUserID for this value, and the shell will either connect to an
-  //    existing instance matching the caller's user id, create a new instance
-  //    matching the caller's user id, or connect to an existing instance
-  //    running as kRootUserID. By default, applications do not have the ability
-  //    to pass arbitrary values to this method, and doing so will result in a
-  //    connection error on the remote service provider. An application with
-  //    the ability to launch applications with arbitrary user ids (e.g. a login
-  //    app) may set this value to something meaningful to it. The user id
-  //    string is a valid guid of the form "%08X-%04X-%04X-%04X-%012llX", and
-  //    (aside from the root user whose guid is defined above) intended to be
-  //    not-guessable.
+  //  target
+  //    Identifies the target application instance to connect to.
   //
   //  remote_interfaces
   //    Allows the source application access to interface implementations
@@ -87,8 +102,7 @@
   //  application_id
   //    A unique identifier for the instance that was connected to.
   //
-  Connect(string name,
-          string user_id,
+  Connect(Identity target,
           InterfaceProvider&? remote_interfaces,
           InterfaceProvider? local_interfaces) => (ConnectResult result,
                                                    string user_id,
diff --git a/mojo/shell/public/interfaces/shell.mojom b/mojo/shell/public/interfaces/shell.mojom
index f20b87ce..1076127 100644
--- a/mojo/shell/public/interfaces/shell.mojom
+++ b/mojo/shell/public/interfaces/shell.mojom
@@ -9,8 +9,7 @@
 
 struct InstanceInfo {
   uint32 id;
-  string name;
-  string qualifier;
+  Identity identity;
   uint32 pid;
 };
 
@@ -67,8 +66,7 @@
   // code, see connector.mojom for definitions) the status of the instance
   // creation.
   CreateInstance(ShellClientFactory factory,
-                 string name,
-                 string user_id,
+                 Identity target,
                  CapabilityFilter filter,
                  PIDReceiver& pid_receiver) => (ConnectResult result);
 
diff --git a/mojo/shell/public/interfaces/shell_client.mojom b/mojo/shell/public/interfaces/shell_client.mojom
index 2af9a1f..d6a223e 100644
--- a/mojo/shell/public/interfaces/shell_client.mojom
+++ b/mojo/shell/public/interfaces/shell_client.mojom
@@ -20,20 +20,18 @@
   //    An interface back to the shell by which new connections may be
   //    established.
   //
-  //  name
-  //    The resolved name used in the connection request that resulted in this
-  //    application being initialized.
-  //
-  //  user_id
-  //    Identifies the user this instance is run as in the shell. This may
-  //    differ from the user the application that caused this application to be
-  //    instantiated is run as. This will always be a valid user id, never
-  //    Shell::kUserInherit.
+  //  identity
+  //    The identity of this instance in the shell. Includes:
+  //    * The resolved name used in the connection request that resulted in this
+  //      instance being initialized.
+  //    * The user associated with this instance in the shell. This will never
+  //      be kInheritUserID.
+  //    * The instance group this instance belongs to.
   //
   //  id
   //    A unique identifier used by the shell to identify this instance.
   //
-  Initialize(Connector connector, string name, string user_id, uint32 id);
+  Initialize(Connector connector, Identity identity, uint32 id);
 
   // Called when another application attempts to open a connection to this
   // application. An application implements this method to complete the exchange
@@ -44,18 +42,11 @@
   //
   // Parameters:
   //
-  //  requestor_name
-  //    The name of the source application.
+  //  source
+  //    The identity of the instance originating the connection.
   //
-  //  requestor_id
-  //    A unique identifier used by the shell to identify the source
-  //    application's instance.
-  //
-  //  requestor_user_id
-  //    An identifier for the user the source application is run as. This may
-  //    differ from the application the target is run as (i.e. the one received
-  //    via Initialize() above). This will always be a valid user id, never
-  //    kInheritUserID.
+  //  source_id
+  //    A unique identifier used by the shell to identify the source instance.
   //
   //  local_interfaces
   //    A request for an InterfaceProvider by which the source application may
@@ -74,9 +65,8 @@
   //  resolved_name
   //    The resolved name used to complete this connection.
   //
-  AcceptConnection(string requestor_name,
-                   string requestor_user_id,
-                   uint32 requestor_id,
+  AcceptConnection(Identity source,
+                   uint32 source_id,
                    InterfaceProvider&? local_interfaces,
                    InterfaceProvider? remote_interfaces,
                    array<string> allowed_interfaces,
diff --git a/mojo/shell/runner/host/BUILD.gn b/mojo/shell/runner/host/BUILD.gn
index 59f2cc7d..f7b45383 100644
--- a/mojo/shell/runner/host/BUILD.gn
+++ b/mojo/shell/runner/host/BUILD.gn
@@ -76,6 +76,7 @@
     "//mojo/message_pump",
     "//mojo/platform_handle:platform_handle_impl",
     "//mojo/shell",
+    "//mojo/shell/public/cpp:sources",
     "//mojo/shell/public/interfaces",
     "//mojo/shell/runner:init",
     "//mojo/shell/runner/common",
diff --git a/mojo/shell/runner/host/child_process_host.h b/mojo/shell/runner/host/child_process_host.h
index 25b59dc3..6c6411d 100644
--- a/mojo/shell/runner/host/child_process_host.h
+++ b/mojo/shell/runner/host/child_process_host.h
@@ -19,7 +19,7 @@
 #include "base/synchronization/waitable_event.h"
 #include "mojo/edk/embedder/platform_channel_pair.h"
 #include "mojo/public/cpp/system/message_pipe.h"
-#include "mojo/shell/identity.h"
+#include "mojo/shell/public/cpp/identity.h"
 #include "mojo/shell/public/interfaces/shell_client_factory.mojom.h"
 #include "mojo/shell/runner/host/child_process_host.h"
 
@@ -28,9 +28,9 @@
 }
 
 namespace mojo {
+class Identity;
 namespace shell {
 
-class Identity;
 class NativeRunnerDelegate;
 
 // This class represents a "child process host". Handles launching and
diff --git a/mojo/shell/shell.cc b/mojo/shell/shell.cc
index 17e912b6..4955c97 100644
--- a/mojo/shell/shell.cc
+++ b/mojo/shell/shell.cc
@@ -37,12 +37,40 @@
 const char kPackageManagerName[] = "mojo:package_manager";
 
 void EmptyResolverCallback(const String& resolved_name,
-                           const String& resolved_qualifier,
+                           const String& resolved_instance,
                            mojom::CapabilityFilterPtr base_filter,
                            const String& file_url) {}
 
 }
 
+Identity CreateShellIdentity() {
+  return Identity("mojo:shell", mojom::kRootUserID);
+}
+
+CapabilityFilter GetPermissiveCapabilityFilter() {
+  CapabilityFilter filter;
+  AllowedInterfaces interfaces;
+  interfaces.insert("*");
+  filter["*"] = interfaces;
+  return filter;
+}
+
+AllowedInterfaces GetAllowedInterfaces(const CapabilityFilter& filter,
+                                       const Identity& identity) {
+  // Start by looking for interfaces specific to the supplied identity.
+  auto it = filter.find(identity.name());
+  if (it != filter.end())
+    return it->second;
+
+  // Fall back to looking for a wildcard rule.
+  it = filter.find("*");
+  if (filter.size() == 1 && it != filter.end())
+    return it->second;
+
+  // Finally, nothing is allowed.
+  return AllowedInterfaces();
+}
+
 // Encapsulates a connection to an instance of an application, tracked by the
 // shell's Shell.
 class Shell::Instance : public mojom::Connector,
@@ -53,12 +81,13 @@
  public:
   Instance(mojom::ShellClientPtr shell_client,
            mojo::shell::Shell* shell,
-           const Identity& identity)
+           const Identity& identity,
+           const CapabilityFilter& filter)
     : shell_(shell),
       id_(GenerateUniqueID()),
       identity_(identity),
-      allow_any_application_(identity.filter().size() == 1 &&
-      identity.filter().count("*") == 1),
+      filter_(filter),
+      allow_any_application_(filter.size() == 1 && filter.count("*") == 1),
       shell_client_(std::move(shell_client)),
       pid_receiver_binding_(this),
       weak_factory_(this) {
@@ -73,7 +102,7 @@
 
   void InitializeClient() {
     shell_client_->Initialize(connectors_.CreateInterfacePtrAndBind(this),
-                              identity_.name(), identity_.user_id(), id_);
+                              mojom::Identity::From(identity_), id_);
     connectors_.set_connection_error_handler(
         base::Bind(&mojo::shell::Shell::OnInstanceError,
                    base::Unretained(shell_), base::Unretained(this)));
@@ -82,15 +111,16 @@
   void ConnectToClient(scoped_ptr<ConnectParams> params) {
     params->connect_callback().Run(mojom::ConnectResult::SUCCEEDED,
                                    identity_.user_id(), id_);
+    uint32_t source_id = mojom::kInvalidInstanceID;
     AllowedInterfaces interfaces;
     interfaces.insert("*");
-    if (!params->source().is_null())
-      interfaces = GetAllowedInterfaces(params->source().filter(), identity_);
-
     Instance* source = shell_->GetExistingInstance(params->source());
-    uint32_t source_id = source ? source->id() : mojom::kInvalidInstanceID;
+    if (source) {
+      interfaces = GetAllowedInterfaces(source->filter_, identity_);
+      source_id = source->id();
+    }
     shell_client_->AcceptConnection(
-        params->source().name(), params->source().user_id(), source_id,
+        mojom::Identity::From(params->source()), source_id,
         params->TakeRemoteInterfaces(), params->TakeLocalInterfaces(),
         Array<String>::From(interfaces), params->target().name());
   }
@@ -114,8 +144,7 @@
   mojom::InstanceInfoPtr CreateInstanceInfo() const {
     mojom::InstanceInfoPtr info(mojom::InstanceInfo::New());
     info->id = id_;
-    info->name = identity_.name();
-    info->qualifier = identity_.qualifier();
+    info->identity = mojom::Identity::From(identity_);
     info->pid = pid_;
     return info;
   }
@@ -131,37 +160,37 @@
 
  private:
   // mojom::Connector implementation:
-  void Connect(const String& app_name,
-               const String& user_id,
-               shell::mojom::InterfaceProviderRequest remote_interfaces,
-               shell::mojom::InterfaceProviderPtr local_interfaces,
+  void Connect(mojom::IdentityPtr target,
+               mojom::InterfaceProviderRequest remote_interfaces,
+               mojom::InterfaceProviderPtr local_interfaces,
                const ConnectCallback& callback) override {
-    if (!IsValidName(app_name)) {
-      LOG(ERROR) << "Error: invalid Name: " << app_name;
+    if (!IsValidName(target->name)) {
+      LOG(ERROR) << "Error: invalid Name: " << target->name;
       callback.Run(mojom::ConnectResult::INVALID_ARGUMENT,
                    mojom::kInheritUserID, mojom::kInvalidInstanceID);
       return;
     }
-    if (!base::IsValidGUID(user_id)) {
-      LOG(ERROR) << "Error: invalid user_id: " << user_id;
+    if (!base::IsValidGUID(target->user_id)) {
+      LOG(ERROR) << "Error: invalid user_id: " << target->user_id;
       callback.Run(mojom::ConnectResult::INVALID_ARGUMENT,
                    mojom::kInheritUserID, mojom::kInvalidInstanceID);
       return;
     }
     // TODO(beng): perform checking on policy of whether this instance is
     // allowed to pass different user_ids.
-    if (allow_any_application_ ||
-        identity_.filter().find(app_name) != identity_.filter().end()) {
+    // TODO(beng): perform checking on policy of whether this instance is
+    // allowed to pass non-empty instance identifiers.
+    if (allow_any_application_ || filter_.find(target->name) != filter_.end()) {
       scoped_ptr<ConnectParams> params(new ConnectParams);
       params->set_source(identity_);
-      params->set_target(Identity(app_name, std::string(), user_id));
+      params->set_target(target.To<Identity>());
       params->set_remote_interfaces(std::move(remote_interfaces));
       params->set_local_interfaces(std::move(local_interfaces));
       params->set_connect_callback(callback);
       shell_->Connect(std::move(params));
     } else {
       LOG(WARNING) << "CapabilityFilter prevented connection from: " <<
-          identity_.name() << " to: " << app_name;
+          identity_.name() << " to: " << target->name;
       callback.Run(mojom::ConnectResult::ACCESS_DENIED,
                    mojom::kInheritUserID, mojom::kInvalidInstanceID);
     }
@@ -183,31 +212,31 @@
 
   // mojom::Shell implementation:
   void CreateInstance(mojom::ShellClientFactoryPtr factory,
-                      const String& name,
-                      const String& user_id,
+                      mojom::IdentityPtr target,
                       mojom::CapabilityFilterPtr filter,
                       mojom::PIDReceiverRequest pid_receiver,
                       const CreateInstanceCallback& callback) override {
-    if (!base::IsValidGUID(user_id))
+    if (!base::IsValidGUID(target->user_id))
       callback.Run(mojom::ConnectResult::INVALID_ARGUMENT);
+
+    Identity target_id = target.To<Identity>();
+
     // TODO(beng): perform checking on policy of whether this instance is
     // allowed to pass different user_ids.
-    std::string user_id_string = user_id;
-    if (user_id_string == mojom::kInheritUserID)
-      user_id_string = identity_.user_id();
+    if (target_id.user_id() == mojom::kInheritUserID)
+      target_id.set_user_id(identity_.user_id());
 
+    mojom::ShellClientRequest request;
+    Instance* instance = shell_->CreateInstance(
+        target_id, filter->filter.To<CapabilityFilter>(), &request);
+    instance->pid_receiver_binding_.Bind(std::move(pid_receiver));
+    instance->factory_ = std::move(factory);
+    instance->factory_->CreateShellClient(std::move(request), target->name);
+    callback.Run(mojom::ConnectResult::SUCCEEDED);
     // We don't call ConnectToClient() here since the instance was created
     // manually by other code, not in response to a Connect() request. The newly
     // created instance is identified by |name| and may be subsequently reached
     // by client code using this identity.
-    Identity target_id(name, std::string(), user_id_string);
-    target_id.set_filter(filter->filter.To<CapabilityFilter>());
-    mojom::ShellClientRequest request;
-    Instance* instance = shell_->CreateInstance(target_id, &request);
-    instance->pid_receiver_binding_.Bind(std::move(pid_receiver));
-    instance->factory_ = std::move(factory);
-    instance->factory_->CreateShellClient(std::move(request), name);
-    callback.Run(mojom::ConnectResult::SUCCEEDED);
   }
   void AddInstanceListener(mojom::InstanceListenerPtr listener) override {
     // TODO(beng): this should only track the instances matching this user, and
@@ -233,6 +262,7 @@
   // process is launched.
   const uint32_t id_;
   const Identity identity_;
+  const CapabilityFilter filter_;
   const bool allow_any_application_;
   mojom::ShellClientPtr shell_client_;
   Binding<mojom::PIDReceiver> pid_receiver_binding_;
@@ -251,8 +281,11 @@
 Shell::TestAPI::~TestAPI() {}
 
 bool Shell::TestAPI::HasRunningInstanceForName(const std::string& name) const {
-  return shell_->identity_to_instance_.find(Identity(name)) !=
-         shell_->identity_to_instance_.end();
+  for (const auto& entry : shell_->identity_to_instance_) {
+    if (entry.first.name() == name)
+      return true;
+  }
+  return false;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -265,7 +298,8 @@
       native_runner_factory_(std::move(native_runner_factory)),
       weak_ptr_factory_(this) {
   mojom::ShellClientRequest request;
-  CreateInstance(CreateShellIdentity(), &request);
+  CreateInstance(CreateShellIdentity(), GetPermissiveCapabilityFilter(),
+                 &request);
   shell_connection_.reset(new ShellConnection(this, std::move(request)));
 
   InitPackageManager(std::move(app_catalog));
@@ -298,6 +332,8 @@
     params->set_target(target);
   }
 
+  CHECK(params->target().user_id() != mojom::kInheritUserID);
+
   // Connect to an existing matching instance, if possible.
   if (ConnectToExistingInstance(&params))
     return;
@@ -313,12 +349,12 @@
     const std::string& name) {
   DCHECK(!embedder_instance_);
 
-  mojo::shell::Identity target(name, std::string(), mojom::kRootUserID);
-  target.set_filter(GetPermissiveCapabilityFilter());
+  Identity target(name, mojom::kRootUserID);
   DCHECK(!GetExistingInstance(target));
 
   mojom::ShellClientRequest request;
-  embedder_instance_ = CreateInstance(target, &request);
+  embedder_instance_ = CreateInstance(
+      target, GetPermissiveCapabilityFilter(), &request);
   DCHECK(embedder_instance_);
 
   return request;
@@ -363,7 +399,10 @@
   SetLoaderForName(std::move(loader), name);
 
   mojom::ShellClientRequest request;
-  CreateInstance(Identity(name), &request);
+  // TODO(beng): Does the package manager actually have to be run with a
+  //             permissive filter?
+  Identity identity(name, mojom::kRootUserID);
+  CreateInstance(identity, GetPermissiveCapabilityFilter(), &request);
   loader_raw->Load(name, std::move(request));
 
   ConnectToInterface(this, CreateShellIdentity(), name, &shell_resolver_);
@@ -419,10 +458,13 @@
 }
 
 Shell::Instance* Shell::CreateInstance(const Identity& target_id,
+                                       const CapabilityFilter& filter,
                                        mojom::ShellClientRequest* request) {
+  CHECK(target_id.user_id() != mojom::kInheritUserID);
   mojom::ShellClientPtr shell_client;
   *request = GetProxy(&shell_client);
-  Instance* instance = new Instance(std::move(shell_client), this, target_id);
+  Instance* instance =
+      new Instance(std::move(shell_client), this, target_id, filter);
   DCHECK(identity_to_instance_.find(target_id) ==
          identity_to_instance_.end());
   identity_to_instance_[target_id] = instance;
@@ -483,14 +525,14 @@
 
 void Shell::OnGotResolvedName(scoped_ptr<ConnectParams> params,
                               const String& resolved_name,
-                              const String& resolved_qualifier,
+                              const String& resolved_instance,
                               mojom::CapabilityFilterPtr base_filter,
                               const String& file_url) {
-  std::string qualifier = params->target().qualifier();
-  if (qualifier == GetNamePath(params->target().name()))
-    qualifier = resolved_qualifier;
-  Identity target(params->target().name(), qualifier,
-                  params->target().user_id());
+  std::string instance_name = params->target().instance();
+  if (instance_name == GetNamePath(params->target().name()))
+    instance_name = resolved_instance;
+  Identity target(params->target().name(), params->target().user_id(),
+                  instance_name);
   params->set_target(target);
 
   // It's possible that when this manifest request was issued, another one was
@@ -505,10 +547,9 @@
   CapabilityFilter filter = GetPermissiveCapabilityFilter();
   if (!base_filter.is_null())
     filter = base_filter->filter.To<CapabilityFilter>();
-  target.set_filter(filter);
 
   mojom::ShellClientRequest request;
-  Instance* instance = CreateInstance(target, &request);
+  Instance* instance = CreateInstance(target, filter, &request);
   instance->ConnectToClient(std::move(params));
 
   if (LoadWithLoader(target, &request))
@@ -517,11 +558,11 @@
   CHECK(!file_url.is_null() && !base_filter.is_null());
 
   if (target.name() != resolved_name) {
-    // In cases where a package alias is resolved, we have to use the qualifier
+    // In cases where a package alias is resolved, we have to use the instance
     // from the original request rather than for the package itself, which will
     // always be the same.
     CreateShellClient(
-        source, Identity(resolved_name, resolved_qualifier, target.user_id()),
+        source, Identity(resolved_name, target.user_id(), resolved_instance),
         target.name(), std::move(request));
   } else {
     bool start_sandboxed = false;
diff --git a/mojo/shell/shell.h b/mojo/shell/shell.h
index 4a5dcb2..407f75d 100644
--- a/mojo/shell/shell.h
+++ b/mojo/shell/shell.h
@@ -16,9 +16,9 @@
 #include "mojo/services/package_manager/package_manager.h"
 #include "mojo/services/package_manager/public/interfaces/shell_resolver.mojom.h"
 #include "mojo/shell/connect_params.h"
-#include "mojo/shell/identity.h"
 #include "mojo/shell/loader.h"
 #include "mojo/shell/native_runner.h"
+#include "mojo/shell/public/cpp/identity.h"
 #include "mojo/shell/public/cpp/interface_factory.h"
 #include "mojo/shell/public/cpp/shell_client.h"
 #include "mojo/shell/public/interfaces/connector.mojom.h"
@@ -36,6 +36,25 @@
 class ShellConnection;
 namespace shell {
 
+// A set of names of interfaces that may be exposed to an application.
+using AllowedInterfaces = std::set<std::string>;
+// A map of allowed applications to allowed interface sets. See shell.mojom for
+// more details.
+using CapabilityFilter = std::map<std::string, AllowedInterfaces>;
+
+// Creates an identity for the Shell, used when the Shell connects to
+// applications.
+Identity CreateShellIdentity();
+
+// Returns a capability filter that allows an application to connect to any
+// other application and any service exposed by other applications.
+CapabilityFilter GetPermissiveCapabilityFilter();
+
+// Returns the set of interfaces that an application instance with |filter| is
+// allowed to see from an instance with |identity|.
+AllowedInterfaces GetAllowedInterfaces(const CapabilityFilter& filter,
+                                       const Identity& identity);
+
 class Shell : public ShellClient {
  public:
   // API for testing.
@@ -119,6 +138,7 @@
   bool ConnectToExistingInstance(scoped_ptr<ConnectParams>* params);
 
   Instance* CreateInstance(const Identity& target_id,
+                           const CapabilityFilter& filter,
                            mojom::ShellClientRequest* request);
 
   // Called from the instance implementing mojom::Shell. |user_id| must be
@@ -152,7 +172,7 @@
   // run with, from its manifest.
   void OnGotResolvedName(scoped_ptr<ConnectParams> params,
                          const String& resolved_name,
-                         const String& resolved_qualifier,
+                         const String& resolved_instance,
                          mojom::CapabilityFilterPtr base_filter,
                          const String& file_url);
 
diff --git a/mojo/shell/standalone/context.cc b/mojo/shell/standalone/context.cc
index 6cd1ac4..a6fcbed 100644
--- a/mojo/shell/standalone/context.cc
+++ b/mojo/shell/standalone/context.cc
@@ -164,8 +164,7 @@
 
   scoped_ptr<ConnectParams> params(new ConnectParams);
   params->set_source(CreateShellIdentity());
-  params->set_target(
-      Identity("mojo:tracing", std::string(), mojom::kInheritUserID));
+  params->set_target(Identity("mojo:tracing", mojom::kInheritUserID));
   params->set_remote_interfaces(GetProxy(&tracing_remote_interfaces));
   params->set_local_interfaces(std::move(tracing_local_interfaces));
   shell_->Connect(std::move(params));
@@ -238,7 +237,7 @@
 
   scoped_ptr<ConnectParams> params(new ConnectParams);
   params->set_source(CreateShellIdentity());
-  params->set_target(Identity(name, std::string(), mojom::kRootUserID));
+  params->set_target(Identity(name, mojom::kRootUserID));
   params->set_remote_interfaces(GetProxy(&remote_interfaces));
   params->set_local_interfaces(std::move(local_interfaces));
   shell_->Connect(std::move(params));
diff --git a/mojo/shell/tests/connect/connect_test.mojom b/mojo/shell/tests/connect/connect_test.mojom
index 356061e..3eeaa12 100644
--- a/mojo/shell/tests/connect/connect_test.mojom
+++ b/mojo/shell/tests/connect/connect_test.mojom
@@ -14,6 +14,8 @@
   // the standalone app's CapabilityFilter, but whose enclosing package is not.
   // The connection should be blocked and title should be "uninitialized".
   ConnectToAllowedAppInBlockedPackage() => (string title);
+
+  GetInstance() => (string instance);
 };
 
 struct ConnectionState {
diff --git a/mojo/shell/tests/connect/connect_test_app.cc b/mojo/shell/tests/connect/connect_test_app.cc
index b469d165..205ddcf 100644
--- a/mojo/shell/tests/connect/connect_test_app.cc
+++ b/mojo/shell/tests/connect/connect_test_app.cc
@@ -33,12 +33,11 @@
 
  private:
   // mojo::ShellClient:
-  void Initialize(Connector* connector, const std::string& name,
-                  const std::string& user_id, uint32_t id) override {
+  void Initialize(Connector* connector, const Identity& identity,
+                  uint32_t id) override {
     connector_ = connector;
-    name_ = name;
+    identity_ = identity;
     id_ = id;
-    userid_ = user_id;
     bindings_.set_connection_error_handler(
         base::Bind(&ConnectTestApp::OnConnectionError,
                    base::Unretained(this)));
@@ -54,12 +53,12 @@
     uint32_t remote_id = connection->GetRemoteInstanceID();
     test::mojom::ConnectionStatePtr state(test::mojom::ConnectionState::New());
     state->connection_local_name = connection->GetConnectionName();
-    state->connection_remote_name = connection->GetRemoteApplicationName();
-    state->connection_remote_userid = connection->GetRemoteUserID();
+    state->connection_remote_name = connection->GetRemoteIdentity().name();
+    state->connection_remote_userid = connection->GetRemoteIdentity().user_id();
     state->connection_remote_id = remote_id;
-    state->initialize_local_name = name_;
+    state->initialize_local_name = identity_.name();
     state->initialize_id = id_;
-    state->initialize_userid = userid_;
+    state->initialize_userid = identity_.user_id();
     connection->GetInterface(&caller_);
     caller_->ConnectionAccepted(std::move(state));
 
@@ -117,6 +116,9 @@
       run_loop.Run();
     }
   }
+  void GetInstance(const GetInstanceCallback& callback) override {
+    callback.Run(identity_.instance());
+  }
 
   // test::mojom::BlockedInterface:
   void GetTitleBlocked(const GetTitleBlockedCallback& callback) override {
@@ -144,9 +146,8 @@
   }
 
   Connector* connector_ = nullptr;
-  std::string name_;
+  Identity identity_;
   uint32_t id_ = shell::mojom::kInvalidInstanceID;
-  std::string userid_ = mojom::kRootUserID;
   BindingSet<test::mojom::ConnectTestService> bindings_;
   BindingSet<test::mojom::StandaloneApp> standalone_bindings_;
   BindingSet<test::mojom::BlockedInterface> blocked_bindings_;
diff --git a/mojo/shell/tests/connect/connect_test_package.cc b/mojo/shell/tests/connect/connect_test_package.cc
index e927335..7956425 100644
--- a/mojo/shell/tests/connect/connect_test_package.cc
+++ b/mojo/shell/tests/connect/connect_test_package.cc
@@ -50,11 +50,11 @@
 
  private:
   // mojo::ShellClient:
-  void Initialize(Connector* connector, const std::string& name,
-                  const std::string& user_id, uint32_t id) override {
-    name_ = name;
+  void Initialize(Connector* connector, const Identity& identity,
+                  uint32_t id) override {
+    name_ = identity.name();
+    userid_ = identity.user_id();
     id_ = id;
-    userid_ = user_id;
     bindings_.set_connection_error_handler(
         base::Bind(&ProvidedShellClient::OnConnectionError,
                    base::Unretained(this)));
@@ -66,8 +66,8 @@
     uint32_t remote_id = connection->GetRemoteInstanceID();
     test::mojom::ConnectionStatePtr state(test::mojom::ConnectionState::New());
     state->connection_local_name = connection->GetConnectionName();
-    state->connection_remote_name = connection->GetRemoteApplicationName();
-    state->connection_remote_userid = connection->GetRemoteUserID();
+    state->connection_remote_name = connection->GetRemoteIdentity().name();
+    state->connection_remote_userid = connection->GetRemoteIdentity().user_id();
     state->connection_remote_id = remote_id;
     state->initialize_local_name = name_;
     state->initialize_id = id_;
@@ -136,8 +136,8 @@
 
  private:
   // mojo::ShellClient:
-  void Initialize(Connector* connector, const std::string& name,
-                  const std::string& user_id, uint32_t id) override {
+  void Initialize(Connector* connector, const Identity& identity,
+                  uint32_t id) override {
     bindings_.set_connection_error_handler(
         base::Bind(&ConnectTestShellClient::OnConnectionError,
                    base::Unretained(this)));
diff --git a/mojo/shell/tests/connect/connect_unittest.cc b/mojo/shell/tests/connect/connect_unittest.cc
index bf04e14..e28a635 100644
--- a/mojo/shell/tests/connect/connect_unittest.cc
+++ b/mojo/shell/tests/connect/connect_unittest.cc
@@ -49,6 +49,14 @@
   ~ConnectTest() override {}
 
  protected:
+  scoped_ptr<Connection> ConnectTo(Connector::ConnectParams* params) {
+    scoped_ptr<Connection> connection = connector()->Connect(params);
+    base::RunLoop loop;
+    connection->AddConnectionCompletedClosure(base::Bind(&QuitLoop, &loop));
+    loop.Run();
+    return connection;
+  }
+
   void set_ping_callback(const base::Closure& callback) {
     ping_callback_ = callback;
   }
@@ -119,7 +127,47 @@
   EXPECT_EQ("APP", title);
   EXPECT_FALSE(connection->IsPending());
   EXPECT_NE(mojom::kInvalidInstanceID, connection->GetRemoteInstanceID());
-  EXPECT_EQ(connection->GetRemoteApplicationName(), kTestAppName);
+  EXPECT_EQ(connection->GetRemoteIdentity().name(), kTestAppName);
+}
+
+TEST_F(ConnectTest, Instances) {
+  Connector::ConnectParams params_a(
+      Identity(kTestAppName, mojom::kInheritUserID, "A"));
+  scoped_ptr<Connection> connection_a1 = ConnectTo(&params_a);
+  scoped_ptr<Connection> connection_a2 = ConnectTo(&params_a);
+  std::string instance_a1, instance_a2;
+  test::mojom::StandaloneAppPtr standalone_app_a1;
+  {
+    connection_a1->GetInterface(&standalone_app_a1);
+    base::RunLoop loop;
+    standalone_app_a1->GetInstance(
+        base::Bind(&ReceiveTitle, &instance_a1, &loop));
+    loop.Run();
+  }
+  test::mojom::StandaloneAppPtr standalone_app_a2;
+  {
+    connection_a2->GetInterface(&standalone_app_a2);
+    base::RunLoop loop;
+    standalone_app_a2->GetInstance(
+        base::Bind(&ReceiveTitle, &instance_a2, &loop));
+    loop.Run();
+  }
+  EXPECT_EQ(instance_a1, instance_a2);
+
+  Connector::ConnectParams params_b(
+      Identity(kTestAppName, mojom::kInheritUserID, "B"));
+  scoped_ptr<Connection> connection_b = ConnectTo(&params_b);
+  std::string instance_b;
+  test::mojom::StandaloneAppPtr standalone_app_b;
+  {
+    connection_b->GetInterface(&standalone_app_b);
+    base::RunLoop loop;
+    standalone_app_b->GetInstance(
+        base::Bind(&ReceiveTitle, &instance_b, &loop));
+    loop.Run();
+  }
+
+  EXPECT_NE(instance_a1, instance_b);
 }
 
 // BlockedInterface should not be exposed to this application because it is not
@@ -148,7 +196,7 @@
   EXPECT_EQ("A", a_name);
   EXPECT_FALSE(connection->IsPending());
   EXPECT_NE(mojom::kInvalidInstanceID, connection->GetRemoteInstanceID());
-  EXPECT_EQ(connection->GetRemoteApplicationName(), kTestAppAName);
+  EXPECT_EQ(connection->GetRemoteIdentity().name(), kTestAppAName);
 }
 
 // Ask the target application to attempt to connect to a third application
@@ -222,7 +270,7 @@
       run_loop.Run();
       CompareConnectionState(
           kTestAppName, test_name(), test_userid(), test_instance_id(),
-          kTestAppName, connection->GetRemoteUserID(), remote_id);
+          kTestAppName, connection->GetRemoteIdentity().user_id(), remote_id);
     }
   }
 
@@ -252,7 +300,7 @@
       run_loop.Run();
       CompareConnectionState(
           kTestAppAName, test_name(), test_userid(), test_instance_id(),
-          kTestAppAName, connection->GetRemoteUserID(), remote_id);
+          kTestAppAName, connection->GetRemoteIdentity().user_id(), remote_id);
     }
 
   }
diff --git a/mojo/shell/tests/lifecycle/lifecycle_unittest.cc b/mojo/shell/tests/lifecycle/lifecycle_unittest.cc
index 012dffc..e85d08b 100644
--- a/mojo/shell/tests/lifecycle/lifecycle_unittest.cc
+++ b/mojo/shell/tests/lifecycle/lifecycle_unittest.cc
@@ -13,6 +13,7 @@
 #include "mojo/edk/embedder/embedder.h"
 #include "mojo/edk/embedder/platform_channel_pair.h"
 #include "mojo/edk/embedder/scoped_platform_handle.h"
+#include "mojo/shell/public/cpp/identity.h"
 #include "mojo/shell/public/cpp/shell_test.h"
 #include "mojo/shell/public/interfaces/shell.mojom.h"
 #include "mojo/shell/runner/common/switches.h"
@@ -40,12 +41,10 @@
 
 struct Instance {
   Instance() : id(shell::mojom::kInvalidInstanceID), pid(0) {}
-  Instance(const std::string& name, const std::string& qualifier, uint32_t id,
-           uint32_t pid)
-      : name(name), qualifier(qualifier), id(id), pid(pid) {}
+  Instance(const Identity& identity, uint32_t id, uint32_t pid)
+      : identity(identity), id(id), pid(pid) {}
 
-  std::string name;
-  std::string qualifier;
+  Identity identity;
   uint32_t id;
   uint32_t pid;
 };
@@ -74,17 +73,17 @@
   // mojom::InstanceListener:
   void SetExistingInstances(Array<mojom::InstanceInfoPtr> instances) override {
     for (const auto& instance : instances) {
-      Instance i(instance->name, instance->qualifier, instance->id,
+      Instance i(instance->identity.To<Identity>(), instance->id,
                  instance->pid);
-      initial_instances_[i.name] = i;
-      instances_[i.name] = i;
+      initial_instances_[i.identity.name()] = i;
+      instances_[i.identity.name()] = i;
     }
     loop_->Quit();
   }
   void InstanceCreated(mojom::InstanceInfoPtr instance) override {
-    instances_[instance->name] =
-       Instance(instance->name, instance->qualifier, instance->id,
-                instance->pid);
+    instances_[instance->identity->name] =
+        Instance(instance->identity.To<Identity>(), instance->id,
+                 instance->pid);
   }
   void InstanceDestroyed(uint32_t id) override {
     for (auto it = instances_.begin(); it != instances_.end(); ++it) {
@@ -217,9 +216,12 @@
     factory.Bind(mojo::InterfacePtrInfo<mojo::shell::mojom::ShellClientFactory>(
         std::move(pipe), 0u));
     base::RunLoop loop;
-    shell->CreateInstance(std::move(factory), kTestExeName,
-                          mojom::kInheritUserID, std::move(filter),
-                          std::move(request),
+    mojo::shell::mojom::IdentityPtr target(mojo::shell::mojom::Identity::New());
+    target->name = kTestExeName;
+    target->user_id = mojom::kInheritUserID;
+    target->instance = "";
+    shell->CreateInstance(std::move(factory), std::move(target),
+                          std::move(filter), std::move(request),
                           base::Bind(&LifecycleTest::OnConnectionCompleted,
                                      base::Unretained(this), &loop));
     loop.Run();
diff --git a/mojo/shell/tests/loader_unittest.cc b/mojo/shell/tests/loader_unittest.cc
index 45156be..56ffd6fb 100644
--- a/mojo/shell/tests/loader_unittest.cc
+++ b/mojo/shell/tests/loader_unittest.cc
@@ -123,7 +123,7 @@
   // mojo::ShellClient implementation.
   bool AcceptConnection(Connection* connection) override {
     connection->AddInterface<TestService>(this);
-    last_requestor_name_ = connection->GetRemoteApplicationName();
+    last_requestor_name_ = connection->GetRemoteIdentity().name();
     return true;
   }
 
@@ -353,14 +353,14 @@
 
   bool AcceptConnection(Connection* connection) override {
     if (!requestor_name_.empty() &&
-        requestor_name_ != connection->GetRemoteApplicationName()) {
+        requestor_name_ != connection->GetRemoteIdentity().name()) {
       context_->set_tester_called_quit();
       context_->QuitSoon();
       base::MessageLoop::current()->QuitWhenIdle();
       return false;
     }
     // If we're coming from A, then add B, otherwise A.
-    if (connection->GetRemoteApplicationName() == kTestAURLString)
+    if (connection->GetRemoteIdentity().name() == kTestAURLString)
       connection->AddInterface<TestB>(this);
     else
       connection->AddInterface<TestA>(this);
@@ -433,7 +433,7 @@
     mojom::InterfaceProviderPtr remote_interfaces;
     scoped_ptr<ConnectParams> params(new ConnectParams);
     params->set_source(CreateShellIdentity());
-    params->set_target(Identity(name));
+    params->set_target(Identity(name, mojom::kRootUserID));
     params->set_remote_interfaces(GetProxy(&remote_interfaces));
     params->set_connect_callback(
         base::Bind(&OnConnect, base::Unretained(&loop)));
@@ -523,7 +523,7 @@
   bool called = false;
   scoped_ptr<ConnectParams> params(new ConnectParams);
   params->set_source(CreateShellIdentity());
-  params->set_target(Identity("test:test", "", mojom::kRootUserID));
+  params->set_target(Identity("test:test", mojom::kRootUserID));
   shell_->SetInstanceQuitCallback(
       base::Bind(&QuitClosure, params->target(), &called));
   shell_->Connect(std::move(params));
diff --git a/mojo/shell/tests/shell/driver.cc b/mojo/shell/tests/shell/driver.cc
index 62c57bfc..68254f8 100644
--- a/mojo/shell/tests/shell/driver.cc
+++ b/mojo/shell/tests/shell/driver.cc
@@ -44,8 +44,8 @@
 
  private:
   // mojo::ShellClient:
-  void Initialize(mojo::Connector* connector, const std::string& name,
-                  const std::string& user_id, uint32_t id) override {
+  void Initialize(mojo::Connector* connector, const mojo::Identity& identity,
+                  uint32_t id) override {
     base::FilePath target_path;
     CHECK(base::PathService::Get(base::DIR_EXE, &target_path));
   #if defined(OS_WIN)
@@ -98,9 +98,12 @@
 
     mojo::shell::mojom::ShellPtr shell;
     connector->ConnectToInterface("mojo:shell", &shell);
-    shell->CreateInstance(std::move(factory), "exe:shell_unittest_target",
-                          mojo::shell::mojom::kInheritUserID, std::move(filter),
-                          std::move(request),
+    mojo::shell::mojom::IdentityPtr target(mojo::shell::mojom::Identity::New());
+    target->name = "exe:shell_unittest_target";
+    target->user_id = mojo::shell::mojom::kInheritUserID;
+    target->instance = "";
+    shell->CreateInstance(std::move(factory), std::move(target),
+                          std::move(filter), std::move(request),
                           base::Bind(&Driver::OnConnectionCompleted,
                                      base::Unretained(this)));
 
diff --git a/mojo/shell/tests/shell/shell_unittest.cc b/mojo/shell/tests/shell/shell_unittest.cc
index db752bba..4a0debf 100644
--- a/mojo/shell/tests/shell/shell_unittest.cc
+++ b/mojo/shell/tests/shell/shell_unittest.cc
@@ -127,11 +127,11 @@
   void SetExistingInstances(Array<mojom::InstanceInfoPtr> instances) override {
     for (size_t i = 0; i < instances.size(); ++i) {
       initial_instances_.push_back(InstanceInfo(instances[i]->id,
-                                                instances[i]->name));
+                                                instances[i]->identity->name));
     }
   }
   void InstanceCreated(mojom::InstanceInfoPtr instance) override {
-    instances_.push_back(InstanceInfo(instance->id, instance->name));
+    instances_.push_back(InstanceInfo(instance->id, instance->identity->name));
   }
   void InstanceDestroyed(uint32_t id) override {
     for (auto it = instances_.begin(); it != instances_.end(); ++it) {
diff --git a/mojo/shell/tests/shell/target.cc b/mojo/shell/tests/shell/target.cc
index 3f75dc9..e05a9dc 100644
--- a/mojo/shell/tests/shell/target.cc
+++ b/mojo/shell/tests/shell/target.cc
@@ -23,8 +23,8 @@
 
  private:
   // mojo::ShellClient:
-  void Initialize(mojo::Connector* connector, const std::string& name,
-                  const std::string& user_id, uint32_t id) override {
+  void Initialize(mojo::Connector* connector, const mojo::Identity& identity,
+                  uint32_t id) override {
     CreateInstanceTestPtr service;
     connector->ConnectToInterface("mojo:shell_unittest", &service);
     service->SetTargetID(id);
diff --git a/net/socket/ssl_server_socket.h b/net/socket/ssl_server_socket.h
index bfbe7de..479bbc7 100644
--- a/net/socket/ssl_server_socket.h
+++ b/net/socket/ssl_server_socket.h
@@ -31,6 +31,20 @@
   virtual int Handshake(const CompletionCallback& callback) = 0;
 };
 
+class SSLServerContext {
+ public:
+  virtual ~SSLServerContext(){};
+
+  // Creates an SSL server socket over an already-connected transport socket.
+  // The caller must ensure the returned socket does not outlive the server
+  // context.
+  //
+  // The caller starts the SSL server handshake by calling Handshake on the
+  // returned socket.
+  virtual scoped_ptr<SSLServerSocket> CreateSSLServerSocket(
+      scoped_ptr<StreamSocket> socket) = 0;
+};
+
 // Configures the underlying SSL library for the use of SSL server sockets.
 //
 // Due to the requirements of the underlying libraries, this should be called
@@ -41,18 +55,14 @@
 // omitted.
 NET_EXPORT void EnableSSLServerSockets();
 
-// Creates an SSL server socket over an already-connected transport socket.
-// The caller must provide the server certificate and private key to use.
+// Creates an SSL server socket context where all sockets spawned using this
+// context will share the same session cache.
 //
-// The returned SSLServerSocket takes ownership of |socket|.  Stubbed versions
-// of CreateSSLServerSocket will delete |socket| and return NULL.
+// The caller must provide the server certificate and private key to use.
 // It takes a reference to |certificate|.
 // The |key| and |ssl_config| parameters are copied.
 //
-// The caller starts the SSL server handshake by calling Handshake on the
-// returned socket.
-NET_EXPORT scoped_ptr<SSLServerSocket> CreateSSLServerSocket(
-    scoped_ptr<StreamSocket> socket,
+NET_EXPORT scoped_ptr<SSLServerContext> CreateSSLServerContext(
     X509Certificate* certificate,
     const crypto::RSAPrivateKey& key,
     const SSLServerConfig& ssl_config);
diff --git a/net/socket/ssl_server_socket_nss.cc b/net/socket/ssl_server_socket_nss.cc
index 6258c87c..9d29a46 100644
--- a/net/socket/ssl_server_socket_nss.cc
+++ b/net/socket/ssl_server_socket_nss.cc
@@ -75,27 +75,140 @@
 static base::LazyInstance<NSSSSLServerInitSingleton>::Leaky
     g_nss_ssl_server_init_singleton = LAZY_INSTANCE_INITIALIZER;
 
-}  // namespace
+class SSLServerSocketNSS : public SSLServerSocket {
+ public:
+  // See comments on CreateSSLServerSocket for details of how these
+  // parameters are used.
+  SSLServerSocketNSS(scoped_ptr<StreamSocket> socket,
+                     X509Certificate* certificate,
+                     const crypto::RSAPrivateKey& key,
+                     const SSLServerConfig& ssl_server_config);
+  ~SSLServerSocketNSS() override;
 
-void EnableSSLServerSockets() {
-  g_nss_ssl_server_init_singleton.Get();
-}
+  // SSLServerSocket interface.
+  int Handshake(const CompletionCallback& callback) override;
 
-scoped_ptr<SSLServerSocket> CreateSSLServerSocket(
-    scoped_ptr<StreamSocket> socket,
-    X509Certificate* certificate,
-    const crypto::RSAPrivateKey& key,
-    const SSLServerConfig& ssl_server_config) {
-  DCHECK(g_nss_server_sockets_init) << "EnableSSLServerSockets() has not been"
-                                    << " called yet!";
+  // SSLSocket interface.
+  int ExportKeyingMaterial(const base::StringPiece& label,
+                           bool has_context,
+                           const base::StringPiece& context,
+                           unsigned char* out,
+                           unsigned int outlen) override;
+  int GetTLSUniqueChannelBinding(std::string* out) override;
 
-  return scoped_ptr<SSLServerSocket>(new SSLServerSocketNSS(
-      std::move(socket), certificate, key, ssl_server_config));
-}
+  // Socket interface (via StreamSocket).
+  int Read(IOBuffer* buf,
+           int buf_len,
+           const CompletionCallback& callback) override;
+  int Write(IOBuffer* buf,
+            int buf_len,
+            const CompletionCallback& callback) override;
+  int SetReceiveBufferSize(int32_t size) override;
+  int SetSendBufferSize(int32_t size) override;
+
+  // StreamSocket implementation.
+  int Connect(const CompletionCallback& callback) override;
+  void Disconnect() override;
+  bool IsConnected() const override;
+  bool IsConnectedAndIdle() const override;
+  int GetPeerAddress(IPEndPoint* address) const override;
+  int GetLocalAddress(IPEndPoint* address) const override;
+  const BoundNetLog& NetLog() const override;
+  void SetSubresourceSpeculation() override;
+  void SetOmniboxSpeculation() override;
+  bool WasEverUsed() const override;
+  bool UsingTCPFastOpen() const override;
+  bool WasNpnNegotiated() const override;
+  NextProto GetNegotiatedProtocol() const override;
+  bool GetSSLInfo(SSLInfo* ssl_info) override;
+  void GetConnectionAttempts(ConnectionAttempts* out) const override;
+  void ClearConnectionAttempts() override {}
+  void AddConnectionAttempts(const ConnectionAttempts& attempts) override {}
+  int64_t GetTotalReceivedBytes() const override;
+
+ private:
+  enum State {
+    STATE_NONE,
+    STATE_HANDSHAKE,
+  };
+
+  int InitializeSSLOptions();
+
+  void OnSendComplete(int result);
+  void OnRecvComplete(int result);
+  void OnHandshakeIOComplete(int result);
+
+  int BufferSend();
+  void BufferSendComplete(int result);
+  int BufferRecv();
+  void BufferRecvComplete(int result);
+  bool DoTransportIO();
+  int DoPayloadRead();
+  int DoPayloadWrite();
+
+  int DoHandshakeLoop(int last_io_result);
+  int DoReadLoop(int result);
+  int DoWriteLoop(int result);
+  int DoHandshake();
+  void DoHandshakeCallback(int result);
+  void DoReadCallback(int result);
+  void DoWriteCallback(int result);
+
+  static SECStatus OwnAuthCertHandler(void* arg,
+                                      PRFileDesc* socket,
+                                      PRBool checksig,
+                                      PRBool is_server);
+  static void HandshakeCallback(PRFileDesc* socket, void* arg);
+
+  int Init();
+
+  // Members used to send and receive buffer.
+  bool transport_send_busy_;
+  bool transport_recv_busy_;
+
+  scoped_refptr<IOBuffer> recv_buffer_;
+
+  BoundNetLog net_log_;
+
+  CompletionCallback user_handshake_callback_;
+  CompletionCallback user_read_callback_;
+  CompletionCallback user_write_callback_;
+
+  // Used by Read function.
+  scoped_refptr<IOBuffer> user_read_buf_;
+  int user_read_buf_len_;
+
+  // Used by Write function.
+  scoped_refptr<IOBuffer> user_write_buf_;
+  int user_write_buf_len_;
+
+  // The NSS SSL state machine
+  PRFileDesc* nss_fd_;
+
+  // Buffers for the network end of the SSL state machine
+  memio_Private* nss_bufs_;
+
+  // StreamSocket for sending and receiving data.
+  scoped_ptr<StreamSocket> transport_socket_;
+
+  // Options for the SSL socket.
+  SSLServerConfig ssl_server_config_;
+
+  // Certificate for the server.
+  scoped_refptr<X509Certificate> cert_;
+
+  // Private key used by the server.
+  scoped_ptr<crypto::RSAPrivateKey> key_;
+
+  State next_handshake_state_;
+  bool completed_handshake_;
+
+  DISALLOW_COPY_AND_ASSIGN(SSLServerSocketNSS);
+};
 
 SSLServerSocketNSS::SSLServerSocketNSS(
     scoped_ptr<StreamSocket> transport_socket,
-    scoped_refptr<X509Certificate> cert,
+    X509Certificate* cert,
     const crypto::RSAPrivateKey& key,
     const SSLServerConfig& ssl_server_config)
     : transport_send_busy_(false),
@@ -193,7 +306,8 @@
   return ERR_NOT_IMPLEMENTED;
 }
 
-int SSLServerSocketNSS::Read(IOBuffer* buf, int buf_len,
+int SSLServerSocketNSS::Read(IOBuffer* buf,
+                             int buf_len,
                              const CompletionCallback& callback) {
   DCHECK(user_read_callback_.is_null());
   DCHECK(user_handshake_callback_.is_null());
@@ -217,7 +331,8 @@
   return rv;
 }
 
-int SSLServerSocketNSS::Write(IOBuffer* buf, int buf_len,
+int SSLServerSocketNSS::Write(IOBuffer* buf,
+                              int buf_len,
                               const CompletionCallback& callback) {
   DCHECK(user_write_callback_.is_null());
   DCHECK(!user_write_buf_);
@@ -582,8 +697,7 @@
     memcpy(send_buffer->data(), buf1, len1);
     memcpy(send_buffer->data() + len1, buf2, len2);
     rv = transport_socket_->Write(
-        send_buffer.get(),
-        len,
+        send_buffer.get(), len,
         base::Bind(&SSLServerSocketNSS::BufferSendComplete,
                    base::Unretained(this)));
     if (rv == ERR_IO_PENDING) {
@@ -614,8 +728,7 @@
   } else {
     recv_buffer_ = new IOBuffer(nb);
     rv = transport_socket_->Read(
-        recv_buffer_.get(),
-        nb,
+        recv_buffer_.get(), nb,
         base::Bind(&SSLServerSocketNSS::BufferRecvComplete,
                    base::Unretained(this)));
     if (rv == ERR_IO_PENDING) {
@@ -838,8 +951,7 @@
 // static
 // NSS calls this when handshake is completed.
 // After the SSL handshake is finished we need to verify the certificate.
-void SSLServerSocketNSS::HandshakeCallback(PRFileDesc* socket,
-                                           void* arg) {
+void SSLServerSocketNSS::HandshakeCallback(PRFileDesc* socket, void* arg) {
   // TODO(hclam): Implement.
 }
 
@@ -854,4 +966,39 @@
   return OK;
 }
 
+}  // namespace
+
+scoped_ptr<SSLServerContext> CreateSSLServerContext(
+    X509Certificate* certificate,
+    const crypto::RSAPrivateKey& key,
+    const SSLServerConfig& ssl_server_config) {
+  return scoped_ptr<SSLServerContext>(
+      new SSLServerContextNSS(certificate, key, ssl_server_config));
+}
+
+SSLServerContextNSS::SSLServerContextNSS(
+    X509Certificate* certificate,
+    const crypto::RSAPrivateKey& key,
+    const SSLServerConfig& ssl_server_config)
+    : ssl_server_config_(ssl_server_config),
+      cert_(certificate),
+      key_(key.Copy()) {
+  CHECK(key_);
+}
+
+SSLServerContextNSS::~SSLServerContextNSS() {}
+
+scoped_ptr<SSLServerSocket> SSLServerContextNSS::CreateSSLServerSocket(
+    scoped_ptr<StreamSocket> socket) {
+  DCHECK(g_nss_server_sockets_init) << "EnableSSLServerSockets() has not been"
+                                    << " called yet!";
+
+  return scoped_ptr<SSLServerSocket>(new SSLServerSocketNSS(
+      std::move(socket), cert_.get(), *key_, ssl_server_config_));
+}
+
+void EnableSSLServerSockets() {
+  g_nss_ssl_server_init_singleton.Get();
+}
+
 }  // namespace net
diff --git a/net/socket/ssl_server_socket_nss.h b/net/socket/ssl_server_socket_nss.h
index 788e452..497d461 100644
--- a/net/socket/ssl_server_socket_nss.h
+++ b/net/socket/ssl_server_socket_nss.h
@@ -22,122 +22,17 @@
 
 namespace net {
 
-class SSLServerSocketNSS : public SSLServerSocket {
+class SSLServerContextNSS : public SSLServerContext {
  public:
-  // See comments on CreateSSLServerSocket for details of how these
-  // parameters are used.
-  SSLServerSocketNSS(scoped_ptr<StreamSocket> socket,
-                     scoped_refptr<X509Certificate> certificate,
-                     const crypto::RSAPrivateKey& key,
-                     const SSLServerConfig& ssl_server_config);
-  ~SSLServerSocketNSS() override;
+  SSLServerContextNSS(X509Certificate* certificate,
+                      const crypto::RSAPrivateKey& key,
+                      const SSLServerConfig& ssl_server_config);
+  ~SSLServerContextNSS() override;
 
-  // SSLServerSocket interface.
-  int Handshake(const CompletionCallback& callback) override;
-
-  // SSLSocket interface.
-  int ExportKeyingMaterial(const base::StringPiece& label,
-                           bool has_context,
-                           const base::StringPiece& context,
-                           unsigned char* out,
-                           unsigned int outlen) override;
-  int GetTLSUniqueChannelBinding(std::string* out) override;
-
-  // Socket interface (via StreamSocket).
-  int Read(IOBuffer* buf,
-           int buf_len,
-           const CompletionCallback& callback) override;
-  int Write(IOBuffer* buf,
-            int buf_len,
-            const CompletionCallback& callback) override;
-  int SetReceiveBufferSize(int32_t size) override;
-  int SetSendBufferSize(int32_t size) override;
-
-  // StreamSocket implementation.
-  int Connect(const CompletionCallback& callback) override;
-  void Disconnect() override;
-  bool IsConnected() const override;
-  bool IsConnectedAndIdle() const override;
-  int GetPeerAddress(IPEndPoint* address) const override;
-  int GetLocalAddress(IPEndPoint* address) const override;
-  const BoundNetLog& NetLog() const override;
-  void SetSubresourceSpeculation() override;
-  void SetOmniboxSpeculation() override;
-  bool WasEverUsed() const override;
-  bool UsingTCPFastOpen() const override;
-  bool WasNpnNegotiated() const override;
-  NextProto GetNegotiatedProtocol() const override;
-  bool GetSSLInfo(SSLInfo* ssl_info) override;
-  void GetConnectionAttempts(ConnectionAttempts* out) const override;
-  void ClearConnectionAttempts() override {}
-  void AddConnectionAttempts(const ConnectionAttempts& attempts) override {}
-  int64_t GetTotalReceivedBytes() const override;
+  scoped_ptr<SSLServerSocket> CreateSSLServerSocket(
+      scoped_ptr<StreamSocket> socket) override;
 
  private:
-  enum State {
-    STATE_NONE,
-    STATE_HANDSHAKE,
-  };
-
-  int InitializeSSLOptions();
-
-  void OnSendComplete(int result);
-  void OnRecvComplete(int result);
-  void OnHandshakeIOComplete(int result);
-
-  int BufferSend();
-  void BufferSendComplete(int result);
-  int BufferRecv();
-  void BufferRecvComplete(int result);
-  bool DoTransportIO();
-  int DoPayloadRead();
-  int DoPayloadWrite();
-
-  int DoHandshakeLoop(int last_io_result);
-  int DoReadLoop(int result);
-  int DoWriteLoop(int result);
-  int DoHandshake();
-  void DoHandshakeCallback(int result);
-  void DoReadCallback(int result);
-  void DoWriteCallback(int result);
-
-  static SECStatus OwnAuthCertHandler(void* arg,
-                                      PRFileDesc* socket,
-                                      PRBool checksig,
-                                      PRBool is_server);
-  static void HandshakeCallback(PRFileDesc* socket, void* arg);
-
-  int Init();
-
-  // Members used to send and receive buffer.
-  bool transport_send_busy_;
-  bool transport_recv_busy_;
-
-  scoped_refptr<IOBuffer> recv_buffer_;
-
-  BoundNetLog net_log_;
-
-  CompletionCallback user_handshake_callback_;
-  CompletionCallback user_read_callback_;
-  CompletionCallback user_write_callback_;
-
-  // Used by Read function.
-  scoped_refptr<IOBuffer> user_read_buf_;
-  int user_read_buf_len_;
-
-  // Used by Write function.
-  scoped_refptr<IOBuffer> user_write_buf_;
-  int user_write_buf_len_;
-
-  // The NSS SSL state machine
-  PRFileDesc* nss_fd_;
-
-  // Buffers for the network end of the SSL state machine
-  memio_Private* nss_bufs_;
-
-  // StreamSocket for sending and receiving data.
-  scoped_ptr<StreamSocket> transport_socket_;
-
   // Options for the SSL socket.
   SSLServerConfig ssl_server_config_;
 
@@ -146,11 +41,6 @@
 
   // Private key used by the server.
   scoped_ptr<crypto::RSAPrivateKey> key_;
-
-  State next_handshake_state_;
-  bool completed_handshake_;
-
-  DISALLOW_COPY_AND_ASSIGN(SSLServerSocketNSS);
 };
 
 }  // namespace net
diff --git a/net/socket/ssl_server_socket_openssl.cc b/net/socket/ssl_server_socket_openssl.cc
index adde711..75a76da 100644
--- a/net/socket/ssl_server_socket_openssl.cc
+++ b/net/socket/ssl_server_socket_openssl.cc
@@ -19,7 +19,6 @@
 #include "net/cert/client_cert_verifier.h"
 #include "net/cert/x509_util_openssl.h"
 #include "net/ssl/openssl_ssl_util.h"
-#include "net/ssl/scoped_openssl_types.h"
 #include "net/ssl/ssl_connection_status_flags.h"
 #include "net/ssl/ssl_info.h"
 
@@ -52,43 +51,142 @@
   return X509Certificate::CreateFromDERCertChain(der_chain);
 }
 
-}  // namespace
+class SSLServerSocketOpenSSL : public SSLServerSocket {
+ public:
+  // See comments on CreateSSLServerSocket for details of how these
+  // parameters are used.
+  SSLServerSocketOpenSSL(scoped_ptr<StreamSocket> socket, SSL* ssl);
+  ~SSLServerSocketOpenSSL() override;
 
-void EnableSSLServerSockets() {
-  // No-op because CreateSSLServerSocket() calls crypto::EnsureOpenSSLInit().
-}
+  // SSLServerSocket interface.
+  int Handshake(const CompletionCallback& callback) override;
 
-scoped_ptr<SSLServerSocket> CreateSSLServerSocket(
-    scoped_ptr<StreamSocket> socket,
-    X509Certificate* certificate,
-    const crypto::RSAPrivateKey& key,
-    const SSLServerConfig& ssl_server_config) {
-  crypto::EnsureOpenSSLInit();
-  return scoped_ptr<SSLServerSocket>(new SSLServerSocketOpenSSL(
-      std::move(socket), certificate, key, ssl_server_config));
-}
+  // SSLSocket interface.
+  int ExportKeyingMaterial(const base::StringPiece& label,
+                           bool has_context,
+                           const base::StringPiece& context,
+                           unsigned char* out,
+                           unsigned int outlen) override;
+  int GetTLSUniqueChannelBinding(std::string* out) override;
+
+  // Socket interface (via StreamSocket).
+  int Read(IOBuffer* buf,
+           int buf_len,
+           const CompletionCallback& callback) override;
+  int Write(IOBuffer* buf,
+            int buf_len,
+            const CompletionCallback& callback) override;
+  int SetReceiveBufferSize(int32_t size) override;
+  int SetSendBufferSize(int32_t size) override;
+
+  // StreamSocket implementation.
+  int Connect(const CompletionCallback& callback) override;
+  void Disconnect() override;
+  bool IsConnected() const override;
+  bool IsConnectedAndIdle() const override;
+  int GetPeerAddress(IPEndPoint* address) const override;
+  int GetLocalAddress(IPEndPoint* address) const override;
+  const BoundNetLog& NetLog() const override;
+  void SetSubresourceSpeculation() override;
+  void SetOmniboxSpeculation() override;
+  bool WasEverUsed() const override;
+  bool UsingTCPFastOpen() const override;
+  bool WasNpnNegotiated() const override;
+  NextProto GetNegotiatedProtocol() const override;
+  bool GetSSLInfo(SSLInfo* ssl_info) override;
+  void GetConnectionAttempts(ConnectionAttempts* out) const override;
+  void ClearConnectionAttempts() override {}
+  void AddConnectionAttempts(const ConnectionAttempts& attempts) override {}
+  int64_t GetTotalReceivedBytes() const override;
+  static int CertVerifyCallback(X509_STORE_CTX* store_ctx, void* arg);
+
+ private:
+  enum State {
+    STATE_NONE,
+    STATE_HANDSHAKE,
+  };
+
+  void OnSendComplete(int result);
+  void OnRecvComplete(int result);
+  void OnHandshakeIOComplete(int result);
+
+  int BufferSend();
+  void BufferSendComplete(int result);
+  void TransportWriteComplete(int result);
+  int BufferRecv();
+  void BufferRecvComplete(int result);
+  int TransportReadComplete(int result);
+  bool DoTransportIO();
+  int DoPayloadRead();
+  int DoPayloadWrite();
+
+  int DoHandshakeLoop(int last_io_result);
+  int DoReadLoop(int result);
+  int DoWriteLoop(int result);
+  int DoHandshake();
+  void DoHandshakeCallback(int result);
+  void DoReadCallback(int result);
+  void DoWriteCallback(int result);
+
+  int Init();
+  void ExtractClientCert();
+
+  // Members used to send and receive buffer.
+  bool transport_send_busy_;
+  bool transport_recv_busy_;
+  bool transport_recv_eof_;
+
+  scoped_refptr<DrainableIOBuffer> send_buffer_;
+  scoped_refptr<IOBuffer> recv_buffer_;
+
+  BoundNetLog net_log_;
+
+  CompletionCallback user_handshake_callback_;
+  CompletionCallback user_read_callback_;
+  CompletionCallback user_write_callback_;
+
+  // Used by Read function.
+  scoped_refptr<IOBuffer> user_read_buf_;
+  int user_read_buf_len_;
+
+  // Used by Write function.
+  scoped_refptr<IOBuffer> user_write_buf_;
+  int user_write_buf_len_;
+
+  // Used by TransportWriteComplete() and TransportReadComplete() to signify an
+  // error writing to the transport socket. A value of OK indicates no error.
+  int transport_write_error_;
+
+  // OpenSSL stuff
+  SSL* ssl_;
+  BIO* transport_bio_;
+
+  // StreamSocket for sending and receiving data.
+  scoped_ptr<StreamSocket> transport_socket_;
+
+  // Certificate for the client.
+  scoped_refptr<X509Certificate> client_cert_;
+
+  State next_handshake_state_;
+  bool completed_handshake_;
+
+  DISALLOW_COPY_AND_ASSIGN(SSLServerSocketOpenSSL);
+};
 
 SSLServerSocketOpenSSL::SSLServerSocketOpenSSL(
     scoped_ptr<StreamSocket> transport_socket,
-    scoped_refptr<X509Certificate> certificate,
-    const crypto::RSAPrivateKey& key,
-    const SSLServerConfig& ssl_server_config)
+    SSL* ssl)
     : transport_send_busy_(false),
       transport_recv_busy_(false),
       transport_recv_eof_(false),
       user_read_buf_len_(0),
       user_write_buf_len_(0),
       transport_write_error_(OK),
-      ssl_(NULL),
+      ssl_(ssl),
       transport_bio_(NULL),
       transport_socket_(std::move(transport_socket)),
-      ssl_server_config_(ssl_server_config),
-      cert_(certificate),
-      key_(key.Copy()),
       next_handshake_state_(STATE_NONE),
-      completed_handshake_(false) {
-  CHECK(key_);
-}
+      completed_handshake_(false) {}
 
 SSLServerSocketOpenSSL::~SSLServerSocketOpenSSL() {
   if (ssl_) {
@@ -160,7 +258,8 @@
   return ERR_NOT_IMPLEMENTED;
 }
 
-int SSLServerSocketOpenSSL::Read(IOBuffer* buf, int buf_len,
+int SSLServerSocketOpenSSL::Read(IOBuffer* buf,
+                                 int buf_len,
                                  const CompletionCallback& callback) {
   DCHECK(user_read_callback_.is_null());
   DCHECK(user_handshake_callback_.is_null());
@@ -184,7 +283,8 @@
   return rv;
 }
 
-int SSLServerSocketOpenSSL::Write(IOBuffer* buf, int buf_len,
+int SSLServerSocketOpenSSL::Write(IOBuffer* buf,
+                                  int buf_len,
                                   const CompletionCallback& callback) {
   DCHECK(user_write_callback_.is_null());
   DCHECK(!user_write_buf_);
@@ -377,8 +477,7 @@
   }
 
   int rv = transport_socket_->Write(
-      send_buffer_.get(),
-      send_buffer_->BytesRemaining(),
+      send_buffer_.get(), send_buffer_->BytesRemaining(),
       base::Bind(&SSLServerSocketOpenSSL::BufferSendComplete,
                  base::Unretained(this)));
   if (rv == ERR_IO_PENDING) {
@@ -450,8 +549,7 @@
 
   recv_buffer_ = new IOBuffer(max_write);
   int rv = transport_socket_->Read(
-      recv_buffer_.get(),
-      max_write,
+      recv_buffer_.get(), max_write,
       base::Bind(&SSLServerSocketOpenSSL::BufferRecvComplete,
                  base::Unretained(this)));
   if (rv == ERR_IO_PENDING) {
@@ -681,27 +779,10 @@
 }
 
 int SSLServerSocketOpenSSL::Init() {
-  DCHECK(!ssl_);
   DCHECK(!transport_bio_);
 
   crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
 
-  ScopedSSL_CTX ssl_ctx(SSL_CTX_new(TLS_method()));
-  int verify_mode = 0;
-  switch (ssl_server_config_.client_cert_type) {
-    case SSLServerConfig::ClientCertType::REQUIRE_CLIENT_CERT:
-      verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
-    // Fall-through
-    case SSLServerConfig::ClientCertType::OPTIONAL_CLIENT_CERT:
-      verify_mode |= SSL_VERIFY_PEER;
-      SSL_CTX_set_verify(ssl_ctx.get(), verify_mode, nullptr);
-      SSL_CTX_set_cert_verify_callback(ssl_ctx.get(), CertVerifyCallback,
-                                       ssl_server_config_.client_cert_verifier);
-      break;
-    case SSLServerConfig::ClientCertType::NO_CLIENT_CERT:
-      break;
-  }
-  ssl_ = SSL_new(ssl_ctx.get());
   if (!ssl_)
     return ERR_UNEXPECTED;
 
@@ -714,100 +795,6 @@
 
   SSL_set_bio(ssl_, ssl_bio, ssl_bio);
 
-  // Set certificate and private key.
-  DCHECK(cert_->os_cert_handle());
-#if defined(USE_OPENSSL_CERTS)
-  if (SSL_use_certificate(ssl_, cert_->os_cert_handle()) != 1) {
-    LOG(ERROR) << "Cannot set certificate.";
-    return ERR_UNEXPECTED;
-  }
-#else
-  // Convert OSCertHandle to X509 structure.
-  std::string der_string;
-  if (!X509Certificate::GetDEREncoded(cert_->os_cert_handle(), &der_string))
-    return ERR_UNEXPECTED;
-
-  const unsigned char* der_string_array =
-      reinterpret_cast<const unsigned char*>(der_string.data());
-
-  ScopedX509 x509(d2i_X509(NULL, &der_string_array, der_string.length()));
-  if (!x509)
-    return ERR_UNEXPECTED;
-
-  // On success, SSL_use_certificate acquires a reference to |x509|.
-  if (SSL_use_certificate(ssl_, x509.get()) != 1) {
-    LOG(ERROR) << "Cannot set certificate.";
-    return ERR_UNEXPECTED;
-  }
-#endif  // USE_OPENSSL_CERTS
-
-  DCHECK(key_->key());
-  if (SSL_use_PrivateKey(ssl_, key_->key()) != 1) {
-    LOG(ERROR) << "Cannot set private key.";
-    return ERR_UNEXPECTED;
-  }
-
-  DCHECK_LT(SSL3_VERSION, ssl_server_config_.version_min);
-  DCHECK_LT(SSL3_VERSION, ssl_server_config_.version_max);
-  SSL_set_min_version(ssl_, ssl_server_config_.version_min);
-  SSL_set_max_version(ssl_, ssl_server_config_.version_max);
-
-  // OpenSSL defaults some options to on, others to off. To avoid ambiguity,
-  // set everything we care about to an absolute value.
-  SslSetClearMask options;
-  options.ConfigureFlag(SSL_OP_NO_COMPRESSION, true);
-
-  SSL_set_options(ssl_, options.set_mask);
-  SSL_clear_options(ssl_, options.clear_mask);
-
-  // Same as above, this time for the SSL mode.
-  SslSetClearMask mode;
-
-  mode.ConfigureFlag(SSL_MODE_RELEASE_BUFFERS, true);
-
-  SSL_set_mode(ssl_, mode.set_mask);
-  SSL_clear_mode(ssl_, mode.clear_mask);
-
-  // See SSLServerConfig::disabled_cipher_suites for description of the suites
-  // disabled by default. Note that !SHA256 and !SHA384 only remove HMAC-SHA256
-  // and HMAC-SHA384 cipher suites, not GCM cipher suites with SHA256 or SHA384
-  // as the handshake hash.
-  std::string command("DEFAULT:!SHA256:!SHA384:!AESGCM+AES256:!aPSK");
-
-  if (ssl_server_config_.require_ecdhe)
-    command.append(":!kRSA:!kDHE");
-
-  // Remove any disabled ciphers.
-  for (uint16_t id : ssl_server_config_.disabled_cipher_suites) {
-    const SSL_CIPHER* cipher = SSL_get_cipher_by_value(id);
-    if (cipher) {
-      command.append(":!");
-      command.append(SSL_CIPHER_get_name(cipher));
-    }
-  }
-
-  int rv = SSL_set_cipher_list(ssl_, command.c_str());
-  // If this fails (rv = 0) it means there are no ciphers enabled on this SSL.
-  // This will almost certainly result in the socket failing to complete the
-  // handshake at which point the appropriate error is bubbled up to the client.
-  LOG_IF(WARNING, rv != 1) << "SSL_set_cipher_list('" << command
-                           << "') returned " << rv;
-
-  if (ssl_server_config_.client_cert_type !=
-          SSLServerConfig::ClientCertType::NO_CLIENT_CERT &&
-      !ssl_server_config_.cert_authorities_.empty()) {
-    ScopedX509NameStack stack(sk_X509_NAME_new_null());
-    for (const auto& authority : ssl_server_config_.cert_authorities_) {
-      const uint8_t* name = reinterpret_cast<const uint8_t*>(authority.c_str());
-      const uint8_t* name_start = name;
-      ScopedX509_NAME subj(d2i_X509_NAME(nullptr, &name, authority.length()));
-      if (!subj || name != name_start + authority.length())
-        return ERR_UNEXPECTED;
-      sk_X509_NAME_push(stack.get(), subj.release());
-    }
-    SSL_set_client_CA_list(ssl_, stack.release());
-  }
-
   return OK;
 }
 
@@ -841,4 +828,141 @@
   return 1;
 }
 
+}  // namespace
+
+scoped_ptr<SSLServerContext> CreateSSLServerContext(
+    X509Certificate* certificate,
+    const crypto::RSAPrivateKey& key,
+    const SSLServerConfig& ssl_server_config) {
+  return scoped_ptr<SSLServerContext>(
+      new SSLServerContextOpenSSL(certificate, key, ssl_server_config));
+}
+
+SSLServerContextOpenSSL::SSLServerContextOpenSSL(
+    X509Certificate* certificate,
+    const crypto::RSAPrivateKey& key,
+    const SSLServerConfig& ssl_server_config)
+    : ssl_server_config_(ssl_server_config),
+      cert_(certificate),
+      key_(key.Copy()) {
+  CHECK(key_);
+  crypto::EnsureOpenSSLInit();
+  ssl_ctx_.reset(SSL_CTX_new(TLS_method()));
+  SSL_CTX_set_session_cache_mode(ssl_ctx_.get(), SSL_SESS_CACHE_SERVER);
+  uint8_t session_ctx_id = 0;
+  SSL_CTX_set_session_id_context(ssl_ctx_.get(), &session_ctx_id,
+                                 sizeof(session_ctx_id));
+
+  int verify_mode = 0;
+  switch (ssl_server_config_.client_cert_type) {
+    case SSLServerConfig::ClientCertType::REQUIRE_CLIENT_CERT:
+      verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+    // Fall-through
+    case SSLServerConfig::ClientCertType::OPTIONAL_CLIENT_CERT:
+      verify_mode |= SSL_VERIFY_PEER;
+      SSL_CTX_set_verify(ssl_ctx_.get(), verify_mode, nullptr);
+      SSL_CTX_set_cert_verify_callback(
+          ssl_ctx_.get(), SSLServerSocketOpenSSL::CertVerifyCallback,
+          ssl_server_config_.client_cert_verifier);
+      break;
+    case SSLServerConfig::ClientCertType::NO_CLIENT_CERT:
+      break;
+  }
+
+  // Set certificate and private key.
+  DCHECK(cert_->os_cert_handle());
+#if defined(USE_OPENSSL_CERTS)
+  CHECK(SSL_CTX_use_certificate(ssl_ctx_.get(), cert_->os_cert_handle()));
+#else
+  // Convert OSCertHandle to X509 structure.
+  std::string der_string;
+  CHECK(X509Certificate::GetDEREncoded(cert_->os_cert_handle(), &der_string));
+
+  const unsigned char* der_string_array =
+      reinterpret_cast<const unsigned char*>(der_string.data());
+
+  ScopedX509 x509(d2i_X509(NULL, &der_string_array, der_string.length()));
+  CHECK(x509);
+
+  // On success, SSL_CTX_use_certificate acquires a reference to |x509|.
+  CHECK(SSL_CTX_use_certificate(ssl_ctx_.get(), x509.get()));
+#endif  // USE_OPENSSL_CERTS
+
+  DCHECK(key_->key());
+  CHECK(SSL_CTX_use_PrivateKey(ssl_ctx_.get(), key_->key()));
+
+  DCHECK_LT(SSL3_VERSION, ssl_server_config_.version_min);
+  DCHECK_LT(SSL3_VERSION, ssl_server_config_.version_max);
+  SSL_CTX_set_min_version(ssl_ctx_.get(), ssl_server_config_.version_min);
+  SSL_CTX_set_max_version(ssl_ctx_.get(), ssl_server_config_.version_max);
+
+  // OpenSSL defaults some options to on, others to off. To avoid ambiguity,
+  // set everything we care about to an absolute value.
+  SslSetClearMask options;
+  options.ConfigureFlag(SSL_OP_NO_COMPRESSION, true);
+
+  SSL_CTX_set_options(ssl_ctx_.get(), options.set_mask);
+  SSL_CTX_clear_options(ssl_ctx_.get(), options.clear_mask);
+
+  // Same as above, this time for the SSL mode.
+  SslSetClearMask mode;
+
+  mode.ConfigureFlag(SSL_MODE_RELEASE_BUFFERS, true);
+
+  SSL_CTX_set_mode(ssl_ctx_.get(), mode.set_mask);
+  SSL_CTX_clear_mode(ssl_ctx_.get(), mode.clear_mask);
+
+  // See SSLServerConfig::disabled_cipher_suites for description of the suites
+  // disabled by default. Note that !SHA256 and !SHA384 only remove HMAC-SHA256
+  // and HMAC-SHA384 cipher suites, not GCM cipher suites with SHA256 or SHA384
+  // as the handshake hash.
+  std::string command("DEFAULT:!SHA256:!SHA384:!AESGCM+AES256:!aPSK");
+
+  if (ssl_server_config_.require_ecdhe)
+    command.append(":!kRSA:!kDHE");
+
+  // Remove any disabled ciphers.
+  for (uint16_t id : ssl_server_config_.disabled_cipher_suites) {
+    const SSL_CIPHER* cipher = SSL_get_cipher_by_value(id);
+    if (cipher) {
+      command.append(":!");
+      command.append(SSL_CIPHER_get_name(cipher));
+    }
+  }
+
+  int rv = SSL_CTX_set_cipher_list(ssl_ctx_.get(), command.c_str());
+  // If this fails (rv = 0) it means there are no ciphers enabled on this SSL.
+  // This will almost certainly result in the socket failing to complete the
+  // handshake at which point the appropriate error is bubbled up to the client.
+  LOG_IF(WARNING, rv != 1) << "SSL_set_cipher_list('" << command
+                           << "') returned " << rv;
+
+  if (ssl_server_config_.client_cert_type !=
+          SSLServerConfig::ClientCertType::NO_CLIENT_CERT &&
+      !ssl_server_config_.cert_authorities_.empty()) {
+    ScopedX509NameStack stack(sk_X509_NAME_new_null());
+    for (const auto& authority : ssl_server_config_.cert_authorities_) {
+      const uint8_t* name = reinterpret_cast<const uint8_t*>(authority.c_str());
+      const uint8_t* name_start = name;
+      ScopedX509_NAME subj(d2i_X509_NAME(nullptr, &name, authority.length()));
+      CHECK(subj && name == name_start + authority.length());
+      sk_X509_NAME_push(stack.get(), subj.release());
+    }
+    SSL_CTX_set_client_CA_list(ssl_ctx_.get(), stack.release());
+  }
+}
+
+SSLServerContextOpenSSL::~SSLServerContextOpenSSL() {}
+
+scoped_ptr<SSLServerSocket> SSLServerContextOpenSSL::CreateSSLServerSocket(
+    scoped_ptr<StreamSocket> socket) {
+  SSL* ssl = SSL_new(ssl_ctx_.get());
+  return scoped_ptr<SSLServerSocket>(
+      new SSLServerSocketOpenSSL(std::move(socket), ssl));
+}
+
+void EnableSSLServerSockets() {
+  // No-op because CreateSSLServerSocket() calls crypto::EnsureOpenSSLInit().
+}
+
 }  // namespace net
diff --git a/net/socket/ssl_server_socket_openssl.h b/net/socket/ssl_server_socket_openssl.h
index 52f8241b..3a9d9c85 100644
--- a/net/socket/ssl_server_socket_openssl.h
+++ b/net/socket/ssl_server_socket_openssl.h
@@ -13,6 +13,7 @@
 #include "net/base/io_buffer.h"
 #include "net/log/net_log.h"
 #include "net/socket/ssl_server_socket.h"
+#include "net/ssl/scoped_openssl_types.h"
 #include "net/ssl/ssl_server_config.h"
 
 // Avoid including misc OpenSSL headers, i.e.:
@@ -26,120 +27,18 @@
 
 class SSLInfo;
 
-class SSLServerSocketOpenSSL : public SSLServerSocket {
+class SSLServerContextOpenSSL : public SSLServerContext {
  public:
-  // See comments on CreateSSLServerSocket for details of how these
-  // parameters are used.
-  SSLServerSocketOpenSSL(scoped_ptr<StreamSocket> socket,
-                         scoped_refptr<X509Certificate> certificate,
-                         const crypto::RSAPrivateKey& key,
-                         const SSLServerConfig& ssl_server_config);
-  ~SSLServerSocketOpenSSL() override;
+  SSLServerContextOpenSSL(X509Certificate* certificate,
+                          const crypto::RSAPrivateKey& key,
+                          const SSLServerConfig& ssl_server_config);
+  ~SSLServerContextOpenSSL() override;
 
-  // SSLServerSocket interface.
-  int Handshake(const CompletionCallback& callback) override;
-
-  // SSLSocket interface.
-  int ExportKeyingMaterial(const base::StringPiece& label,
-                           bool has_context,
-                           const base::StringPiece& context,
-                           unsigned char* out,
-                           unsigned int outlen) override;
-  int GetTLSUniqueChannelBinding(std::string* out) override;
-
-  // Socket interface (via StreamSocket).
-  int Read(IOBuffer* buf,
-           int buf_len,
-           const CompletionCallback& callback) override;
-  int Write(IOBuffer* buf,
-            int buf_len,
-            const CompletionCallback& callback) override;
-  int SetReceiveBufferSize(int32_t size) override;
-  int SetSendBufferSize(int32_t size) override;
-
-  // StreamSocket implementation.
-  int Connect(const CompletionCallback& callback) override;
-  void Disconnect() override;
-  bool IsConnected() const override;
-  bool IsConnectedAndIdle() const override;
-  int GetPeerAddress(IPEndPoint* address) const override;
-  int GetLocalAddress(IPEndPoint* address) const override;
-  const BoundNetLog& NetLog() const override;
-  void SetSubresourceSpeculation() override;
-  void SetOmniboxSpeculation() override;
-  bool WasEverUsed() const override;
-  bool UsingTCPFastOpen() const override;
-  bool WasNpnNegotiated() const override;
-  NextProto GetNegotiatedProtocol() const override;
-  bool GetSSLInfo(SSLInfo* ssl_info) override;
-  void GetConnectionAttempts(ConnectionAttempts* out) const override;
-  void ClearConnectionAttempts() override {}
-  void AddConnectionAttempts(const ConnectionAttempts& attempts) override {}
-  int64_t GetTotalReceivedBytes() const override;
+  scoped_ptr<SSLServerSocket> CreateSSLServerSocket(
+      scoped_ptr<StreamSocket> socket) override;
 
  private:
-  enum State {
-    STATE_NONE,
-    STATE_HANDSHAKE,
-  };
-
-  void OnSendComplete(int result);
-  void OnRecvComplete(int result);
-  void OnHandshakeIOComplete(int result);
-
-  int BufferSend();
-  void BufferSendComplete(int result);
-  void TransportWriteComplete(int result);
-  int BufferRecv();
-  void BufferRecvComplete(int result);
-  int TransportReadComplete(int result);
-  bool DoTransportIO();
-  int DoPayloadRead();
-  int DoPayloadWrite();
-
-  int DoHandshakeLoop(int last_io_result);
-  int DoReadLoop(int result);
-  int DoWriteLoop(int result);
-  int DoHandshake();
-  void DoHandshakeCallback(int result);
-  void DoReadCallback(int result);
-  void DoWriteCallback(int result);
-
-  int Init();
-  static int CertVerifyCallback(X509_STORE_CTX* store_ctx, void* arg);
-
-  // Members used to send and receive buffer.
-  bool transport_send_busy_;
-  bool transport_recv_busy_;
-  bool transport_recv_eof_;
-
-  scoped_refptr<DrainableIOBuffer> send_buffer_;
-  scoped_refptr<IOBuffer> recv_buffer_;
-
-  BoundNetLog net_log_;
-
-  CompletionCallback user_handshake_callback_;
-  CompletionCallback user_read_callback_;
-  CompletionCallback user_write_callback_;
-
-  // Used by Read function.
-  scoped_refptr<IOBuffer> user_read_buf_;
-  int user_read_buf_len_;
-
-  // Used by Write function.
-  scoped_refptr<IOBuffer> user_write_buf_;
-  int user_write_buf_len_;
-
-  // Used by TransportWriteComplete() and TransportReadComplete() to signify an
-  // error writing to the transport socket. A value of OK indicates no error.
-  int transport_write_error_;
-
-  // OpenSSL stuff
-  SSL* ssl_;
-  BIO* transport_bio_;
-
-  // StreamSocket for sending and receiving data.
-  scoped_ptr<StreamSocket> transport_socket_;
+  ScopedSSL_CTX ssl_ctx_;
 
   // Options for the SSL socket.
   SSLServerConfig ssl_server_config_;
@@ -149,14 +48,6 @@
 
   // Private key used by the server.
   scoped_ptr<crypto::RSAPrivateKey> key_;
-
-  // Certificate for the client.
-  scoped_refptr<X509Certificate> client_cert_;
-
-  State next_handshake_state_;
-  bool completed_handshake_;
-
-  DISALLOW_COPY_AND_ASSIGN(SSLServerSocketOpenSSL);
 };
 
 }  // namespace net
diff --git a/net/socket/ssl_server_socket_unittest.cc b/net/socket/ssl_server_socket_unittest.cc
index 9a2dd9c..52ae7d8 100644
--- a/net/socket/ssl_server_socket_unittest.cc
+++ b/net/socket/ssl_server_socket_unittest.cc
@@ -204,9 +204,7 @@
  public:
   FakeSocket(FakeDataChannel* incoming_channel,
              FakeDataChannel* outgoing_channel)
-      : incoming_(incoming_channel),
-        outgoing_(outgoing_channel) {
-  }
+      : incoming_(incoming_channel), outgoing_(outgoing_channel) {}
 
   ~FakeSocket() override {}
 
@@ -340,20 +338,10 @@
         transport_security_state_(new TransportSecurityState) {
     cert_verifier_->set_default_result(ERR_CERT_AUTHORITY_INVALID);
     client_cert_verifier_->set_default_result(ERR_CERT_AUTHORITY_INVALID);
-  }
 
- protected:
-  void Initialize() {
-    scoped_ptr<ClientSocketHandle> client_connection(new ClientSocketHandle);
-    client_connection->SetSocket(
-        scoped_ptr<StreamSocket>(new FakeSocket(&channel_1_, &channel_2_)));
-    scoped_ptr<StreamSocket> server_socket(
-        new FakeSocket(&channel_2_, &channel_1_));
-
-    scoped_refptr<X509Certificate> server_cert(
-        ImportCertFromFile(GetTestCertsDirectory(), "unittest.selfsigned.der"));
-    scoped_ptr<crypto::RSAPrivateKey> server_private_key(
-        ReadTestKey("unittest.key.bin"));
+    server_cert_ =
+        ImportCertFromFile(GetTestCertsDirectory(), "unittest.selfsigned.der");
+    server_private_key_ = ReadTestKey("unittest.key.bin");
 
     client_ssl_config_.false_start_enabled = false;
     client_ssl_config_.channel_id_enabled = false;
@@ -362,22 +350,44 @@
     SSLConfig::CertAndStatus cert_and_status;
     cert_and_status.cert_status = CERT_STATUS_AUTHORITY_INVALID;
     std::string server_cert_der;
-    CHECK(X509Certificate::GetDEREncoded(server_cert->os_cert_handle(),
+    CHECK(X509Certificate::GetDEREncoded(server_cert_->os_cert_handle(),
                                          &server_cert_der));
     cert_and_status.der_cert = server_cert_der;
     client_ssl_config_.allowed_bad_certs.push_back(cert_and_status);
+  }
+
+ protected:
+  void CreateContext() {
+    client_socket_.reset();
+    server_socket_.reset();
+    channel_1_.reset();
+    channel_2_.reset();
+    server_context_.reset();
+    server_context_ = CreateSSLServerContext(
+        server_cert_.get(), *server_private_key_, server_ssl_config_);
+  }
+
+  void CreateSockets() {
+    client_socket_.reset();
+    server_socket_.reset();
+    channel_1_.reset(new FakeDataChannel());
+    channel_2_.reset(new FakeDataChannel());
+    scoped_ptr<ClientSocketHandle> client_connection(new ClientSocketHandle);
+    client_connection->SetSocket(scoped_ptr<StreamSocket>(
+        new FakeSocket(channel_1_.get(), channel_2_.get())));
+    scoped_ptr<StreamSocket> server_socket(
+        new FakeSocket(channel_2_.get(), channel_1_.get()));
 
     HostPortPair host_and_pair("unittest", 0);
     SSLClientSocketContext context;
     context.cert_verifier = cert_verifier_.get();
     context.transport_security_state = transport_security_state_.get();
-    socket_factory_->ClearSSLSessionCache();
     client_socket_ = socket_factory_->CreateSSLClientSocket(
         std::move(client_connection), host_and_pair, client_ssl_config_,
         context);
+
     server_socket_ =
-        CreateSSLServerSocket(std::move(server_socket), server_cert.get(),
-                              *server_private_key, server_ssl_config_);
+        server_context_->CreateSSLServerSocket(std::move(server_socket));
   }
 
 #if defined(USE_OPENSSL)
@@ -434,8 +444,8 @@
   }
 #endif
 
-  FakeDataChannel channel_1_;
-  FakeDataChannel channel_2_;
+  scoped_ptr<FakeDataChannel> channel_1_;
+  scoped_ptr<FakeDataChannel> channel_2_;
   SSLConfig client_ssl_config_;
   SSLServerConfig server_ssl_config_;
   scoped_ptr<SSLClientSocket> client_socket_;
@@ -444,20 +454,25 @@
   scoped_ptr<MockCertVerifier> cert_verifier_;
   scoped_ptr<MockClientCertVerifier> client_cert_verifier_;
   scoped_ptr<TransportSecurityState> transport_security_state_;
+  scoped_ptr<SSLServerContext> server_context_;
+  scoped_ptr<crypto::RSAPrivateKey> server_private_key_;
+  scoped_refptr<X509Certificate> server_cert_;
 };
 
 // This test only executes creation of client and server sockets. This is to
 // test that creation of sockets doesn't crash and have minimal code to run
 // under valgrind in order to help debugging memory problems.
 TEST_F(SSLServerSocketTest, Initialize) {
-  Initialize();
+  CreateContext();
+  CreateSockets();
 }
 
 // This test executes Connect() on SSLClientSocket and Handshake() on
 // SSLServerSocket to make sure handshaking between the two sockets is
 // completed successfully.
 TEST_F(SSLServerSocketTest, Handshake) {
-  Initialize();
+  CreateContext();
+  CreateSockets();
 
   TestCompletionCallback handshake_callback;
   int server_ret = server_socket_->Handshake(handshake_callback.callback());
@@ -489,9 +504,107 @@
   EXPECT_TRUE(is_aead);
 }
 
-// NSS ports don't support client certificates.
+// NSS ports don't support client certificates and have a global session cache.
 #if defined(USE_OPENSSL)
 
+// This test makes sure the session cache is working.
+TEST_F(SSLServerSocketTest, HandshakeCached) {
+  CreateContext();
+  CreateSockets();
+
+  TestCompletionCallback handshake_callback;
+  int server_ret = server_socket_->Handshake(handshake_callback.callback());
+
+  TestCompletionCallback connect_callback;
+  int client_ret = client_socket_->Connect(connect_callback.callback());
+
+  client_ret = connect_callback.GetResult(client_ret);
+  server_ret = handshake_callback.GetResult(server_ret);
+
+  ASSERT_EQ(OK, client_ret);
+  ASSERT_EQ(OK, server_ret);
+
+  // Make sure the cert status is expected.
+  SSLInfo ssl_info;
+  ASSERT_TRUE(client_socket_->GetSSLInfo(&ssl_info));
+  EXPECT_EQ(ssl_info.handshake_type, SSLInfo::HANDSHAKE_FULL);
+  SSLInfo ssl_server_info;
+  ASSERT_TRUE(server_socket_->GetSSLInfo(&ssl_server_info));
+  EXPECT_EQ(ssl_server_info.handshake_type, SSLInfo::HANDSHAKE_FULL);
+
+  // Make sure the second connection is cached.
+  CreateSockets();
+  TestCompletionCallback handshake_callback2;
+  int server_ret2 = server_socket_->Handshake(handshake_callback2.callback());
+
+  TestCompletionCallback connect_callback2;
+  int client_ret2 = client_socket_->Connect(connect_callback2.callback());
+
+  client_ret2 = connect_callback2.GetResult(client_ret2);
+  server_ret2 = handshake_callback2.GetResult(server_ret2);
+
+  ASSERT_EQ(OK, client_ret2);
+  ASSERT_EQ(OK, server_ret2);
+
+  // Make sure the cert status is expected.
+  SSLInfo ssl_info2;
+  ASSERT_TRUE(client_socket_->GetSSLInfo(&ssl_info2));
+  EXPECT_EQ(ssl_info2.handshake_type, SSLInfo::HANDSHAKE_RESUME);
+  SSLInfo ssl_server_info2;
+  ASSERT_TRUE(server_socket_->GetSSLInfo(&ssl_server_info2));
+  EXPECT_EQ(ssl_server_info2.handshake_type, SSLInfo::HANDSHAKE_RESUME);
+}
+
+// This test makes sure the session cache separates out by server context.
+TEST_F(SSLServerSocketTest, HandshakeCachedContextSwitch) {
+  CreateContext();
+  CreateSockets();
+
+  TestCompletionCallback handshake_callback;
+  int server_ret = server_socket_->Handshake(handshake_callback.callback());
+
+  TestCompletionCallback connect_callback;
+  int client_ret = client_socket_->Connect(connect_callback.callback());
+
+  client_ret = connect_callback.GetResult(client_ret);
+  server_ret = handshake_callback.GetResult(server_ret);
+
+  ASSERT_EQ(OK, client_ret);
+  ASSERT_EQ(OK, server_ret);
+
+  // Make sure the cert status is expected.
+  SSLInfo ssl_info;
+  ASSERT_TRUE(client_socket_->GetSSLInfo(&ssl_info));
+  EXPECT_EQ(ssl_info.handshake_type, SSLInfo::HANDSHAKE_FULL);
+  SSLInfo ssl_server_info;
+  ASSERT_TRUE(server_socket_->GetSSLInfo(&ssl_server_info));
+  EXPECT_EQ(ssl_server_info.handshake_type, SSLInfo::HANDSHAKE_FULL);
+
+  // Make sure the second connection is NOT cached when using a new context.
+  CreateContext();
+  CreateSockets();
+
+  TestCompletionCallback handshake_callback2;
+  int server_ret2 = server_socket_->Handshake(handshake_callback2.callback());
+
+  TestCompletionCallback connect_callback2;
+  int client_ret2 = client_socket_->Connect(connect_callback2.callback());
+
+  client_ret2 = connect_callback2.GetResult(client_ret2);
+  server_ret2 = handshake_callback2.GetResult(server_ret2);
+
+  ASSERT_EQ(OK, client_ret2);
+  ASSERT_EQ(OK, server_ret2);
+
+  // Make sure the cert status is expected.
+  SSLInfo ssl_info2;
+  ASSERT_TRUE(client_socket_->GetSSLInfo(&ssl_info2));
+  EXPECT_EQ(ssl_info2.handshake_type, SSLInfo::HANDSHAKE_FULL);
+  SSLInfo ssl_server_info2;
+  ASSERT_TRUE(server_socket_->GetSSLInfo(&ssl_server_info2));
+  EXPECT_EQ(ssl_server_info2.handshake_type, SSLInfo::HANDSHAKE_FULL);
+}
+
 // This test executes Connect() on SSLClientSocket and Handshake() on
 // SSLServerSocket to make sure handshaking between the two sockets is
 // completed successfully, using client certificate.
@@ -500,7 +613,8 @@
       ImportCertFromFile(GetTestCertsDirectory(), kClientCertFileName);
   ConfigureClientCertsForClient(kClientCertFileName, kClientPrivateKeyFileName);
   ConfigureClientCertsForServer();
-  Initialize();
+  CreateContext();
+  CreateSockets();
 
   TestCompletionCallback handshake_callback;
   int server_ret = server_socket_->Handshake(handshake_callback.callback());
@@ -523,9 +637,71 @@
   EXPECT_TRUE(client_cert->Equals(ssl_info.cert.get()));
 }
 
+// This test executes Connect() on SSLClientSocket and Handshake() twice on
+// SSLServerSocket to make sure handshaking between the two sockets is
+// completed successfully, using client certificate. The second connection is
+// expected to succeed through the session cache.
+TEST_F(SSLServerSocketTest, HandshakeWithClientCertCached) {
+  scoped_refptr<X509Certificate> client_cert =
+      ImportCertFromFile(GetTestCertsDirectory(), kClientCertFileName);
+  ConfigureClientCertsForClient(kClientCertFileName, kClientPrivateKeyFileName);
+  ConfigureClientCertsForServer();
+  CreateContext();
+  CreateSockets();
+
+  TestCompletionCallback handshake_callback;
+  int server_ret = server_socket_->Handshake(handshake_callback.callback());
+
+  TestCompletionCallback connect_callback;
+  int client_ret = client_socket_->Connect(connect_callback.callback());
+
+  client_ret = connect_callback.GetResult(client_ret);
+  server_ret = handshake_callback.GetResult(server_ret);
+
+  ASSERT_EQ(OK, client_ret);
+  ASSERT_EQ(OK, server_ret);
+
+  // Make sure the cert status is expected.
+  SSLInfo ssl_info;
+  ASSERT_TRUE(client_socket_->GetSSLInfo(&ssl_info));
+  EXPECT_EQ(ssl_info.handshake_type, SSLInfo::HANDSHAKE_FULL);
+  SSLInfo ssl_server_info;
+  ASSERT_TRUE(server_socket_->GetSSLInfo(&ssl_server_info));
+  ASSERT_TRUE(ssl_server_info.cert.get());
+  EXPECT_TRUE(client_cert->Equals(ssl_server_info.cert.get()));
+  EXPECT_EQ(ssl_server_info.handshake_type, SSLInfo::HANDSHAKE_FULL);
+  server_socket_->Disconnect();
+  client_socket_->Disconnect();
+
+  // Create the connection again.
+  CreateSockets();
+  TestCompletionCallback handshake_callback2;
+  int server_ret2 = server_socket_->Handshake(handshake_callback2.callback());
+
+  TestCompletionCallback connect_callback2;
+  int client_ret2 = client_socket_->Connect(connect_callback2.callback());
+
+  client_ret2 = connect_callback2.GetResult(client_ret2);
+  server_ret2 = handshake_callback2.GetResult(server_ret2);
+
+  ASSERT_EQ(OK, client_ret2);
+  ASSERT_EQ(OK, server_ret2);
+
+  // Make sure the cert status is expected.
+  SSLInfo ssl_info2;
+  ASSERT_TRUE(client_socket_->GetSSLInfo(&ssl_info2));
+  EXPECT_EQ(ssl_info2.handshake_type, SSLInfo::HANDSHAKE_RESUME);
+  SSLInfo ssl_server_info2;
+  ASSERT_TRUE(server_socket_->GetSSLInfo(&ssl_server_info2));
+  ASSERT_TRUE(ssl_server_info2.cert.get());
+  EXPECT_TRUE(client_cert->Equals(ssl_server_info2.cert.get()));
+  EXPECT_EQ(ssl_server_info2.handshake_type, SSLInfo::HANDSHAKE_RESUME);
+}
+
 TEST_F(SSLServerSocketTest, HandshakeWithClientCertRequiredNotSupplied) {
   ConfigureClientCertsForServer();
-  Initialize();
+  CreateContext();
+  CreateSockets();
   // Use the default setting for the client socket, which is to not send
   // a client certificate. This will cause the client to receive an
   // ERR_SSL_CLIENT_AUTH_CERT_NEEDED error, and allow for inspecting the
@@ -554,13 +730,68 @@
   EXPECT_EQ(ERR_FAILED, handshake_callback.GetResult(server_ret));
 }
 
+TEST_F(SSLServerSocketTest, HandshakeWithClientCertRequiredNotSuppliedCached) {
+  ConfigureClientCertsForServer();
+  CreateContext();
+  CreateSockets();
+  // Use the default setting for the client socket, which is to not send
+  // a client certificate. This will cause the client to receive an
+  // ERR_SSL_CLIENT_AUTH_CERT_NEEDED error, and allow for inspecting the
+  // requested cert_authorities from the CertificateRequest sent by the
+  // server.
+
+  TestCompletionCallback handshake_callback;
+  int server_ret = server_socket_->Handshake(handshake_callback.callback());
+
+  TestCompletionCallback connect_callback;
+  EXPECT_EQ(ERR_SSL_CLIENT_AUTH_CERT_NEEDED,
+            connect_callback.GetResult(
+                client_socket_->Connect(connect_callback.callback())));
+
+  scoped_refptr<SSLCertRequestInfo> request_info = new SSLCertRequestInfo();
+  client_socket_->GetSSLCertRequestInfo(request_info.get());
+
+  // Check that the authority name that arrived in the CertificateRequest
+  // handshake message is as expected.
+  scoped_refptr<X509Certificate> client_cert =
+      ImportCertFromFile(GetTestCertsDirectory(), kClientCertFileName);
+  EXPECT_TRUE(client_cert->IsIssuedByEncoded(request_info->cert_authorities));
+
+  client_socket_->Disconnect();
+
+  EXPECT_EQ(ERR_FAILED, handshake_callback.GetResult(server_ret));
+  server_socket_->Disconnect();
+
+  // Below, check that the cache didn't store the result of a failed handshake.
+  CreateSockets();
+  TestCompletionCallback handshake_callback2;
+  int server_ret2 = server_socket_->Handshake(handshake_callback2.callback());
+
+  TestCompletionCallback connect_callback2;
+  EXPECT_EQ(ERR_SSL_CLIENT_AUTH_CERT_NEEDED,
+            connect_callback2.GetResult(
+                client_socket_->Connect(connect_callback2.callback())));
+
+  scoped_refptr<SSLCertRequestInfo> request_info2 = new SSLCertRequestInfo();
+  client_socket_->GetSSLCertRequestInfo(request_info2.get());
+
+  // Check that the authority name that arrived in the CertificateRequest
+  // handshake message is as expected.
+  EXPECT_TRUE(client_cert->IsIssuedByEncoded(request_info2->cert_authorities));
+
+  client_socket_->Disconnect();
+
+  EXPECT_EQ(ERR_FAILED, handshake_callback2.GetResult(server_ret2));
+}
+
 TEST_F(SSLServerSocketTest, HandshakeWithWrongClientCertSupplied) {
   scoped_refptr<X509Certificate> client_cert =
       ImportCertFromFile(GetTestCertsDirectory(), kClientCertFileName);
   ConfigureClientCertsForClient(kWrongClientCertFileName,
                                 kWrongClientPrivateKeyFileName);
   ConfigureClientCertsForServer();
-  Initialize();
+  CreateContext();
+  CreateSockets();
 
   TestCompletionCallback handshake_callback;
   int server_ret = server_socket_->Handshake(handshake_callback.callback());
@@ -573,10 +804,48 @@
   EXPECT_EQ(ERR_BAD_SSL_CLIENT_AUTH_CERT,
             handshake_callback.GetResult(server_ret));
 }
+
+TEST_F(SSLServerSocketTest, HandshakeWithWrongClientCertSuppliedCached) {
+  scoped_refptr<X509Certificate> client_cert =
+      ImportCertFromFile(GetTestCertsDirectory(), kClientCertFileName);
+  ConfigureClientCertsForClient(kWrongClientCertFileName,
+                                kWrongClientPrivateKeyFileName);
+  ConfigureClientCertsForServer();
+  CreateContext();
+  CreateSockets();
+
+  TestCompletionCallback handshake_callback;
+  int server_ret = server_socket_->Handshake(handshake_callback.callback());
+
+  TestCompletionCallback connect_callback;
+  int client_ret = client_socket_->Connect(connect_callback.callback());
+
+  EXPECT_EQ(ERR_BAD_SSL_CLIENT_AUTH_CERT,
+            connect_callback.GetResult(client_ret));
+  EXPECT_EQ(ERR_BAD_SSL_CLIENT_AUTH_CERT,
+            handshake_callback.GetResult(server_ret));
+
+  client_socket_->Disconnect();
+  server_socket_->Disconnect();
+
+  // Below, check that the cache didn't store the result of a failed handshake.
+  CreateSockets();
+  TestCompletionCallback handshake_callback2;
+  int server_ret2 = server_socket_->Handshake(handshake_callback2.callback());
+
+  TestCompletionCallback connect_callback2;
+  int client_ret2 = client_socket_->Connect(connect_callback2.callback());
+
+  EXPECT_EQ(ERR_BAD_SSL_CLIENT_AUTH_CERT,
+            connect_callback2.GetResult(client_ret2));
+  EXPECT_EQ(ERR_BAD_SSL_CLIENT_AUTH_CERT,
+            handshake_callback2.GetResult(server_ret2));
+}
 #endif  // defined(USE_OPENSSL)
 
 TEST_F(SSLServerSocketTest, DataTransfer) {
-  Initialize();
+  CreateContext();
+  CreateSockets();
 
   // Establish connection.
   TestCompletionCallback connect_callback;
@@ -601,8 +870,8 @@
   // Write then read.
   TestCompletionCallback write_callback;
   TestCompletionCallback read_callback;
-  server_ret = server_socket_->Write(
-      write_buf.get(), write_buf->size(), write_callback.callback());
+  server_ret = server_socket_->Write(write_buf.get(), write_buf->size(),
+                                     write_callback.callback());
   EXPECT_TRUE(server_ret > 0 || server_ret == ERR_IO_PENDING);
   client_ret = client_socket_->Read(
       read_buf.get(), read_buf->BytesRemaining(), read_callback.callback());
@@ -631,8 +900,8 @@
   server_ret = server_socket_->Read(
       read_buf.get(), read_buf->BytesRemaining(), read_callback.callback());
   EXPECT_TRUE(server_ret > 0 || server_ret == ERR_IO_PENDING);
-  client_ret = client_socket_->Write(
-      write_buf.get(), write_buf->size(), write_callback.callback());
+  client_ret = client_socket_->Write(write_buf.get(), write_buf->size(),
+                                     write_callback.callback());
   EXPECT_TRUE(client_ret > 0 || client_ret == ERR_IO_PENDING);
 
   server_ret = read_callback.GetResult(server_ret);
@@ -659,8 +928,8 @@
 // the client's Write() call should not cause an infinite loop.
 // NOTE: this is a test for SSLClientSocket rather than SSLServerSocket.
 TEST_F(SSLServerSocketTest, ClientWriteAfterServerClose) {
-  Initialize();
-
+  CreateContext();
+  CreateSockets();
 
   // Establish connection.
   TestCompletionCallback connect_callback;
@@ -683,8 +952,8 @@
   // socket won't return ERR_IO_PENDING.  This ensures that the client
   // will call Read() on the transport socket again.
   TestCompletionCallback write_callback;
-  server_ret = server_socket_->Write(
-      write_buf.get(), write_buf->size(), write_callback.callback());
+  server_ret = server_socket_->Write(write_buf.get(), write_buf->size(),
+                                     write_callback.callback());
   EXPECT_TRUE(server_ret > 0 || server_ret == ERR_IO_PENDING);
 
   server_ret = write_callback.GetResult(server_ret);
@@ -693,8 +962,8 @@
   server_socket_->Disconnect();
 
   // The client writes some data. This should not cause an infinite loop.
-  client_ret = client_socket_->Write(
-      write_buf.get(), write_buf->size(), write_callback.callback());
+  client_ret = client_socket_->Write(write_buf.get(), write_buf->size(),
+                                     write_callback.callback());
   EXPECT_TRUE(client_ret > 0 || client_ret == ERR_IO_PENDING);
 
   client_ret = write_callback.GetResult(client_ret);
@@ -710,7 +979,8 @@
 // after connecting them, and verifies that the results match.
 // This test will fail if False Start is enabled (see crbug.com/90208).
 TEST_F(SSLServerSocketTest, ExportKeyingMaterial) {
-  Initialize();
+  CreateContext();
+  CreateSockets();
 
   TestCompletionCallback connect_callback;
   int client_ret = client_socket_->Connect(connect_callback.callback());
@@ -731,23 +1001,20 @@
   const char kKeyingLabel[] = "EXPERIMENTAL-server-socket-test";
   const char kKeyingContext[] = "";
   unsigned char server_out[kKeyingMaterialSize];
-  int rv = server_socket_->ExportKeyingMaterial(kKeyingLabel,
-                                                false, kKeyingContext,
-                                                server_out, sizeof(server_out));
+  int rv = server_socket_->ExportKeyingMaterial(
+      kKeyingLabel, false, kKeyingContext, server_out, sizeof(server_out));
   ASSERT_EQ(OK, rv);
 
   unsigned char client_out[kKeyingMaterialSize];
-  rv = client_socket_->ExportKeyingMaterial(kKeyingLabel,
-                                            false, kKeyingContext,
+  rv = client_socket_->ExportKeyingMaterial(kKeyingLabel, false, kKeyingContext,
                                             client_out, sizeof(client_out));
   ASSERT_EQ(OK, rv);
   EXPECT_EQ(0, memcmp(server_out, client_out, sizeof(server_out)));
 
   const char kKeyingLabelBad[] = "EXPERIMENTAL-server-socket-test-bad";
   unsigned char client_bad[kKeyingMaterialSize];
-  rv = client_socket_->ExportKeyingMaterial(kKeyingLabelBad,
-                                            false, kKeyingContext,
-                                            client_bad, sizeof(client_bad));
+  rv = client_socket_->ExportKeyingMaterial(
+      kKeyingLabelBad, false, kKeyingContext, client_bad, sizeof(client_bad));
   ASSERT_EQ(rv, OK);
   EXPECT_NE(0, memcmp(server_out, client_bad, sizeof(server_out)));
 }
@@ -773,7 +1040,8 @@
   // Require ECDHE on the server.
   server_ssl_config_.require_ecdhe = true;
 
-  Initialize();
+  CreateContext();
+  CreateSockets();
 
   TestCompletionCallback connect_callback;
   int client_ret = client_socket_->Connect(connect_callback.callback());
diff --git a/net/ssl/ssl_server_config.h b/net/ssl/ssl_server_config.h
index 7a1861b..21ec128 100644
--- a/net/ssl/ssl_server_config.h
+++ b/net/ssl/ssl_server_config.h
@@ -73,7 +73,7 @@
   // Provides the ClientCertVerifier that is to be used to verify
   // client certificates during the handshake.
   // The |client_cert_verifier| continues to be owned by the caller,
-  // and must outlive any sockets using this SSLServerConfig.
+  // and must outlive any sockets spawned from this SSLServerContext.
   // This field is meaningful only if client certificates are requested.
   // If a verifier is not provided then all certificates are accepted.
   ClientCertVerifier* client_cert_verifier;
diff --git a/net/test/embedded_test_server/embedded_test_server.cc b/net/test/embedded_test_server/embedded_test_server.cc
index 8f10e1ca..eb09b96 100644
--- a/net/test/embedded_test_server/embedded_test_server.cc
+++ b/net/test/embedded_test_server/embedded_test_server.cc
@@ -111,9 +111,32 @@
   port_ = local_endpoint_.port();
 
   listen_socket_->DetachFromThread();
+
+  if (is_using_ssl_)
+    InitializeSSLServerContext();
   return true;
 }
 
+void EmbeddedTestServer::InitializeSSLServerContext() {
+  base::FilePath certs_dir(GetTestCertsDirectory());
+  std::string cert_name = GetCertificateName();
+
+  base::FilePath key_path = certs_dir.AppendASCII(cert_name);
+  std::string key_string;
+  CHECK(base::ReadFileToString(key_path, &key_string));
+  std::vector<std::string> headers;
+  headers.push_back("PRIVATE KEY");
+  PEMTokenizer pem_tokenizer(key_string, headers);
+  pem_tokenizer.GetNext();
+  std::vector<uint8_t> key_vector;
+  key_vector.assign(pem_tokenizer.data().begin(), pem_tokenizer.data().end());
+
+  scoped_ptr<crypto::RSAPrivateKey> server_key(
+      crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(key_vector));
+  context_ =
+      CreateSSLServerContext(GetCertificate().get(), *server_key, ssl_config_);
+}
+
 void EmbeddedTestServer::StartAcceptingConnections() {
   DCHECK(!io_thread_.get());
   base::Thread::Options thread_options;
@@ -276,24 +299,7 @@
     scoped_ptr<StreamSocket> connection) {
   DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
 
-  base::FilePath certs_dir(GetTestCertsDirectory());
-  std::string cert_name = GetCertificateName();
-
-  base::FilePath key_path = certs_dir.AppendASCII(cert_name);
-  std::string key_string;
-  CHECK(base::ReadFileToString(key_path, &key_string));
-  std::vector<std::string> headers;
-  headers.push_back("PRIVATE KEY");
-  PEMTokenizer pem_tokenizer(key_string, headers);
-  pem_tokenizer.GetNext();
-  std::vector<uint8_t> key_vector;
-  key_vector.assign(pem_tokenizer.data().begin(), pem_tokenizer.data().end());
-
-  scoped_ptr<crypto::RSAPrivateKey> server_key(
-      crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(key_vector));
-
-  return CreateSSLServerSocket(std::move(connection), GetCertificate().get(),
-                               *server_key, ssl_config_);
+  return context_->CreateSSLServerSocket(std::move(connection));
 }
 
 void EmbeddedTestServer::DoAcceptLoop() {
diff --git a/net/test/embedded_test_server/embedded_test_server.h b/net/test/embedded_test_server/embedded_test_server.h
index f226286..00952f9 100644
--- a/net/test/embedded_test_server/embedded_test_server.h
+++ b/net/test/embedded_test_server/embedded_test_server.h
@@ -25,6 +25,7 @@
 #include "net/base/host_port_pair.h"
 #include "net/base/ip_endpoint.h"
 #include "net/cert/x509_certificate.h"
+#include "net/socket/ssl_server_socket.h"
 #include "net/socket/stream_socket.h"
 #include "net/socket/tcp_server_socket.h"
 #include "net/ssl/ssl_server_config.h"
@@ -243,6 +244,10 @@
   void HandleRequest(HttpConnection* connection,
                      scoped_ptr<HttpRequest> request);
 
+  // Initializes the SSLServerContext so that SSLServerSocket connections may
+  // share the same cache
+  void InitializeSSLServerContext();
+
   HttpConnection* FindConnection(StreamSocket* socket);
 
   // Posts a task to the |io_thread_| and waits for a reply.
@@ -272,6 +277,7 @@
 
   net::SSLServerConfig ssl_config_;
   ServerCertificate cert_;
+  scoped_ptr<SSLServerContext> context_;
 
   base::WeakPtrFactory<EmbeddedTestServer> weak_factory_;
 
diff --git a/remoting/protocol/ssl_hmac_channel_authenticator.cc b/remoting/protocol/ssl_hmac_channel_authenticator.cc
index 808bd1b..fb91655 100644
--- a/remoting/protocol/ssl_hmac_channel_authenticator.cc
+++ b/remoting/protocol/ssl_hmac_channel_authenticator.cc
@@ -151,8 +151,10 @@
 // Implements P2PStreamSocket interface on top of net::StreamSocket.
 class P2PStreamSocketAdapter : public P2PStreamSocket {
  public:
-  P2PStreamSocketAdapter(scoped_ptr<net::StreamSocket> socket)
-      : socket_(std::move(socket)) {}
+  P2PStreamSocketAdapter(scoped_ptr<net::StreamSocket> socket,
+                         scoped_ptr<net::SSLServerContext> server_context)
+      : server_context_(std::move(server_context)),
+        socket_(std::move(socket)) {}
   ~P2PStreamSocketAdapter() override {}
 
   int Read(const scoped_refptr<net::IOBuffer>& buf, int buf_len,
@@ -165,6 +167,9 @@
   }
 
  private:
+  // The server_context_ will be a nullptr for client sockets.
+  // The server_context_ must outlive any sockets it spawns.
+  scoped_ptr<net::SSLServerContext> server_context_;
   scoped_ptr<net::StreamSocket> socket_;
 };
 
@@ -217,8 +222,8 @@
     result = net::ERR_FAILED;
 #else
     scoped_refptr<net::X509Certificate> cert =
-        net::X509Certificate::CreateFromBytes(
-            local_cert_.data(), local_cert_.length());
+        net::X509Certificate::CreateFromBytes(local_cert_.data(),
+                                              local_cert_.length());
     if (!cert.get()) {
       LOG(ERROR) << "Failed to parse X509Certificate";
       NotifyError(net::ERR_FAILED);
@@ -228,9 +233,12 @@
     net::SSLServerConfig ssl_config;
     ssl_config.require_ecdhe = true;
 
-    scoped_ptr<net::SSLServerSocket> server_socket = net::CreateSSLServerSocket(
-        make_scoped_ptr(new NetStreamSocketAdapter(std::move(socket))),
+    server_context_ = net::CreateSSLServerContext(
         cert.get(), *local_key_pair_->private_key(), ssl_config);
+
+    scoped_ptr<net::SSLServerSocket> server_socket =
+        server_context_->CreateSSLServerSocket(
+            make_scoped_ptr(new NetStreamSocketAdapter(std::move(socket))));
     net::SSLServerSocket* raw_server_socket = server_socket.get();
     socket_ = std::move(server_socket);
     result = raw_server_socket->Handshake(
@@ -430,8 +438,8 @@
       *callback_called = true;
 
     base::ResetAndReturn(&done_callback_)
-        .Run(net::OK,
-             make_scoped_ptr(new P2PStreamSocketAdapter(std::move(socket_))));
+        .Run(net::OK, make_scoped_ptr(new P2PStreamSocketAdapter(
+                          std::move(socket_), std::move(server_context_))));
   }
 }
 
diff --git a/remoting/protocol/ssl_hmac_channel_authenticator.h b/remoting/protocol/ssl_hmac_channel_authenticator.h
index e1da9ca..313f4bb 100644
--- a/remoting/protocol/ssl_hmac_channel_authenticator.h
+++ b/remoting/protocol/ssl_hmac_channel_authenticator.h
@@ -18,6 +18,7 @@
 class CertVerifier;
 class DrainableIOBuffer;
 class GrowableIOBuffer;
+class SSLServerContext;
 class SSLSocket;
 class TransportSecurityState;
 }  // namespace net
@@ -86,6 +87,7 @@
   // Used in the SERVER mode only.
   std::string local_cert_;
   scoped_refptr<RsaKeyPair> local_key_pair_;
+  scoped_ptr<net::SSLServerContext> server_context_;
 
   // Used in the CLIENT mode only.
   std::string remote_cert_;
diff --git a/third_party/WebKit/LayoutTests/LeakExpectations b/third_party/WebKit/LayoutTests/LeakExpectations
index fb6a1581..1ba76df 100644
--- a/third_party/WebKit/LayoutTests/LeakExpectations
+++ b/third_party/WebKit/LayoutTests/LeakExpectations
@@ -48,13 +48,10 @@
 # Untriaged but known leaks which may be false positives.
 # -----------------------------------------------------------------
 
-crbug.com/364411 fast/frames/location-observe-callback-crash.html [ Leak ]
-
 crbug.com/364417 editing/selection/selection-in-iframe-removed-crash.html [ Leak ]
 crbug.com/364417 editing/selection/user-select-js-property.html [ Leak ]
 crbug.com/364417 fast/events/touch/gesture/context-menu-on-long-tap.html [ Leak ]
 crbug.com/364417 fast/repaint/japanese-rl-selection-clear.html [ Leak ]
-crbug.com/364417 virtual/spv2/fast/repaint/japanese-rl-selection-clear.html [ Leak ]
 crbug.com/364417 fast/text/international/hebrew-selection.html [ Leak ]
 
 crbug.com/455369 fast/html/marquee-destroyed-without-removed-from-crash.html [ Leak Pass ]
@@ -94,8 +91,6 @@
 crbug.com/564571 virtual/threaded/animations/svg-length-unittype-crash.html [ Leak ]
 crbug.com/571534 virtual/threaded/animations/svg-element-css-animation-crash.html [ Leak ]
 
-crbug.com/588598 web-animations-api/player-cancel-event.html [ Leak ]
-
 # -----------------------------------------------------------------
 # Untriaged but known leaks of ActiveDOMObject (fast).
 # -----------------------------------------------------------------
@@ -117,7 +112,6 @@
 # Untriaged but known leaks of ActiveDOMObject (http).
 # -----------------------------------------------------------------
 crbug.com/506754 http/tests/cachestorage/window/cache-put.html [ Leak ]
-crbug.com/506754 http/tests/inspector/filesystem/request-file-content.html [ Leak ]
 crbug.com/506754 http/tests/inspector/network/network-xhr-replay.html [ Leak ]
 crbug.com/506754 http/tests/inspector/service-workers/service-worker-agents.html [ Crash Leak ]
 crbug.com/506754 http/tests/security/cross-origin-indexeddb-allowed.html [ Leak ]
diff --git a/third_party/WebKit/LayoutTests/animations/additive-transform-animations-expected.html b/third_party/WebKit/LayoutTests/animations/additive-transform-animations-expected.html
index 1b5d690..b64dd6b 100644
--- a/third_party/WebKit/LayoutTests/animations/additive-transform-animations-expected.html
+++ b/third_party/WebKit/LayoutTests/animations/additive-transform-animations-expected.html
@@ -1,24 +1,13 @@
 <!DOCTYPE html>
-<html>
-<head>
-  <style type="text/css">
-    .box {
-      height: 100px;
-      width: 100px;
-      background-color: blue;
-    }
-    
-    #box {
-      transform: rotate(90deg) translate(100px, 0);
-    }
-  </style>
-</head>
-<body>
+<style>
+.box {
+  height: 100px;
+  width: 100px;
+  background-color: blue;
+}
 
+#box {
+  transform: rotate(90deg) translate(100px, 0);
+}
+</style>
 <div class="box" id="box"></div>
-<div id="result">
-PASS - "webkitTransform" property for "box" element at 1s saw something close to: 0,1,-1,0,0,100
-</div>
-
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/animations/additive-transform-animations.html b/third_party/WebKit/LayoutTests/animations/additive-transform-animations.html
index 00e326e..2c94473 100644
--- a/third_party/WebKit/LayoutTests/animations/additive-transform-animations.html
+++ b/third_party/WebKit/LayoutTests/animations/additive-transform-animations.html
@@ -1,39 +1,22 @@
 <!DOCTYPE html>
+<style>
+.box {
+  height: 100px;
+  width: 100px;
+  background-color: blue;
+}
 
-<html>
-<head>
-  <style type="text/css">
-    .box {
-      height: 100px;
-      width: 100px;
-      background-color: blue;
-    }
-    
-    #box {
-      -webkit-animation: anim 2s linear both;
-    }
-    
-    @-webkit-keyframes anim {
-        from { transform: rotate(0deg) translate(-100px, 0); }
-        to   { transform: rotate(180deg) translate(300px, 0); }
-    }
-  </style>
-  <script src="resources/animation-test-helpers.js" type="text/javascript"></script>
-  <script type="text/javascript">
-    const expectedValues = [
-      // [time, element-id, property, expected-value, tolerance]
-      [1, "box",  "webkitTransform", [0, 1, -1, 0, 0, 100], 0.002],
-    ];
-    
-    const doPixelTest = true;
-    const disablePauseAnimationAPI = false;
-    runAnimationTest(expectedValues, null, null, disablePauseAnimationAPI, doPixelTest);
-  </script>
-</head>
-<body>
+#box {
+  animation-name: anim;
+  animation-duration: 1s;
+  animation-delay: -0.5s;
+  animation-play-state: paused;
+  animation-timing-function: linear;
+}
 
+@-webkit-keyframes anim {
+  from { transform: rotate(0deg) translate(-100px, 0); }
+  to   { transform: rotate(180deg) translate(300px, 0); }
+}
+</style>
 <div class="box" id="box"></div>
-<div id="result"></div>
-
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/animations/change-keyframes-expected.txt b/third_party/WebKit/LayoutTests/animations/change-keyframes-expected.txt
deleted file mode 100644
index d833812..0000000
--- a/third_party/WebKit/LayoutTests/animations/change-keyframes-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Warning this test is running in real-time and may be flaky.
-PASS - "left" property for "box" element at 0.5s saw something close to: 200
-PASS - "top" property for "box" element at 1s saw something close to: 100
-
diff --git a/third_party/WebKit/LayoutTests/animations/change-keyframes.html b/third_party/WebKit/LayoutTests/animations/change-keyframes.html
index a7358b8..97fda5a4 100644
--- a/third_party/WebKit/LayoutTests/animations/change-keyframes.html
+++ b/third_party/WebKit/LayoutTests/animations/change-keyframes.html
@@ -1,81 +1,60 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
-   "http://www.w3.org/TR/html4/loose.dtd">
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<style>
+  #box {
+    position: relative;
+    height: 100px;
+    width: 100px;
+    background-color: blue;
+    animation-name: anim;
+    animation-duration: 1s;
+    animation-delay: -0.5s;
+    animation-play-state: paused;
+    animation-timing-function: linear;
+  }
 
-<html lang="en">
-<head>
-  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-  <title>Test Changing Keyframes Using CSSOM</title>
-  <style type="text/css" media="screen">
-    #box {
-        position: relative;
-        left: 0;
-        top: 0;
-        height: 100px;
-        width: 100px;
-        background-color: blue;
-        -webkit-animation-duration: 1s;
-        -webkit-animation-timing-function: linear;
-        -webkit-animation-name: anim;
-    }
-    @-webkit-keyframes anim {
-        from { left: 100px; }
-        10%  { left: 200px; }
-        90%  { left: 200px; }
-        to   { left: 300px; }
-    }
-    </style>
-    <script src="resources/animation-test-helpers.js" type="text/javascript" charset="utf-8"></script>
-    <script type="text/javascript" charset="utf-8">
-
-    function findKeyframesRule(rule)
-    {
-        var ss = document.styleSheets;
-        for (var i = 0; i < ss.length; ++i) {
-            for (var j = 0; j < ss[i].cssRules.length; ++j) {
-                if (ss[i].cssRules[j].type == window.CSSRule.WEBKIT_KEYFRAMES_RULE && ss[i].cssRules[j].name == rule)
-                    return ss[i].cssRules[j];
-            }
+  @keyframes anim {
+    from { left: 100px; }
+    to   { left: 200px; }
+  }
+</style>
+<div id="box"></div>
+<script>
+  function findKeyframesRule(rule) {
+    var ss = document.styleSheets;
+    for (var i = 0; i < ss.length; ++i) {
+      for (var j = 0; j < ss[i].cssRules.length; ++j) {
+        if (ss[i].cssRules[j].type == CSSRule.KEYFRAMES_RULE &&
+            ss[i].cssRules[j].name == rule) {
+          return ss[i].cssRules[j];
         }
-
-        return null;
-    }
-
-    const expectedValues = [
-      // [time, element-id, property, expected-value, tolerance]
-      [0.5, "box", "left", 200, 10],
-      [1, "box", "top", 100, 10],
-    ];
-
-    const callbacks = {
-      0.6: function() {
-          document.getElementById('box').style.webkitAnimationName = "none";
-          // a forced style-recalc aborts the previous animation
-          document.getElementById('box').offsetTop;
-          // change keyframes
-          var keyframes = findKeyframesRule("anim");
-          keyframes.deleteRule("0%");
-          keyframes.deleteRule("40%");
-          keyframes.deleteRule("60%");
-          keyframes.deleteRule("100%");
-          keyframes.appendRule("0% { top: 50px; }");
-          keyframes.appendRule("10% { top: 100px; }");
-          keyframes.appendRule("90% { top: 100px; }");
-          keyframes.appendRule("100% { top: 150px; }");
-          document.getElementById('box').style.webkitAnimationName = "anim";
       }
     }
 
-    // FIXME: Consider whether we can support this kind of test (staggered start) under the pause API
-    runAnimationTest(expectedValues, callbacks, null, 'do-not-use-pause-api');
-  </script>
-</head>
-<body>
-This test performs an animation of the left property and makes sure it is animating. Then it stops
-the animation, changes the keyframes to an animation of the top property, restarts the animation
-and makes sure top is animating.
-<div id="box">
-</div>
-<div id="result">
-</div>
-</body>
-</html>
+    return null;
+  }
+
+  test(function() {
+    var box = document.getElementById('box');
+
+    // The left property should be animating initially.
+    assert_equals(getComputedStyle(box).left, '150px', 'left');
+
+    // A forced style-recalc aborts the previous animation.
+    box.style.animationName = "none";
+    assert_equals(getComputedStyle(box).left, 'auto', 'left');
+
+    // Change keyframes.
+    var keyframes = findKeyframesRule("anim");
+    keyframes.deleteRule("0%");
+    keyframes.deleteRule("100%");
+    keyframes.appendRule("0% { top: 50px; }");
+    keyframes.appendRule("100% { top: 150px; }");
+    box.style.webkitAnimationName = "anim";
+
+    // The left property should reset to auto and top should be animating.
+    assert_equals(getComputedStyle(box).left, 'auto', 'left');
+    assert_equals(getComputedStyle(box).top, '100px', 'top');
+  }, "Check that changes to keyframe rules take effect");
+</script>
diff --git a/third_party/WebKit/LayoutTests/css3/images/cross-fade-svg-size-expected.html b/third_party/WebKit/LayoutTests/css3/images/cross-fade-svg-size-expected.html
new file mode 100644
index 0000000..17996c3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/images/cross-fade-svg-size-expected.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<title>Test SVG in -webkit-cross-fade image</title>
+<p>There should be four green circles below.
+<div>
+<img width=100 src="data:image/svg+xml,<svg width='100' height='100' xmlns='http://www.w3.org/2000/svg'><circle cx='50' cy='50' r='25' fill='green'/></svg>">
+<img width=100 src="data:image/svg+xml,<svg width='100' height='100' xmlns='http://www.w3.org/2000/svg'><circle cx='50' cy='50' r='25' fill='green'/></svg>">
+<img width=100 src="data:image/svg+xml,<svg width='100' height='100' xmlns='http://www.w3.org/2000/svg'><circle cx='50' cy='50' r='25' fill='green'/></svg>">
+<img width=100 src="data:image/svg+xml,<svg width='100' height='100' xmlns='http://www.w3.org/2000/svg'><circle cx='50' cy='50' r='25' fill='green'/></svg>">
diff --git a/third_party/WebKit/LayoutTests/css3/images/cross-fade-svg-size.html b/third_party/WebKit/LayoutTests/css3/images/cross-fade-svg-size.html
new file mode 100644
index 0000000..c1ea969
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/images/cross-fade-svg-size.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<title>Test SVG in -webkit-cross-fade image</title>
+<style>
+div {
+    display: inline-block;
+    width: 100px;
+    height: 100px;
+}
+#tst1 {
+    background-image: -webkit-cross-fade(
+        url("data:image/svg+xml,<svg viewBox='0 0 10 10' xmlns='http://www.w3.org/2000/svg'><circle cx='5' cy='5' r='2.5' fill='green'/></svg>"), 
+        url("data:image/svg+xml,<svg viewBox='0 0 10 10' xmlns='http://www.w3.org/2000/svg'><circle cx='5' cy='5' r='2.5' fill='red'/></svg>"),
+        0);
+}
+#tst2 {
+    background-image: -webkit-cross-fade(
+        url("data:image/svg+xml,<svg viewBox='0 0 10 10' xmlns='http://www.w3.org/2000/svg'><circle cx='5' cy='5' r='2.5' fill='red'/></svg>"), 
+        url("data:image/svg+xml,<svg viewBox='0 0 10 10' xmlns='http://www.w3.org/2000/svg'><circle cx='5' cy='5' r='2.5' fill='green'/></svg>"),
+        1.0);
+}
+#tst3 {
+    background-image: -webkit-cross-fade(
+        url("resources/green-10.png"), 
+        url("data:image/svg+xml,<svg viewBox='0 0 10 10' xmlns='http://www.w3.org/2000/svg'><circle cx='5' cy='5' r='2.5' fill='green'/></svg>"),
+        1.0);
+}
+#tst4 {
+    background-image: -webkit-cross-fade(
+        url("data:image/svg+xml,<svg viewBox='0 0 10 10' xmlns='http://www.w3.org/2000/svg'><circle cx='5' cy='5' r='2.5' fill='green'/></svg>"),
+        url("resources/green-10.png"), 
+        0.0);
+}
+</style>
+<p>There should be four green circles below.
+<div id=tst1></div>
+<div id=tst2></div>
+<div id=tst3></div>
+<div id=tst4></div>
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/background-clip-per-layer-expected.txt b/third_party/WebKit/LayoutTests/fast/backgrounds/background-clip-per-layer-expected.txt
new file mode 100644
index 0000000..afe7065
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/background-clip-per-layer-expected.txt
@@ -0,0 +1,11 @@
+Tests that background shorthand property parsing will deal correctly with clip values in multiple layers.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS e.style.backgroundOrigin is "content-box, border-box"
+PASS e.style.backgroundClip is "padding-box, border-box"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/background-clip-per-layer.html b/third_party/WebKit/LayoutTests/fast/backgrounds/background-clip-per-layer.html
new file mode 100644
index 0000000..8f5284f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/background-clip-per-layer.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<script src="../../resources/js-test.js"></script>
+<div id="test"> </div>
+<script>
+description("Tests that background shorthand property parsing will deal correctly with clip values in multiple layers.");
+
+var e = document.getElementById('test');
+
+e.style.background = "url('a') content-box padding-box, url('b') border-box";
+shouldBeEqualToString("e.style.backgroundOrigin", 'content-box, border-box');
+shouldBeEqualToString("e.style.backgroundClip", 'padding-box, border-box');
+
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/background-position-parsing-2-expected.txt b/third_party/WebKit/LayoutTests/fast/backgrounds/background-position-parsing-2-expected.txt
index f666e88..bb5334e 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/background-position-parsing-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/background-position-parsing-2-expected.txt
@@ -200,30 +200,30 @@
 background-position inside the background shorthand
 PASS style.background is 'left 30% top 10% / 10em round fixed border-box border-box gray'
 PASS computedStyle.background is 'rgb(128, 128, 128) none round fixed left 30% top 10% / 160px border-box border-box'
-PASS style.background is 'right 0% top 15px / 10em round fixed border-box border-box gray'
-PASS computedStyle.background is 'rgb(128, 128, 128) none round fixed right 0% top 15px / 160px border-box border-box'
-PASS style.background is 'left 10px top 50% / 10em round fixed border-box border-box gray'
-PASS computedStyle.background is 'rgb(128, 128, 128) none round fixed left 10px top 50% / 160px border-box border-box'
-PASS style.background is 'left 10px top 50% round fixed border-box border-box'
-PASS computedStyle.background is 'rgba(0, 0, 0, 0) none round fixed left 10px top 50% / auto border-box border-box'
-PASS style.background is 'left 50% top 20px round fixed border-box border-box'
-PASS computedStyle.background is 'rgba(0, 0, 0, 0) none round fixed left 50% top 20px / auto border-box border-box'
-PASS style.background is 'left 50% top 20px round fixed border-box border-box'
-PASS computedStyle.background is 'rgba(0, 0, 0, 0) none round fixed left 50% top 20px / auto border-box border-box'
-PASS style.background is '50% 0% round fixed border-box border-box'
+PASS style.background is 'right top 15px / 10em round fixed border-box border-box gray'
+PASS computedStyle.background is 'rgb(128, 128, 128) none round fixed 100% top 15px / 160px border-box border-box'
+PASS style.background is 'left 10px center / 10em round fixed border-box border-box gray'
+PASS computedStyle.background is 'rgb(128, 128, 128) none round fixed left 10px 50% / 160px border-box border-box'
+PASS style.background is 'left 10px center round fixed border-box border-box'
+PASS computedStyle.background is 'rgba(0, 0, 0, 0) none round fixed left 10px 50% / auto border-box border-box'
+PASS style.background is 'center top 20px round fixed border-box border-box'
+PASS computedStyle.background is 'rgba(0, 0, 0, 0) none round fixed 50% top 20px / auto border-box border-box'
+PASS style.background is 'center top 20px round fixed border-box border-box'
+PASS computedStyle.background is 'rgba(0, 0, 0, 0) none round fixed 50% top 20px / auto border-box border-box'
+PASS style.background is 'center top round fixed border-box border-box'
 PASS computedStyle.background is 'rgba(0, 0, 0, 0) none round fixed 50% 0% / auto border-box border-box'
 PASS style.background is '50px 60px / 50px round fixed border-box border-box'
 PASS computedStyle.background is 'rgba(0, 0, 0, 0) none round fixed 50px 60px / 50px border-box border-box'
-PASS style.background is '50px 50% / 50px round fixed border-box border-box'
+PASS style.background is '50px center / 50px round fixed border-box border-box'
 PASS computedStyle.background is 'rgba(0, 0, 0, 0) none round fixed 50px 50% / 50px border-box border-box'
-PASS style.background is 'left 0% top 60px / 50px round fixed border-box border-box'
-PASS computedStyle.background is 'rgba(0, 0, 0, 0) none round fixed left 0% top 60px / 50px border-box border-box'
+PASS style.background is 'left top 60px / 50px round fixed border-box border-box'
+PASS computedStyle.background is 'rgba(0, 0, 0, 0) none round fixed 0% top 60px / 50px border-box border-box'
 PASS style.background is 'left -20px top 60px / 50px round fixed border-box border-box'
 PASS computedStyle.background is 'rgba(0, 0, 0, 0) none round fixed left -20px top 60px / 50px border-box border-box'
-PASS style.background is 'left 20px top 0% / 50px round fixed border-box border-box'
-PASS computedStyle.background is 'rgba(0, 0, 0, 0) none round fixed left 20px top 0% / 50px border-box border-box'
-PASS style.background is 'left 20px top 0% / 50px round fixed border-box border-box'
-PASS computedStyle.background is 'rgba(0, 0, 0, 0) none round fixed left 20px top 0% / 50px border-box border-box'
+PASS style.background is 'left 20px top / 50px round fixed border-box border-box'
+PASS computedStyle.background is 'rgba(0, 0, 0, 0) none round fixed left 20px 0% / 50px border-box border-box'
+PASS style.background is 'left 20px top / 50px round fixed border-box border-box'
+PASS computedStyle.background is 'rgba(0, 0, 0, 0) none round fixed left 20px 0% / 50px border-box border-box'
 PASS style.background is 'left 20px top 40px / 50px round fixed border-box border-box'
 PASS computedStyle.background is 'rgba(0, 0, 0, 0) none round fixed left 20px top 40px / 50px border-box border-box'
 PASS style.background is 'left 20px top 40px round fixed border-box border-box'
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/background-position-parsing-2.html b/third_party/WebKit/LayoutTests/fast/backgrounds/background-position-parsing-2.html
index db23060..b3cd721 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/background-position-parsing-2.html
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/background-position-parsing-2.html
@@ -412,27 +412,27 @@
 shouldBe("computedStyle.background", "'rgb(128, 128, 128) none round fixed left 30% top 10% / 160px border-box border-box'");
 
 style.background = "right top 15px / 10em gray round fixed border-box";
-shouldBe("style.background", "'right 0% top 15px / 10em round fixed border-box border-box gray'");
-shouldBe("computedStyle.background", "'rgb(128, 128, 128) none round fixed right 0% top 15px / 160px border-box border-box'");
+shouldBe("style.background", "'right top 15px / 10em round fixed border-box border-box gray'");
+shouldBe("computedStyle.background", "'rgb(128, 128, 128) none round fixed 100% top 15px / 160px border-box border-box'");
 
 style.background = "left 10px center / 10em gray round fixed border-box";
-shouldBe("style.background", "'left 10px top 50% / 10em round fixed border-box border-box gray'");
-shouldBe("computedStyle.background", "'rgb(128, 128, 128) none round fixed left 10px top 50% / 160px border-box border-box'");
+shouldBe("style.background", "'left 10px center / 10em round fixed border-box border-box gray'");
+shouldBe("computedStyle.background", "'rgb(128, 128, 128) none round fixed left 10px 50% / 160px border-box border-box'");
 
 style.background = "left 10px center round fixed border-box";
-shouldBe("style.background", "'left 10px top 50% round fixed border-box border-box'");
-shouldBe("computedStyle.background", "'rgba(0, 0, 0, 0) none round fixed left 10px top 50% / auto border-box border-box'");
+shouldBe("style.background", "'left 10px center round fixed border-box border-box'");
+shouldBe("computedStyle.background", "'rgba(0, 0, 0, 0) none round fixed left 10px 50% / auto border-box border-box'");
 
 style.background = "center top 20px round fixed border-box";
-shouldBe("style.background", "'left 50% top 20px round fixed border-box border-box'");
-shouldBe("computedStyle.background", "'rgba(0, 0, 0, 0) none round fixed left 50% top 20px / auto border-box border-box'");
+shouldBe("style.background", "'center top 20px round fixed border-box border-box'");
+shouldBe("computedStyle.background", "'rgba(0, 0, 0, 0) none round fixed 50% top 20px / auto border-box border-box'");
 
 style.background = "top 20px center round fixed border-box";
-shouldBe("style.background", "'left 50% top 20px round fixed border-box border-box'");
-shouldBe("computedStyle.background", "'rgba(0, 0, 0, 0) none round fixed left 50% top 20px / auto border-box border-box'");
+shouldBe("style.background", "'center top 20px round fixed border-box border-box'");
+shouldBe("computedStyle.background", "'rgba(0, 0, 0, 0) none round fixed 50% top 20px / auto border-box border-box'");
 
 style.background = "top center round fixed border-box";
-shouldBe("style.background", "'50% 0% round fixed border-box border-box'");
+shouldBe("style.background", "'center top round fixed border-box border-box'");
 shouldBe("computedStyle.background", "'rgba(0, 0, 0, 0) none round fixed 50% 0% / auto border-box border-box'");
 
 style.background = "50px 60px / 50px round fixed border-box";
@@ -440,24 +440,24 @@
 shouldBe("computedStyle.background", "'rgba(0, 0, 0, 0) none round fixed 50px 60px / 50px border-box border-box'");
 
 style.background = "50px / 50px round fixed border-box";
-shouldBe("style.background", "'50px 50% / 50px round fixed border-box border-box'");
+shouldBe("style.background", "'50px center / 50px round fixed border-box border-box'");
 shouldBe("computedStyle.background", "'rgba(0, 0, 0, 0) none round fixed 50px 50% / 50px border-box border-box'");
 
 style.background = "left top 60px / 50px round fixed border-box";
-shouldBe("style.background", "'left 0% top 60px / 50px round fixed border-box border-box'");
-shouldBe("computedStyle.background", "'rgba(0, 0, 0, 0) none round fixed left 0% top 60px / 50px border-box border-box'");
+shouldBe("style.background", "'left top 60px / 50px round fixed border-box border-box'");
+shouldBe("computedStyle.background", "'rgba(0, 0, 0, 0) none round fixed 0% top 60px / 50px border-box border-box'");
 
 style.background = "left -20px top 60px / 50px round fixed border-box";
 shouldBe("style.background", "'left -20px top 60px / 50px round fixed border-box border-box'");
 shouldBe("computedStyle.background", "'rgba(0, 0, 0, 0) none round fixed left -20px top 60px / 50px border-box border-box'");
 
 style.background = "border-box left 20px top / 50px round fixed";
-shouldBe("style.background", "'left 20px top 0% / 50px round fixed border-box border-box'");
-shouldBe("computedStyle.background", "'rgba(0, 0, 0, 0) none round fixed left 20px top 0% / 50px border-box border-box'");
+shouldBe("style.background", "'left 20px top / 50px round fixed border-box border-box'");
+shouldBe("computedStyle.background", "'rgba(0, 0, 0, 0) none round fixed left 20px 0% / 50px border-box border-box'");
 
 style.background = "border-box round fixed left 20px top / 50px";
-shouldBe("style.background", "'left 20px top 0% / 50px round fixed border-box border-box'");
-shouldBe("computedStyle.background", "'rgba(0, 0, 0, 0) none round fixed left 20px top 0% / 50px border-box border-box'");
+shouldBe("style.background", "'left 20px top / 50px round fixed border-box border-box'");
+shouldBe("computedStyle.background", "'rgba(0, 0, 0, 0) none round fixed left 20px 0% / 50px border-box border-box'");
 
 style.background = "border-box round fixed left 20px top 40px / 50px";
 shouldBe("style.background", "'left 20px top 40px / 50px round fixed border-box border-box'");
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/background-shorthand-after-set-backgroundSize-expected.txt b/third_party/WebKit/LayoutTests/fast/backgrounds/background-shorthand-after-set-backgroundSize-expected.txt
index a2b24540..bf8adea 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/background-shorthand-after-set-backgroundSize-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/background-shorthand-after-set-backgroundSize-expected.txt
@@ -3,7 +3,7 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS e.style.background is "url(\"dummy://test.png\") 50% 50% / cover no-repeat border-box border-box red"
+PASS e.style.background is "url(\"dummy://test.png\") center center / cover no-repeat border-box border-box red"
 PASS e.style.backgroundSize is "cover"
 
 PASS successfullyParsed is true
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/background-shorthand-after-set-backgroundSize.html b/third_party/WebKit/LayoutTests/fast/backgrounds/background-shorthand-after-set-backgroundSize.html
index 0f5e82a6..f04969e 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/background-shorthand-after-set-backgroundSize.html
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/background-shorthand-after-set-backgroundSize.html
@@ -12,7 +12,7 @@
 
     e.style.backgroundSize = "cover";
     e.style.background = "center red url(dummy://test.png) no-repeat border-box";
-    shouldBeEqualToString("e.style.background", 'url("dummy://test.png") 50% 50% / cover no-repeat border-box border-box red')
+    shouldBeEqualToString("e.style.background", 'url("dummy://test.png") center center / cover no-repeat border-box border-box red')
     shouldBeEqualToString("e.style.backgroundSize", 'cover');
     debug("")
 
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/background-shorthand-with-backgroundSize-style-expected.txt b/third_party/WebKit/LayoutTests/fast/backgrounds/background-shorthand-with-backgroundSize-style-expected.txt
index 311620f..850ea68 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/background-shorthand-with-backgroundSize-style-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/background-shorthand-with-backgroundSize-style-expected.txt
@@ -3,14 +3,14 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS e.style.background is "url(\"dummy://test.png\") 50% 50% / cover no-repeat border-box border-box red"
+PASS e.style.background is "url(\"dummy://test.png\") center center / cover no-repeat border-box border-box red"
 PASS e.style.backgroundSize is "cover"
 PASS checkStyle() is true
 PASS computedStyle.getPropertyValue("background") is "rgb(255, 0, 0) url(\"dummy://test.png\") no-repeat scroll 50% 50% / cover border-box border-box"
 PASS computedStyle.getPropertyValue("background-size") is "cover"
 PASS checkComputedStyleValue() is true
 
-PASS e.style.background is "url(\"dummy://test.png\") 20px 50% / contain no-repeat padding-box padding-box red"
+PASS e.style.background is "url(\"dummy://test.png\") 20px center / contain no-repeat padding-box padding-box red"
 PASS e.style.backgroundSize is "contain"
 PASS checkStyle() is true
 PASS computedStyle.getPropertyValue("background") is "rgb(255, 0, 0) url(\"dummy://test.png\") no-repeat scroll 20px 50% / contain padding-box padding-box"
@@ -24,14 +24,14 @@
 PASS computedStyle.getPropertyValue("background-size") is "50% 75%"
 PASS checkComputedStyleValue() is true
 
-PASS e.style.background is "url(\"dummy://test.png\") 0% 0% / 100px 200px repeat border-box content-box red"
+PASS e.style.background is "url(\"dummy://test.png\") left top / 100px 200px repeat border-box content-box red"
 PASS e.style.backgroundSize is "100px 200px"
 PASS checkStyle() is true
 PASS computedStyle.getPropertyValue("background") is "rgb(255, 0, 0) url(\"dummy://test.png\") repeat scroll 0% 0% / 100px 200px border-box content-box"
 PASS computedStyle.getPropertyValue("background-size") is "100px 200px"
 PASS checkComputedStyleValue() is true
 
-PASS e.style.background is "url(\"dummy://test.png\") 50% 50% / auto repeat content-box padding-box red"
+PASS e.style.background is "url(\"dummy://test.png\") 50% center / auto repeat content-box padding-box red"
 PASS e.style.backgroundSize is "auto"
 PASS checkStyle() is true
 PASS computedStyle.getPropertyValue("background") is "rgb(255, 0, 0) url(\"dummy://test.png\") repeat scroll 50% 50% / auto content-box padding-box"
@@ -45,21 +45,21 @@
 PASS computedStyle.getPropertyValue("background-size") is "50%"
 PASS checkComputedStyleValue() is true
 
-PASS e.style.background is "url(\"dummy://test.png\") 0% 0% / 100px repeat scroll padding-box border-box red"
+PASS e.style.background is "url(\"dummy://test.png\") left top / 100px repeat scroll padding-box border-box red"
 PASS e.style.backgroundSize is "100px"
 PASS checkStyle() is true
 PASS computedStyle.getPropertyValue("background") is "rgb(255, 0, 0) url(\"dummy://test.png\") repeat scroll 0% 0% / 100px padding-box border-box"
 PASS computedStyle.getPropertyValue("background-size") is "100px"
 PASS checkComputedStyleValue() is true
 
-PASS e.style.background is "url(\"dummy://test.png\") 50% 50% / auto repeat fixed content-box content-box red"
+PASS e.style.background is "url(\"dummy://test.png\") 50% center / auto repeat fixed content-box content-box red"
 PASS e.style.backgroundSize is "auto"
 PASS checkStyle() is true
 PASS computedStyle.getPropertyValue("background") is "rgb(255, 0, 0) url(\"dummy://test.png\") repeat fixed 50% 50% / auto content-box content-box"
 PASS computedStyle.getPropertyValue("background-size") is "auto"
 PASS checkComputedStyleValue() is true
 
-PASS e.style.background is "0% 0% / 50%"
+PASS e.style.background is "left top / 50%"
 PASS e.style.backgroundSize is "50%"
 PASS checkStyle() is true
 PASS computedStyle.getPropertyValue("background") is "rgba(0, 0, 0, 0) none repeat scroll 0% 0% / 50% padding-box border-box"
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/background-shorthand-with-backgroundSize-style.html b/third_party/WebKit/LayoutTests/fast/backgrounds/background-shorthand-with-backgroundSize-style.html
index 25adc59..8bd7570 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/background-shorthand-with-backgroundSize-style.html
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/background-shorthand-with-backgroundSize-style.html
@@ -23,7 +23,7 @@
 }
 
 e.style.background = 'center / cover red url("dummy://test.png") no-repeat border-box';
-shouldBeEqualToString("e.style.background", 'url("dummy://test.png") 50% 50% / cover no-repeat border-box border-box red');
+shouldBeEqualToString("e.style.background", 'url("dummy://test.png") center center / cover no-repeat border-box border-box red');
 shouldBeEqualToString("e.style.backgroundSize", 'cover');
 shouldBe("checkStyle()", "true");
 shouldBeEqualToString('computedStyle.getPropertyValue("background")', 'rgb(255, 0, 0) url("dummy://test.png") no-repeat scroll 50% 50% / cover border-box border-box');
@@ -32,7 +32,7 @@
 debug("")
 
 e.style.background = 'red 20px / contain url("dummy://test.png") no-repeat padding-box';
-shouldBeEqualToString("e.style.background", 'url("dummy://test.png") 20px 50% / contain no-repeat padding-box padding-box red');
+shouldBeEqualToString("e.style.background", 'url("dummy://test.png") 20px center / contain no-repeat padding-box padding-box red');
 shouldBeEqualToString("e.style.backgroundSize", 'contain');
 shouldBe("checkStyle()", "true");
 shouldBeEqualToString('computedStyle.getPropertyValue("background")', 'rgb(255, 0, 0) url("dummy://test.png") no-repeat scroll 20px 50% / contain padding-box padding-box');
@@ -50,7 +50,7 @@
 debug("")
 
 e.style.background = 'red url("dummy://test.png") repeat top left / 100px 200px border-box content-box';
-shouldBeEqualToString("e.style.background", 'url("dummy://test.png") 0% 0% / 100px 200px repeat border-box content-box red');
+shouldBeEqualToString("e.style.background", 'url("dummy://test.png") left top / 100px 200px repeat border-box content-box red');
 shouldBeEqualToString("e.style.backgroundSize", '100px 200px');
 shouldBe("checkStyle()", "true");
 shouldBeEqualToString('computedStyle.getPropertyValue("background")', 'rgb(255, 0, 0) url("dummy://test.png") repeat scroll 0% 0% / 100px 200px border-box content-box');
@@ -59,7 +59,7 @@
 debug("")
 
 e.style.background = 'red url("dummy://test.png") repeat 50% / auto auto content-box padding-box';
-shouldBeEqualToString("e.style.background", 'url("dummy://test.png") 50% 50% / auto repeat content-box padding-box red');
+shouldBeEqualToString("e.style.background", 'url("dummy://test.png") 50% center / auto repeat content-box padding-box red');
 shouldBeEqualToString("e.style.backgroundSize", 'auto');
 shouldBe("checkStyle()", "true");
 shouldBeEqualToString('computedStyle.getPropertyValue("background")', 'rgb(255, 0, 0) url("dummy://test.png") repeat scroll 50% 50% / auto content-box padding-box');
@@ -77,7 +77,7 @@
 debug("")
 
 e.style.background = 'red repeat scroll padding-box border-box top left / 100px url("dummy://test.png")';
-shouldBeEqualToString("e.style.background", 'url("dummy://test.png") 0% 0% / 100px repeat scroll padding-box border-box red');
+shouldBeEqualToString("e.style.background", 'url("dummy://test.png") left top / 100px repeat scroll padding-box border-box red');
 shouldBeEqualToString("e.style.backgroundSize", '100px');
 shouldBe("checkStyle()", "true");
 shouldBeEqualToString('computedStyle.getPropertyValue("background")', 'rgb(255, 0, 0) url("dummy://test.png") repeat scroll 0% 0% / 100px padding-box border-box');
@@ -86,7 +86,7 @@
 debug("")
 
 e.style.background = '50% / auto fixed url("dummy://test.png") repeat content-box red';
-shouldBeEqualToString("e.style.background", 'url("dummy://test.png") 50% 50% / auto repeat fixed content-box content-box red');
+shouldBeEqualToString("e.style.background", 'url("dummy://test.png") 50% center / auto repeat fixed content-box content-box red');
 shouldBeEqualToString("e.style.backgroundSize", 'auto');
 shouldBe("checkStyle()", "true");
 shouldBeEqualToString('computedStyle.getPropertyValue("background")', 'rgb(255, 0, 0) url("dummy://test.png") repeat fixed 50% 50% / auto content-box content-box');
@@ -95,7 +95,7 @@
 debug("")
 
 e.style.background = "top left / 50%";
-shouldBeEqualToString("e.style.background", '0% 0% / 50%');
+shouldBeEqualToString("e.style.background", 'left top / 50%');
 shouldBeEqualToString("e.style.backgroundSize", '50%');
 shouldBe("checkStyle()", "true");
 shouldBeEqualToString('computedStyle.getPropertyValue("background")', 'rgba(0, 0, 0, 0) none repeat scroll 0% 0% / 50% padding-box border-box');
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-constructor-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-constructor-expected.txt
deleted file mode 100644
index bd3a4f8..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-constructor-expected.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-Tests that the constructor of the OffscreenCanvas can be called on the main thread
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS aCanvas.width is 50
-PASS aCanvas.height is 50
-PASS aCanvas.width is 100
-PASS aCanvas.height is 100
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-constructor.html b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-constructor.html
deleted file mode 100644
index 0b61a34..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-constructor.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE html>
-<script src="../../resources/js-test.js"></script>
-<script>
-description("Tests that the constructor of the OffscreenCanvas can be called on the main thread");
-
-var aCanvas = new OffscreenCanvas(50, 50);
-shouldBe("aCanvas.width", "50");
-shouldBe("aCanvas.height", "50");
-
-aCanvas.width = 100;
-aCanvas.height = 100;
-shouldBe("aCanvas.width", "100");
-shouldBe("aCanvas.height", "100");
-</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext2D-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext2D-expected.txt
new file mode 100644
index 0000000..6894f5c0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext2D-expected.txt
@@ -0,0 +1,20 @@
+Tests basic functionalities of offscreenCanvas.getContext on the main thread
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS aCanvas.width is 40
+PASS aCanvas.height is 60
+PASS aCanvas.width is 110
+PASS aCanvas.height is 90
+PASS aCanvas.width is 0
+PASS ctx = aCanvas.getContext('2d') did not throw exception.
+PASS ctx is an instance of OffscreenCanvasRenderingContext2D
+PASS ctx2 is null
+PASS ctx3 is non-null.
+PASS ctx3 == ctx is true
+PASS bogusCtx is null
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext2D-in-worker-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext2D-in-worker-expected.txt
new file mode 100644
index 0000000..2682efa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext2D-in-worker-expected.txt
@@ -0,0 +1,10 @@
+Tests that the 2D context of OffscreenCanvas can be constructed on a worker thread.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS getContext('2d') correctly returns [object OffscreenCanvasRenderingContext2D].
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext2D-in-worker.html b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext2D-in-worker.html
new file mode 100644
index 0000000..e555fa9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext2D-in-worker.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+<script src="../../resources/js-test.js"></script>
+<body>
+<script id="myWorker" type="text/worker">
+self.onmessage = function(e) {
+    var aCanvas = new OffscreenCanvas(50, 50);
+    try {
+      var ctx = aCanvas.getContext('2d');
+      if (toString.call(ctx) != '[object OffscreenCanvasRenderingContext2D]') {
+          self.postMessage("aCanvas.getContext('2d') does not return [object OffscreenCanvasRenderingContext2D]");
+      } else {
+          self.postMessage("success");
+      }
+    } catch (e) {
+      self.postMessage(e);
+    }
+};
+</script>
+
+<script>
+jsTestIsAsync = true;
+description("Tests that the 2D context of OffscreenCanvas can be constructed on a worker thread.");
+
+function makeWorker(script) {
+  var blob = new Blob([script]);
+  return new Worker(URL.createObjectURL(blob));
+}
+
+function handleMessageFromWorker(msg)
+{
+    if (msg.data == "success") {
+        testPassed("getContext('2d') correctly returns [object OffscreenCanvasRenderingContext2D].");
+    } else {
+        testFailed(msg.data);
+    }
+    finishJSTest();
+}
+
+var worker = makeWorker(document.getElementById('myWorker').textContent);
+worker.addEventListener('message', handleMessageFromWorker);
+worker.postMessage("");
+</script>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext2D.html b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext2D.html
new file mode 100644
index 0000000..be7fad2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext2D.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<script src="../../resources/js-test.js"></script>
+<script>
+description("Tests basic functionalities of offscreenCanvas.getContext on the main thread");
+
+// Tests onstructor of OffscreenCanvas and length/width change
+var aCanvas = new OffscreenCanvas(40, 60);
+shouldBe("aCanvas.width", "40");
+shouldBe("aCanvas.height", "60");
+
+aCanvas.width = 110;
+aCanvas.height = 90;
+shouldBe("aCanvas.width", "110");
+shouldBe("aCanvas.height", "90");
+
+aCanvas.width = 0; // Zero dimension is allowed
+shouldBe("aCanvas.width", "0");
+
+// Tests object type of getContext('2d')
+var ctx;
+shouldNotThrow("ctx = aCanvas.getContext('2d')");
+shouldBeType("ctx", "OffscreenCanvasRenderingContext2D");
+
+// Calling getContext on a different context type will return null
+var ctx2 = aCanvas.getContext("webgl");
+shouldBeNull("ctx2");
+
+// Calling getContext on the same context type will return the original context type
+var ctx3 = aCanvas.getContext("2d");
+shouldBeNonNull("ctx3");
+shouldBeTrue("ctx3 == ctx");
+
+// TODO: change the below part of the test when webgl is supported.
+// Calling getContext on an unimplemented context type will return null
+var bogusCanvas = new OffscreenCanvas(20, 20);
+var bogusCtx = bogusCanvas.getContext("webgl");
+shouldBeNull("bogusCtx");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/atapply/at-apply-invalid-nesting.html b/third_party/WebKit/LayoutTests/fast/css/atapply/at-apply-invalid-nesting.html
index e0a472f7..00df0c6 100644
--- a/third_party/WebKit/LayoutTests/fast/css/atapply/at-apply-invalid-nesting.html
+++ b/third_party/WebKit/LayoutTests/fast/css/atapply/at-apply-invalid-nesting.html
@@ -11,7 +11,7 @@
     --red: { background-color: red; };
     --foo: {
         background-color: green;
-        var(--apply1) var(--apply2);
+        var(--apply1, ) var(--apply2, );
     };
     @apply --foo;
 }
@@ -21,7 +21,8 @@
 <script>
 test(function(){
     assert_equals(getComputedStyle(e).backgroundColor, "rgb(0, 128, 0)");
-    assert_equals(getComputedStyle(e).getPropertyValue("--foo"), " { background-color: green;  @apply  --red; }");
+    assert_equals(getComputedStyle(e).getPropertyValue("--apply1"), "");
+    assert_equals(getComputedStyle(e).getPropertyValue("--foo"), " { background-color: green;    --red; }");
 }, "@apply inside custom properties don't get expanded if the @apply rule was " +
    "constructed from variable references");
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/atapply/at-apply-invalid-syntax.html b/third_party/WebKit/LayoutTests/fast/css/atapply/at-apply-invalid-syntax.html
index 1cbf1e4..a578ce4 100644
--- a/third_party/WebKit/LayoutTests/fast/css/atapply/at-apply-invalid-syntax.html
+++ b/third_party/WebKit/LayoutTests/fast/css/atapply/at-apply-invalid-syntax.html
@@ -24,6 +24,12 @@
     --red2: { background-color: red; } bla ;
     @apply --red2;
 
+    --var1: @apply;
+    --var2: @apply foo;
+    --var3: @apply --red :/ ;
+    --var4: @apply --red @apply --red;
+    --var5: @apply --red {;
+
     width: 100px;
     height: 100px;
 
@@ -43,5 +49,10 @@
 <script>
 test(function(){
     assert_equals(getComputedStyle(e).backgroundColor, "rgb(0, 128, 0)");
+    assert_equals(getComputedStyle(e).getPropertyValue("--var1"), "");
+    assert_equals(getComputedStyle(e).getPropertyValue("--var2"), "");
+    assert_equals(getComputedStyle(e).getPropertyValue("--var3"), "");
+    assert_equals(getComputedStyle(e).getPropertyValue("--var4"), "");
+    assert_equals(getComputedStyle(e).getPropertyValue("--var5"), "");
 }, "Tests various invalid @apply rules get rejected");
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/parsing-unitless-length-quirk.html b/third_party/WebKit/LayoutTests/fast/css/parsing-unitless-length-quirk.html
index 1313ae6..2a2142b 100644
--- a/third_party/WebKit/LayoutTests/fast/css/parsing-unitless-length-quirk.html
+++ b/third_party/WebKit/LayoutTests/fast/css/parsing-unitless-length-quirk.html
@@ -195,7 +195,7 @@
     assert_equals(sheet.cssRules[44].style.background, "");
 }, "No unitless length quirk for background property");
 test(function(){
-    assert_equals(sheet.cssRules[45].style.background, "10px 50% rgb(255, 0, 0)");
+    assert_equals(sheet.cssRules[45].style.background, "10px center rgb(255, 0, 0)");
 }, "No unitless length quirk for background property");
 test(function(){
     assert_equals(sheet.cssRules[46].style.background, "");
diff --git a/third_party/WebKit/LayoutTests/fast/css/preferred-stylesheet-order-expected.txt b/third_party/WebKit/LayoutTests/fast/css/preferred-stylesheet-order-expected.txt
new file mode 100644
index 0000000..be77474
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/preferred-stylesheet-order-expected.txt
@@ -0,0 +1,12 @@
+Preferred stylesheet where insertion order is reversed tree order
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS getComputedStyle(t1).color is "rgb(0, 128, 0)"
+PASS document.preferredStylesheetSet is "preferred"
+PASS document.selectedStylesheetSet is "preferred"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+This text should be green
diff --git a/third_party/WebKit/LayoutTests/fast/css/preferred-stylesheet-order.html b/third_party/WebKit/LayoutTests/fast/css/preferred-stylesheet-order.html
new file mode 100644
index 0000000..b28225e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/preferred-stylesheet-order.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<script src="../../resources/js-test.js"></script>
+<div id="t1">This text should be green</div>
+<script>
+description("Preferred stylesheet where insertion order is reversed tree order");
+
+function createStyleElement(text, title) {
+    var elm = document.createElement("style");
+    elm.setAttribute("title", title);
+    elm.appendChild(document.createTextNode(text));
+    return elm;
+}
+
+document.head.appendChild(createStyleElement("#t1 {color:green}", "preferred"));
+document.head.appendChild(createStyleElement("#t1 {color:red}", "notpreferred"));
+
+shouldBeEqualToString("getComputedStyle(t1).color", "rgb(0, 128, 0)");
+shouldBeEqualToString("document.preferredStylesheetSet", "preferred");
+shouldBeEqualToString("document.selectedStylesheetSet", "preferred");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/preferred-stylesheet-reversed-order-expected.txt b/third_party/WebKit/LayoutTests/fast/css/preferred-stylesheet-reversed-order-expected.txt
new file mode 100644
index 0000000..b78f3a9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/preferred-stylesheet-reversed-order-expected.txt
@@ -0,0 +1,12 @@
+Preferred stylesheet where insertion order is tree order
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS getComputedStyle(t1).color is "rgb(0, 128, 0)"
+PASS document.preferredStylesheetSet is "preferred"
+PASS document.selectedStylesheetSet is "preferred"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+This text should be green
diff --git a/third_party/WebKit/LayoutTests/fast/css/preferred-stylesheet-reversed-order.html b/third_party/WebKit/LayoutTests/fast/css/preferred-stylesheet-reversed-order.html
new file mode 100644
index 0000000..f3278801
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/preferred-stylesheet-reversed-order.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<script src="../../resources/js-test.js"></script>
+<div id="t1">This text should be green</div>
+<script>
+description("Preferred stylesheet where insertion order is tree order");
+
+function createStyleElement(text, title) {
+    var elm = document.createElement("style");
+    elm.setAttribute("title", title);
+    elm.appendChild(document.createTextNode(text));
+    return elm;
+}
+
+document.head.insertBefore(createStyleElement("#t1 {color:green}", "preferred"), document.head.firstChild);
+document.head.insertBefore(createStyleElement("#t1 {color:red}", "notpreferred"), document.head.firstChild);
+
+shouldBeEqualToString("getComputedStyle(t1).color", "rgb(0, 128, 0)");
+shouldBeEqualToString("document.preferredStylesheetSet", "preferred");
+shouldBeEqualToString("document.selectedStylesheetSet", "preferred");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/pseudo-default-dynamic.html b/third_party/WebKit/LayoutTests/fast/css/pseudo-default-dynamic.html
index 73a2893..202af00e 100644
--- a/third_party/WebKit/LayoutTests/fast/css/pseudo-default-dynamic.html
+++ b/third_party/WebKit/LayoutTests/fast/css/pseudo-default-dynamic.html
@@ -4,8 +4,8 @@
 <div id="log"></div>
 <div id="container"></div>
 <style>
-button, input { background: red; }
-button:default, input:default { background: green; }
+button, input, option { background: red; }
+button:default, input:default, option:default { background: green; }
 </style>
 <script>
 // TODO(tkent): This should be merged to web-platform-tests/html/semantics/selectors/pseudo-classes/default.html.
@@ -86,4 +86,83 @@
     assert_equals(background('second'), NOT_DEFAULT);
 }, 'Adding a button by form content attribute should update the default button.');
 
+test(function() {
+    container.innerHTML = '<form><input type=checkbox checked id=c1><input type=text checked id=t1></form>';
+    assert_equals(background('c1'), DEFAULT);
+    assert_equals(background('t1'), NOT_DEFAULT);
+    document.querySelector('#c1').type = 'text';
+    document.querySelector('#t1').type = 'checkbox';
+    assert_equals(background('c1'), NOT_DEFAULT);
+    assert_equals(background('t1'), DEFAULT);
+}, 'Updating type attribute of :default checkbox should update default status');
+
+test(function() {
+    container.innerHTML = '<form><input type=radio checked id=r1><input type=text checked id=t1></form>';
+    assert_equals(background('r1'), DEFAULT);
+    assert_equals(background('t1'), NOT_DEFAULT);
+    document.querySelector('#r1').type = 'text';
+    document.querySelector('#t1').type = 'radio';
+    assert_equals(background('r1'), NOT_DEFAULT);
+    assert_equals(background('t1'), DEFAULT);
+}, 'Updating type attribute of :default radio should update default status');
+
+test(function() {
+    container.innerHTML = '<form><input type=checkbox checked id=c1><input type=radio checked id=r1></form>';
+    assert_equals(background('c1'), DEFAULT);
+    assert_equals(background('r1'), DEFAULT);
+    document.querySelector('#c1').defaultChecked = false;
+    document.querySelector('#r1').defaultChecked = false;
+    assert_equals(background('c1'), NOT_DEFAULT);
+    assert_equals(background('r1'), NOT_DEFAULT);
+}, 'Updating the checked attribute of :default checkbox or radio should update default status');
+
+test(function() {
+    container.innerHTML = '<form><input type=checkbox id=c1><input type=radio id=r1></form>';
+    assert_equals(background('c1'), NOT_DEFAULT);
+    assert_equals(background('r1'), NOT_DEFAULT);
+    if (window.eventSender){
+        var checkbox = document.querySelector('#c1');
+        checkbox.focus();
+        eventSender.keyDown(' ');
+        assert_equals(checkbox.checked, true);
+        assert_equals(background('c1'), NOT_DEFAULT);
+
+        var radio = document.querySelector('#r1');
+        radio.focus();
+        eventSender.keyDown(' ');
+        assert_equals(radio.checked, true);
+        assert_equals(background('r1'), NOT_DEFAULT);
+    }
+    document.querySelector('#c1').setAttribute('checked', 'checked');
+    document.querySelector('#r1').setAttribute('checked', 'checked');
+    assert_equals(background('c1'), DEFAULT);
+    assert_equals(background('r1'), DEFAULT);
+
+    document.querySelector('#c1').removeAttribute('checked');
+    document.querySelector('#r1').removeAttribute('checked');
+    assert_equals(background('c1'), NOT_DEFAULT);
+    assert_equals(background('r1'), NOT_DEFAULT);
+}, 'Dynamically updating checked status or setting checked attribute should reflect correct default status');
+
+test(function() {
+    container.innerHTML = '<form><select><option selected id=o1>1</option><option id=o2>2</option></select></form>';
+    assert_equals(background('o1'), DEFAULT);
+    assert_equals(background('o2'), NOT_DEFAULT);
+    document.querySelector('#o1').defaultSelected = false;
+    document.querySelector('#o2').defaultSelected = true;
+    assert_equals(background('o1'), NOT_DEFAULT);
+    assert_equals(background('o2'), DEFAULT);
+}, 'Updating the selected attribute of :default option element should update default status');
+
+test(function() {
+    container.innerHTML = '<form><select><option id=o1></option><option id=o2></option</select></form>';
+    assert_equals(background('o1'), NOT_DEFAULT);
+    document.querySelector('#o1').selected = true;
+    assert_equals(background('o1'), NOT_DEFAULT);
+    document.querySelector('#o1').setAttribute('selected', 'selected');
+    assert_equals(background('o1'), DEFAULT);
+    document.querySelector('#o1').removeAttribute('selected');
+    assert_equals(background('o1'), NOT_DEFAULT);
+}, 'Dynamically updating selected status or setting selected attribute should reflect correct default status');
+
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/serialize-style-with-all-crash-expected.txt b/third_party/WebKit/LayoutTests/fast/css/serialize-style-with-all-crash-expected.txt
new file mode 100644
index 0000000..43699ea
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/serialize-style-with-all-crash-expected.txt
@@ -0,0 +1,9 @@
+crbug.com/590412: this test checks that style is correctly serialized without any crashes when applying property-all after setting identity-box-chrome-color.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+PASS
diff --git a/third_party/WebKit/LayoutTests/fast/css/serialize-style-with-all-crash.html b/third_party/WebKit/LayoutTests/fast/css/serialize-style-with-all-crash.html
new file mode 100644
index 0000000..7ff0b84
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/serialize-style-with-all-crash.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<script src="../../resources/js-test.js"></script>
+<div id="target">PASS</div>
+<script>
+description("crbug.com/590412: this test checks that style is correctly serialized without any crashes when applying property-all after setting identity-box-chrome-color.");
+
+var target=document.getElementById("target")
+target.style.setProperty('--identity-box-chrome-color','important');
+target.style['all']='initial';
+// cloneNode serializes target's style internally.
+target.cloneNode();
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/HTMLImageElement/image-natural-width-height-svg-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/HTMLImageElement/image-natural-width-height-svg-expected.txt
index ae3d2ea5..b1acd09 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/HTMLImageElement/image-natural-width-height-svg-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/dom/HTMLImageElement/image-natural-width-height-svg-expected.txt
@@ -4,7 +4,7 @@
 FAIL naturalWidth/Height of SVG in <img>, width in pixels; height unspecified assert_equals: expected "500x0" but got "500x150"
 FAIL naturalWidth/Height of SVG in <img>, width in pixels; percentage height assert_equals: expected "500x0" but got "500x150"
 PASS naturalWidth/Height of SVG in <img>, width/height in pixels; viewBox 
-FAIL naturalWidth/Height of SVG in <img>, width/height unspecified; viewBox assert_equals: expected "0x0" but got "800x600"
+FAIL naturalWidth/Height of SVG in <img>, width/height unspecified; viewBox assert_equals: expected "0x0" but got "200x150"
 FAIL naturalWidth/Height of SVG in <img>, width in pixels; height unspecified; viewBox assert_equals: expected "400x0" but got "400x300"
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/resources/shadow-dom.js b/third_party/WebKit/LayoutTests/fast/dom/shadow/resources/shadow-dom.js
index 54800d4..80a1c00 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/shadow/resources/shadow-dom.js
+++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/resources/shadow-dom.js
@@ -1,3 +1,37 @@
+// TODO(yuzus): These two functions below need cleaning up. They are currently
+// from js-test.js.
+function getOrCreateTestElement(id, tagName)
+{
+    var element = document.getElementById(id);
+    if (element)
+        return element;
+
+    element = document.createElement(tagName);
+    element.id = id;
+    var refNode;
+    var parent = document.body || document.documentElement;
+    if (id == "description")
+        refNode = getOrCreateTestElement("console", "div");
+    else
+        refNode = parent.firstChild;
+
+    parent.insertBefore(element, refNode);
+    return element;
+}
+
+function debug(msg)
+{
+    if (self._lazyTestResults) {
+        self._lazyTestResults.push(msg);
+    } else {
+        var span = document.createElement("span");
+        // insert it first so XHTML knows the namespace;
+        getOrCreateTestElement("console", "div").appendChild(span);
+        span.innerHTML = msg + '<br />';
+    };
+}
+
+
 function createShadowRoot()
 {
     var children = Array.prototype.slice.call(arguments);
@@ -227,6 +261,7 @@
         debug('PASS');
     else
         debug('FAIL');
+    return isInnermostActiveElement(to);
 }
 
 function navigateFocusForward()
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/tabindex-slot.html b/third_party/WebKit/LayoutTests/fast/dom/shadow/tabindex-slot.html
index d5f73ce..6810bec 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/shadow/tabindex-slot.html
+++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/tabindex-slot.html
@@ -39,23 +39,6 @@
 
 <script>
 
-function shouldCustomNavigateFocus(from, to, direction)
-{   
-    var fromElement = getNodeInComposedTree(from);
-    if (!fromElement) {
-      return;
-    }
-    fromElement.focus();
-    if (!isInnermostActiveElement(from)) {
-        return;
-    }
-    if (direction == 'forward')
-        navigateFocusForward();
-    else
-        navigateFocusBackward();
-    return isInnermostActiveElement(to);
-}
-
 test(function() {
   var xfoo = document.getElementById('x-foo');
   convertTemplatesToShadowRootsWithin(xfoo);
@@ -80,10 +63,10 @@
   ];
 
   for (var i = 0; i + 1 < elements.length; ++i)
-      assert_true(shouldCustomNavigateFocus(elements[i], elements[i + 1], 'forward'), elements[i]+" to "+ elements[i+1]);
+      assert_true(shouldNavigateFocus(elements[i], elements[i + 1], 'forward'), elements[i]+" to "+ elements[i+1]);
   elements.reverse();
   for (var i = 0; i + 1 < elements.length; ++i)
-      assert_true(shouldCustomNavigateFocus(elements[i], elements[i + 1], 'backward'), elements[i]+" to "+ elements[i+1]);
+      assert_true(shouldNavigateFocus(elements[i], elements[i + 1], 'backward'), elements[i]+" to "+ elements[i+1]);
 }, 'Focus controller should treat slots as a focus scope.');
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/textarea/textarea-nowrap-paste-eol-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/textarea/textarea-nowrap-paste-eol-expected.txt
new file mode 100644
index 0000000..924a7fa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/textarea/textarea-nowrap-paste-eol-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL TEXTAREA with white-space:nowrap should not increase the number of EOLs assert_equals: expected "a\n\n   b\n" but got "a\n\n\n\n\n   b\n"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/fast/forms/textarea/textarea-nowrap-paste-eol.html b/third_party/WebKit/LayoutTests/fast/forms/textarea/textarea-nowrap-paste-eol.html
new file mode 100644
index 0000000..0bca8f1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/textarea/textarea-nowrap-paste-eol.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<body>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<div id="log"></div>
+<textarea style="white-space:nowrap"></textarea>
+<script>
+test(function() {
+    var textarea = document.querySelector('textarea');
+    textarea.focus();
+    textarea.addEventListener('copy', function(event) {
+        event.clipboardData.setData('text', 'a\r\n\r\n   b\r\n');
+        event.preventDefault();
+    });
+    document.execCommand('copy');
+    document.execCommand('paste');
+    // TODO(tkent): The following assertion fails now. crbug.com/2007 and
+    // crbug.com/528491.
+    assert_equals(textarea.value, 'a\n\n   b\n');
+}, 'TEXTAREA with white-space:nowrap should not increase the number of EOLs');
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/textarea/textarea-preline-eol-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/textarea/textarea-preline-eol-expected.txt
new file mode 100644
index 0000000..dac87d7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/textarea/textarea-preline-eol-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL TEXTAREA with white-space:pre-line should not produce nbsp by Enter key assert_equals: expected "P1\n\nP2\n\n\n\nP3\n" but got "P1\n\nP2\n\n \nP3\n"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/fast/forms/textarea/textarea-preline-eol.html b/third_party/WebKit/LayoutTests/fast/forms/textarea/textarea-preline-eol.html
new file mode 100644
index 0000000..781d49a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/textarea/textarea-preline-eol.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<body>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<div id="log"></div>
+<textarea style="white-space:pre-line">P1
+
+P2
+
+P3
+</textarea>
+<script>
+test(function() {
+    var textarea = document.querySelector('textarea');
+    textarea.focus();
+    textarea.setSelectionRange(7, 7); // Empty line between P2 and P3.
+    eventSender.keyDown('\n');
+    eventSender.keyDown('upArrow');
+    eventSender.keyDown('\n');
+    // TODO(tkent): The following assertion fails now. crbug.com/410417
+    assert_equals(textarea.value, 'P1\n\nP2\n\n\n\nP3\n');
+}, 'TEXTAREA with white-space:pre-line should not produce nbsp by Enter key');
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/textarea/textarea-value-last-eol-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/textarea/textarea-value-last-eol-expected.txt
new file mode 100644
index 0000000..f715bfd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/textarea/textarea-value-last-eol-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL TEXTAREA should not remove the last EOL on paste. assert_equals: expected "WH\n" but got "WH"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/fast/forms/textarea/textarea-value-last-eol.html b/third_party/WebKit/LayoutTests/fast/forms/textarea/textarea-value-last-eol.html
new file mode 100644
index 0000000..1664f53
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/textarea/textarea-value-last-eol.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<body>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<div id="log"></div>
+<textarea></textarea>
+<script>
+test(function() {
+    var textarea = document.querySelector('textarea');
+    textarea.focus();
+    eventSender.keyDown('H');
+    eventSender.keyDown('\n');
+    eventSender.keyDown('W');
+    assert_equals(textarea.value, 'H\nW');
+    textarea.setSelectionRange(2, 3); // "W"
+    document.execCommand('cut');
+    textarea.setSelectionRange(0, 0);
+    document.execCommand('paste');
+    // TODO(tkent): The following assertion fails now. crbug.com/522144.
+    assert_equals(textarea.value, 'WH\n');
+}, 'TEXTAREA should not remove the last EOL on paste.');
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/fast/hidpi/image-set-list-style-image-expected.html b/third_party/WebKit/LayoutTests/fast/hidpi/image-set-list-style-image-expected.html
new file mode 100644
index 0000000..52c59b0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/hidpi/image-set-list-style-image-expected.html
@@ -0,0 +1,2 @@
+<script src="resources/srcset-helper.js"></script>
+<img width=30 src="resources/deleteButton-2x.png">
diff --git a/third_party/WebKit/LayoutTests/fast/hidpi/image-set-list-style-image.html b/third_party/WebKit/LayoutTests/fast/hidpi/image-set-list-style-image.html
new file mode 100644
index 0000000..b23af9b5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/hidpi/image-set-list-style-image.html
@@ -0,0 +1,9 @@
+<script src="resources/srcset-helper.js"></script>
+<style>
+ul {
+    list-style-image: -webkit-image-set(url('resources/deleteButton.png') 1x, url('resources/deleteButton-2x.png') 2x);
+    list-style-position: inside;
+    padding: 0;
+}
+</style>
+<ul><li></ul>
diff --git a/third_party/WebKit/LayoutTests/fast/hidpi/image-set-shape-outside-expected.html b/third_party/WebKit/LayoutTests/fast/hidpi/image-set-shape-outside-expected.html
new file mode 100644
index 0000000..8f38854
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/hidpi/image-set-shape-outside-expected.html
@@ -0,0 +1,9 @@
+<style>
+.left {
+    float: left;
+    width: 30px;
+    height: 1em;
+}
+</style>
+<div class="left"></div>
+<img width=30 src="resources/deleteButton.png">
diff --git a/third_party/WebKit/LayoutTests/fast/hidpi/image-set-shape-outside.html b/third_party/WebKit/LayoutTests/fast/hidpi/image-set-shape-outside.html
new file mode 100644
index 0000000..ad1a5da36
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/hidpi/image-set-shape-outside.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<style>
+.left {
+    -webkit-shape-outside: -webkit-image-set(url('resources/deleteButton.png') 1x, url('resources/deleteButton-2x.png') 2x);
+    float: left;
+    width: 60px;
+    height: 1em;
+}
+</style>
+<div class="left"></div>
+<img width=30 src="resources/deleteButton.png">
diff --git a/third_party/WebKit/LayoutTests/fast/inspector-support/style-expected.txt b/third_party/WebKit/LayoutTests/fast/inspector-support/style-expected.txt
index 64ee892..a1f21b0 100644
--- a/third_party/WebKit/LayoutTests/fast/inspector-support/style-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/inspector-support/style-expected.txt
@@ -2,15 +2,15 @@
 Note that background is buggy right now!
 Test
 background-image: initial
+background-position-x: initial
+background-position-y: initial
+background-size: initial
 background-repeat-x: initial
 background-repeat-y: initial
 background-attachment: initial
-background-position-x: initial
-background-position-y: initial
 background-origin: initial
 background-clip: initial
 background-color: purple
-background-size: initial
 margin-top: 1em
 margin-right: 1em
 margin-bottom: 1em
diff --git a/third_party/WebKit/LayoutTests/fast/masking/parsing-mask-expected.txt b/third_party/WebKit/LayoutTests/fast/masking/parsing-mask-expected.txt
index c00c5ee..f372473 100644
--- a/third_party/WebKit/LayoutTests/fast/masking/parsing-mask-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/masking/parsing-mask-expected.txt
@@ -8,30 +8,30 @@
 PASS innerStyle("-webkit-mask", "none, none, none") is "none, none, none"
 PASS innerStyle("-webkit-mask", "url(file:///image.png), none") is "url(\"file:///image.png\"), none"
 PASS innerStyle("-webkit-mask", "none, url(file:///image.png)") is "none, url(\"file:///image.png\")"
-PASS innerStyle("-webkit-mask", "top left") is "0% 0%"
-PASS innerStyle("-webkit-mask", "bottom right") is "100% 100%"
-PASS innerStyle("-webkit-mask", "left bottom") is "0% 100%"
-PASS innerStyle("-webkit-mask", "right top") is "100% 0%"
-PASS innerStyle("-webkit-mask", "center") is "50% 50%"
-PASS innerStyle("-webkit-mask", "none top") is "none 50% 0%"
-PASS innerStyle("-webkit-mask", "none bottom") is "none 50% 100%"
-PASS innerStyle("-webkit-mask", "none right") is "none 100% 50%"
-PASS innerStyle("-webkit-mask", "none top right") is "none 100% 0%"
-PASS innerStyle("-webkit-mask", "none bottom left") is "none 0% 100%"
-PASS innerStyle("-webkit-mask", "none right") is "none 100% 50%"
-PASS innerStyle("-webkit-mask", "none left") is "none 0% 50%"
-PASS innerStyle("-webkit-mask", "center 50%") is "50% 50%"
+PASS innerStyle("-webkit-mask", "top left") is "left top"
+PASS innerStyle("-webkit-mask", "bottom right") is "right bottom"
+PASS innerStyle("-webkit-mask", "left bottom") is "left bottom"
+PASS innerStyle("-webkit-mask", "right top") is "right top"
+PASS innerStyle("-webkit-mask", "center") is "center center"
+PASS innerStyle("-webkit-mask", "none top") is "none center top"
+PASS innerStyle("-webkit-mask", "none bottom") is "none center bottom"
+PASS innerStyle("-webkit-mask", "none right") is "none right center"
+PASS innerStyle("-webkit-mask", "none top right") is "none right top"
+PASS innerStyle("-webkit-mask", "none bottom left") is "none left bottom"
+PASS innerStyle("-webkit-mask", "none right") is "none right center"
+PASS innerStyle("-webkit-mask", "none left") is "none left center"
+PASS innerStyle("-webkit-mask", "center 50%") is "center 50%"
 PASS innerStyle("-webkit-mask", "50px 50%") is "50px 50%"
-PASS innerStyle("-webkit-mask", "center left") is "0% 50%"
-PASS innerStyle("-webkit-mask", "top center") is "50% 0%"
+PASS innerStyle("-webkit-mask", "center left") is "left center"
+PASS innerStyle("-webkit-mask", "top center") is "center top"
 PASS innerStyle("-webkit-mask", "left 10px top 15px") is "left 10px top 15px"
 PASS innerStyle("-webkit-mask", "left 10% top 30%") is "left 10% top 30%"
-PASS innerStyle("-webkit-mask", "right top 15px") is "right 0% top 15px"
-PASS innerStyle("-webkit-mask", "left 10px center") is "left 10px top 50%"
-PASS innerStyle("-webkit-mask", "center top 20px") is "left 50% top 20px"
-PASS innerStyle("-webkit-mask", "center left 30px") is "left 30px top 50%"
-PASS innerStyle("-webkit-mask", "left 20% top") is "left 20% top 0%"
-PASS innerStyle("-webkit-mask", "center center") is "50% 50%"
+PASS innerStyle("-webkit-mask", "right top 15px") is "right top 15px"
+PASS innerStyle("-webkit-mask", "left 10px center") is "left 10px center"
+PASS innerStyle("-webkit-mask", "center top 20px") is "center top 20px"
+PASS innerStyle("-webkit-mask", "center left 30px") is "left 30px center"
+PASS innerStyle("-webkit-mask", "left 20% top") is "left 20% top"
+PASS innerStyle("-webkit-mask", "center center") is "center center"
 PASS innerStyle("-webkit-mask-position", "left 10px top 15px") is "left 10px top 15px"
 PASS innerStyle("-webkit-mask-position", "left 10% top 30%") is "left 10% top 30%"
 PASS innerStyle("-webkit-mask-position", "right top 15px") is "right top 15px"
@@ -67,25 +67,25 @@
 PASS innerStyle("-webkit-mask", "padding-box border-box") is "padding-box border-box"
 PASS innerStyle("-webkit-mask", "padding-box border-box none") is "none padding-box border-box"
 PASS innerStyle("-webkit-mask", "none padding-box border-box") is "none padding-box border-box"
-PASS innerStyle("-webkit-mask", "none left top / auto") is "none 0% 0% / auto"
-PASS innerStyle("-webkit-mask", "none left top / auto auto") is "none 0% 0% / auto"
-PASS innerStyle("-webkit-mask", "none left top / 100%") is "none 0% 0% / 100%"
-PASS innerStyle("-webkit-mask", "none left top / 100% 100%") is "none 0% 0% / 100% 100%"
-PASS innerStyle("-webkit-mask", "none left top / 0%") is "none 0% 0% / 0%"
-PASS innerStyle("-webkit-mask", "none left top / auto 0%") is "none 0% 0% / auto 0%"
-PASS innerStyle("-webkit-mask", "none left top / cover") is "none 0% 0% / cover"
-PASS innerStyle("-webkit-mask", "none left top / contain") is "none 0% 0% / contain"
+PASS innerStyle("-webkit-mask", "none left top / auto") is "none left top / auto"
+PASS innerStyle("-webkit-mask", "none left top / auto auto") is "none left top / auto"
+PASS innerStyle("-webkit-mask", "none left top / 100%") is "none left top / 100%"
+PASS innerStyle("-webkit-mask", "none left top / 100% 100%") is "none left top / 100% 100%"
+PASS innerStyle("-webkit-mask", "none left top / 0%") is "none left top / 0%"
+PASS innerStyle("-webkit-mask", "none left top / auto 0%") is "none left top / auto 0%"
+PASS innerStyle("-webkit-mask", "none left top / cover") is "none left top / cover"
+PASS innerStyle("-webkit-mask", "none left top / contain") is "none left top / contain"
 PASS innerStyle("-webkit-mask", "none left 20px top 10px / contain") is "none left 20px top 10px / contain"
-PASS innerStyle("-webkit-mask", "none left 20px top / contain") is "none left 20px top 0% / contain"
+PASS innerStyle("-webkit-mask", "none left 20px top / contain") is "none left 20px top / contain"
 PASS innerStyle("-webkit-mask", "none padding-box content-box") is "none padding-box content-box"
 PASS innerStyle("-webkit-mask", "none padding-box") is "none padding-box padding-box"
-PASS innerStyle("-webkit-mask", "none top") is "none 50% 0%"
-PASS innerStyle("-webkit-mask", "none center right 20px") is "none right 20px top 50%"
-PASS innerStyle("-webkit-mask", "none border-box left top") is "none 0% 0% border-box border-box"
-PASS innerStyle("-webkit-mask", "none border-box left top 20px") is "none left 0% top 20px border-box border-box"
-PASS innerStyle("-webkit-mask", "none border-box content-box left top repeat-x") is "none 0% 0% repeat-x border-box content-box"
-PASS innerStyle("-webkit-mask", "none border-box content-box left top / auto repeat-x") is "none 0% 0% / auto repeat-x border-box content-box"
-PASS innerStyle("-webkit-mask", "none border-box content-box right 0px center / auto repeat-x") is "none right 0px top 50% / auto repeat-x border-box content-box"
+PASS innerStyle("-webkit-mask", "none top") is "none center top"
+PASS innerStyle("-webkit-mask", "none center right 20px") is "none right 20px center"
+PASS innerStyle("-webkit-mask", "none border-box left top") is "none left top border-box border-box"
+PASS innerStyle("-webkit-mask", "none border-box left top 20px") is "none left top 20px border-box border-box"
+PASS innerStyle("-webkit-mask", "none border-box content-box left top repeat-x") is "none left top repeat-x border-box content-box"
+PASS innerStyle("-webkit-mask", "none border-box content-box left top / auto repeat-x") is "none left top / auto repeat-x border-box content-box"
+PASS innerStyle("-webkit-mask", "none border-box content-box right 0px center / auto repeat-x") is "none right 0px center / auto repeat-x border-box content-box"
 PASS innerStyle("-webkit-mask", "top none left") is ""
 PASS innerStyle("-webkit-mask", "right none bottom") is ""
 PASS innerStyle("-webkit-mask", "right right") is ""
diff --git a/third_party/WebKit/LayoutTests/fast/masking/parsing-mask.html b/third_party/WebKit/LayoutTests/fast/masking/parsing-mask.html
index 32f846ca..4511888c 100644
--- a/third_party/WebKit/LayoutTests/fast/masking/parsing-mask.html
+++ b/third_party/WebKit/LayoutTests/fast/masking/parsing-mask.html
@@ -50,30 +50,30 @@
 
 
 // test mask-position
-testInner("-webkit-mask", "top left", "0% 0%");
-testInner("-webkit-mask", "bottom right", "100% 100%");
-testInner("-webkit-mask", "left bottom", "0% 100%");
-testInner("-webkit-mask", "right top", "100% 0%");
-testInner("-webkit-mask", "center", "50% 50%");
-testInner("-webkit-mask", "none top", "none 50% 0%");
-testInner("-webkit-mask", "none bottom", "none 50% 100%");
-testInner("-webkit-mask", "none right", "none 100% 50%");
-testInner("-webkit-mask", "none top right", "none 100% 0%");
-testInner("-webkit-mask", "none bottom left", "none 0% 100%");
-testInner("-webkit-mask", "none right", "none 100% 50%");
-testInner("-webkit-mask", "none left", "none 0% 50%");
-testInner("-webkit-mask", "center 50%", "50% 50%");
+testInner("-webkit-mask", "top left", "left top");
+testInner("-webkit-mask", "bottom right", "right bottom");
+testInner("-webkit-mask", "left bottom", "left bottom");
+testInner("-webkit-mask", "right top", "right top");
+testInner("-webkit-mask", "center", "center center");
+testInner("-webkit-mask", "none top", "none center top");
+testInner("-webkit-mask", "none bottom", "none center bottom");
+testInner("-webkit-mask", "none right", "none right center");
+testInner("-webkit-mask", "none top right", "none right top");
+testInner("-webkit-mask", "none bottom left", "none left bottom");
+testInner("-webkit-mask", "none right", "none right center");
+testInner("-webkit-mask", "none left", "none left center");
+testInner("-webkit-mask", "center 50%", "center 50%");
 testInner("-webkit-mask", "50px 50%", "50px 50%");
-testInner("-webkit-mask", "center left", "0% 50%");
-testInner("-webkit-mask", "top center", "50% 0%");
+testInner("-webkit-mask", "center left", "left center");
+testInner("-webkit-mask", "top center", "center top");
 testInner("-webkit-mask", "left 10px top 15px", "left 10px top 15px");
 testInner("-webkit-mask", "left 10% top 30%", "left 10% top 30%");
-testInner("-webkit-mask", "right top 15px", "right 0% top 15px");
-testInner("-webkit-mask", "left 10px center", "left 10px top 50%");
-testInner("-webkit-mask", "center top 20px", "left 50% top 20px");
-testInner("-webkit-mask", "center left 30px", "left 30px top 50%");
-testInner("-webkit-mask", "left 20% top", "left 20% top 0%");
-testInner("-webkit-mask", "center center", "50% 50%");
+testInner("-webkit-mask", "right top 15px", "right top 15px");
+testInner("-webkit-mask", "left 10px center", "left 10px center");
+testInner("-webkit-mask", "center top 20px", "center top 20px");
+testInner("-webkit-mask", "center left 30px", "left 30px center");
+testInner("-webkit-mask", "left 20% top", "left 20% top");
+testInner("-webkit-mask", "center center", "center center");
 
 testInner("-webkit-mask-position", "left 10px top 15px", "left 10px top 15px");
 testInner("-webkit-mask-position", "left 10% top 30%", "left 10% top 30%");
@@ -118,27 +118,27 @@
 testInner("-webkit-mask", "none padding-box border-box", "none padding-box border-box");
 
 // test mask-size
-testInner("-webkit-mask", "none left top / auto", "none 0% 0% / auto");
-testInner("-webkit-mask", "none left top / auto auto", "none 0% 0% / auto");
-testInner("-webkit-mask", "none left top / 100%", "none 0% 0% / 100%");
-testInner("-webkit-mask", "none left top / 100% 100%", "none 0% 0% / 100% 100%");
-testInner("-webkit-mask", "none left top / 0%", "none 0% 0% / 0%");
-testInner("-webkit-mask", "none left top / auto 0%", "none 0% 0% / auto 0%");
-testInner("-webkit-mask", "none left top / cover", "none 0% 0% / cover");
-testInner("-webkit-mask", "none left top / contain", "none 0% 0% / contain");
+testInner("-webkit-mask", "none left top / auto", "none left top / auto");
+testInner("-webkit-mask", "none left top / auto auto", "none left top / auto");
+testInner("-webkit-mask", "none left top / 100%", "none left top / 100%");
+testInner("-webkit-mask", "none left top / 100% 100%", "none left top / 100% 100%");
+testInner("-webkit-mask", "none left top / 0%", "none left top / 0%");
+testInner("-webkit-mask", "none left top / auto 0%", "none left top / auto 0%");
+testInner("-webkit-mask", "none left top / cover", "none left top / cover");
+testInner("-webkit-mask", "none left top / contain", "none left top / contain");
 testInner("-webkit-mask", "none left 20px top 10px / contain", "none left 20px top 10px / contain");
-testInner("-webkit-mask", "none left 20px top / contain", "none left 20px top 0% / contain");
+testInner("-webkit-mask", "none left 20px top / contain", "none left 20px top / contain");
 
 // combinations
 testInner("-webkit-mask", "none padding-box content-box", "none padding-box content-box");
 testInner("-webkit-mask", "none padding-box", "none padding-box padding-box");
-testInner("-webkit-mask", "none top", "none 50% 0%");
-testInner("-webkit-mask", "none center right 20px", "none right 20px top 50%");
-testInner("-webkit-mask", "none border-box left top", "none 0% 0% border-box border-box");
-testInner("-webkit-mask", "none border-box left top 20px", "none left 0% top 20px border-box border-box");
-testInner("-webkit-mask", "none border-box content-box left top repeat-x", "none 0% 0% repeat-x border-box content-box");
-testInner("-webkit-mask", "none border-box content-box left top / auto repeat-x", "none 0% 0% / auto repeat-x border-box content-box");
-testInner("-webkit-mask", "none border-box content-box right 0px center / auto repeat-x", "none right 0px top 50% / auto repeat-x border-box content-box");
+testInner("-webkit-mask", "none top", "none center top");
+testInner("-webkit-mask", "none center right 20px", "none right 20px center");
+testInner("-webkit-mask", "none border-box left top", "none left top border-box border-box");
+testInner("-webkit-mask", "none border-box left top 20px", "none left top 20px border-box border-box");
+testInner("-webkit-mask", "none border-box content-box left top repeat-x", "none left top repeat-x border-box content-box");
+testInner("-webkit-mask", "none border-box content-box left top / auto repeat-x", "none left top / auto repeat-x border-box content-box");
+testInner("-webkit-mask", "none border-box content-box right 0px center / auto repeat-x", "none right 0px center / auto repeat-x border-box content-box");
 
 // FIXME: Computed style not yet implemented.
 // testComputed("-webkit-mask", "", "");
diff --git a/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-line-height-crash-expected.txt b/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-line-height-crash-expected.txt
index 9e16c0b2..0e74c24 100644
--- a/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-line-height-crash-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-line-height-crash-expected.txt
@@ -1,3 +1,4 @@
 CONSOLE ERROR: The shape-outside image is too large.
 CONSOLE ERROR: The shape-outside image is too large.
+CONSOLE ERROR: The shape-outside image is too large.
 This test passes if it doesn't crash.
diff --git a/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-line-height-crash2-expected.txt b/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-line-height-crash2-expected.txt
index 9e16c0b2..0e74c24 100644
--- a/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-line-height-crash2-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-line-height-crash2-expected.txt
@@ -1,3 +1,4 @@
 CONSOLE ERROR: The shape-outside image is too large.
 CONSOLE ERROR: The shape-outside image is too large.
+CONSOLE ERROR: The shape-outside image is too large.
 This test passes if it doesn't crash.
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/cors-rfc1918/addressspace-document-appcache.html b/third_party/WebKit/LayoutTests/http/tests/security/cors-rfc1918/addressspace-document-appcache.html
new file mode 100644
index 0000000..c2ac4f9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/cors-rfc1918/addressspace-document-appcache.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/addressspace-test.js"></script>
+<script>
+    window.onload = function () {
+        addressSpaceTest("http://localhost:8000", "document+appcache", "local",
+            // If we request the same resources again, we should load them from the
+            // memory cache with the same properties.
+            function () {
+                addressSpaceTest("http://localhost:8000", "document+appcache", "local");
+            });
+        addressSpaceTest("http://127.0.0.1:8000", "document", "local",
+            // If we request the same resources again, we should load them from the
+            // memory cache with the same properties.
+            function () {
+                addressSpaceTest("http://127.0.0.1:8000", "document+appcache", "local");
+            });
+
+        addressSpaceTest("http://example.test:8000", "document+appcache", "private",
+            // If we request the same resources again, we should load them from the
+            // memory cache with the same properties.
+            function () {
+                addressSpaceTest("http://example.test:8000", "document+appcache", "private");
+            });
+    };
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/cors-rfc1918/addressspace-document-csp-appcache.html b/third_party/WebKit/LayoutTests/http/tests/security/cors-rfc1918/addressspace-document-csp-appcache.html
new file mode 100644
index 0000000..b77a776
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/cors-rfc1918/addressspace-document-csp-appcache.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/addressspace-test.js"></script>
+<script>
+    window.onload = function () {
+        addressSpaceTest("http://localhost:8000", "document+appcache+csp", "public",
+            // If we request the same resources again, we should load them from the
+            // memory cache with the same properties.
+            function () {
+                addressSpaceTest("http://localhost:8000", "document+appcache+csp", "public");
+            });
+        addressSpaceTest("http://127.0.0.1:8000", "document+appcache+csp", "public",
+            // If we request the same resources again, we should load them from the
+            // memory cache with the same properties.
+            function () {
+                addressSpaceTest("http://127.0.0.1:8000", "document+appcache+csp", "public");
+            });
+
+        addressSpaceTest("http://example.test:8000", "document+appcache+csp", "public",
+            // If we request the same resources again, we should load them from the
+            // memory cache with the same properties.
+            function () {
+                addressSpaceTest("http://example.test:8000", "document+appcache+csp", "public");
+            });
+    };
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/cors-rfc1918/resources/addressspace-test.js b/third_party/WebKit/LayoutTests/http/tests/security/cors-rfc1918/resources/addressspace-test.js
index 8e019a5..c7738bbf 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/cors-rfc1918/resources/addressspace-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/security/cors-rfc1918/resources/addressspace-test.js
@@ -4,6 +4,10 @@
         file = "post-addressspace-to-parent.html";
     } else if (type == "document+csp") {
         file = "post-addressspace-to-parent.html?csp";
+    } else if (type == "document+appcache") {
+        file = "post-addressspace-to-parent-with-appcache.html";
+    } else if (type == "document+appcache+csp") {
+        file = "post-addressspace-to-parent-with-appcache.html?csp";
     } else if (type == "worker") {
         file = "post-addressspace-from-worker.html";
     } else if (type == "sharedworker") {
@@ -15,13 +19,15 @@
     return i;
 }
 
-function addressSpaceTest(origin, type, expected) {
+function addressSpaceTest(origin, type, expected, callback) {
     async_test(function (t) {
         var i = createIFrame(origin, type);
         window.addEventListener("message", t.step_func(function (e) {
             if (e.source == i.contentWindow) {
                 assert_equals(e.data.origin, origin);
                 assert_equals(e.data.addressSpace, expected);
+                if (callback)
+                    callback();
                 t.done();
             }
         }));
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/cors-rfc1918/resources/appcache.php b/third_party/WebKit/LayoutTests/http/tests/security/cors-rfc1918/resources/appcache.php
new file mode 100644
index 0000000..7265cb2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/cors-rfc1918/resources/appcache.php
@@ -0,0 +1,5 @@
+<?php
+header("Content-Type: text/cache-manifest");
+print("CACHE MANIFEST\n\n");
+print("post-addressspace-to-parent-with-appcache.html");
+?>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/cors-rfc1918/resources/post-addressspace-to-parent-with-appcache.html b/third_party/WebKit/LayoutTests/http/tests/security/cors-rfc1918/resources/post-addressspace-to-parent-with-appcache.html
new file mode 100644
index 0000000..cf75676
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/cors-rfc1918/resources/post-addressspace-to-parent-with-appcache.html
@@ -0,0 +1,16 @@
+<html manifest="/security/cors-rfc1918/resources/appcache.php">
+<script>
+    if (window.location.search == "?csp") {
+        var m = document.createElement("meta");
+        m.setAttribute("http-equiv", "Content-Security-Policy");
+        m.setAttribute("content", "treat-as-public-address");
+        document.head.appendChild(m);
+    }
+
+    window.applicationCache.oncached = window.applicationCache.onnoupdate = function (e) {
+        window.parent.postMessage({
+            "origin": window.location.origin,
+            "addressSpace": document.addressSpace
+        }, "*");
+    }
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index ddf65c1..7890480f 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -476,8 +476,21 @@
     getter height
     getter width
     method constructor
+    method getContext
     setter height
     setter width
+interface OffscreenCanvasRenderingContext2D
+    getter offscreenCanvas
+    method arc
+    method arcTo
+    method bezierCurveTo
+    method closePath
+    method constructor
+    method ellipse
+    method lineTo
+    method moveTo
+    method quadraticCurveTo
+    method rect
 interface PerformanceObserverEntryList
     method constructor
     method getEntries
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/semantics/tabular-data/the-tbody-element/deleteRow-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/semantics/tabular-data/the-tbody-element/deleteRow-expected.txt
deleted file mode 100644
index 89e17977..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/semantics/tabular-data/the-tbody-element/deleteRow-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-This is a testharness.js-based test.
-PASS HTMLTableSectionElement deleteRow(0) 
-PASS HTMLTableSectionElement deleteRow(-1) 
-PASS HTMLTableSectionElement deleteRow(rows.length) 
-PASS HTMLTableSectionElement deleteRow(-2) 
-FAIL HTMLTableSectionElement deleteRow(-1) with no rows Failed to execute 'deleteRow' on 'HTMLTableSectionElement': The provided index (-1 is outside the range [-1, 0].
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-new-API-expected.txt b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-new-API-expected.txt
index 806e8ef..c2b28cb 100644
--- a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-new-API-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-new-API-expected.txt
@@ -40,15 +40,15 @@
 body.main2: [regular, 23:0-23:10] {
     ['background':'green /* value !important comment */ !important /* no semicolon, very !important */' is-important] @[23:11-23:106] 
     ['background-image':'initial' is-important] @[undefined-undefined] 
+    ['background-position-x':'initial' is-important] @[undefined-undefined] 
+    ['background-position-y':'initial' is-important] @[undefined-undefined] 
+    ['background-size':'initial' is-important] @[undefined-undefined] 
     ['background-repeat-x':'initial' is-important] @[undefined-undefined] 
     ['background-repeat-y':'initial' is-important] @[undefined-undefined] 
     ['background-attachment':'initial' is-important] @[undefined-undefined] 
-    ['background-position-x':'initial' is-important] @[undefined-undefined] 
-    ['background-position-y':'initial' is-important] @[undefined-undefined] 
     ['background-origin':'initial' is-important] @[undefined-undefined] 
     ['background-clip':'initial' is-important] @[undefined-undefined] 
     ['background-color':'green' is-important] @[undefined-undefined] 
-    ['background-size':'initial' is-important] @[undefined-undefined] 
 }
 body.mainpage: [regular, 3:0-3:13] {
     ['text-decoration':'none'] @[4:4-4:26] 
@@ -116,15 +116,15 @@
 body.main2: [regular, 23:0-23:10] {
     ['background':'green /* value !important comment */ !important /* no semicolon, very !important */' is-important] @[23:11-23:106] 
     ['background-image':'initial' is-important] @[undefined-undefined] 
+    ['background-position-x':'initial' is-important] @[undefined-undefined] 
+    ['background-position-y':'initial' is-important] @[undefined-undefined] 
+    ['background-size':'initial' is-important] @[undefined-undefined] 
     ['background-repeat-x':'initial' is-important] @[undefined-undefined] 
     ['background-repeat-y':'initial' is-important] @[undefined-undefined] 
     ['background-attachment':'initial' is-important] @[undefined-undefined] 
-    ['background-position-x':'initial' is-important] @[undefined-undefined] 
-    ['background-position-y':'initial' is-important] @[undefined-undefined] 
     ['background-origin':'initial' is-important] @[undefined-undefined] 
     ['background-clip':'initial' is-important] @[undefined-undefined] 
     ['background-color':'green' is-important] @[undefined-undefined] 
-    ['background-size':'initial' is-important] @[undefined-undefined] 
 }
 body.mainpage: [regular, 3:0-3:13] {
     ['text-decoration':'none'] @[4:4-4:26] 
@@ -194,15 +194,15 @@
 body.main2: [regular, 23:0-23:10] {
     ['background':'green /* value !important comment */ !important /* no semicolon, very !important */' is-important] @[23:11-23:106] 
     ['background-image':'initial' is-important] @[undefined-undefined] 
+    ['background-position-x':'initial' is-important] @[undefined-undefined] 
+    ['background-position-y':'initial' is-important] @[undefined-undefined] 
+    ['background-size':'initial' is-important] @[undefined-undefined] 
     ['background-repeat-x':'initial' is-important] @[undefined-undefined] 
     ['background-repeat-y':'initial' is-important] @[undefined-undefined] 
     ['background-attachment':'initial' is-important] @[undefined-undefined] 
-    ['background-position-x':'initial' is-important] @[undefined-undefined] 
-    ['background-position-y':'initial' is-important] @[undefined-undefined] 
     ['background-origin':'initial' is-important] @[undefined-undefined] 
     ['background-clip':'initial' is-important] @[undefined-undefined] 
     ['background-color':'green' is-important] @[undefined-undefined] 
-    ['background-size':'initial' is-important] @[undefined-undefined] 
 }
 body.mainpage: [regular, 3:0-3:13] {
     ['text-decoration':'none'] @[4:4-4:26] 
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/svg/as-border-image/svg-as-border-image-2-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/svg/as-border-image/svg-as-border-image-2-expected.txt
index 828795e..290e3de 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-retina/svg/as-border-image/svg-as-border-image-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/svg/as-border-image/svg-as-border-image-2-expected.txt
@@ -1,4 +1,3 @@
-CONSOLE WARNING: Elements using the 'border-image' CSS property with no 'border-style' set should have no border, but currently do. Setting 'border-style' will be required in M51, around May 2016. See https://www.chromestatus.com/features/5542503914668032 for more details.
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
 layer at (0,0) size 800x600
@@ -9,17 +8,17 @@
           LayoutText {#text} at (0,0) size 195x28
             text run at (0,0) width 195: "SVG border-image"
         LayoutBlockFlow (anonymous) at (1,68.81) size 368x368
-          LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px none #000000)]
+          LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,166) size 4x18
             text run at (180,166) width 4: " "
-          LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px none #000000)]
+          LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (364,166) size 4x18
             text run at (364,166) width 4: " "
           LayoutBR {BR} at (0,0) size 0x0
-          LayoutBlockFlow {DIV} at (10,194) size 160x160 [border: (30px none #000000)]
+          LayoutBlockFlow {DIV} at (10,194) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,350) size 4x18
             text run at (180,350) width 4: " "
-          LayoutBlockFlow {DIV} at (194,194) size 160x160 [border: (30px none #000000)]
+          LayoutBlockFlow {DIV} at (194,194) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (0,0) size 0x0
       LayoutText {#text} at (370,418) size 4x18
         text run at (370,418) width 4: " "
@@ -28,16 +27,16 @@
           LayoutText {#text} at (0,0) size 196x28
             text run at (0,0) width 196: "PNG border-image"
         LayoutBlockFlow (anonymous) at (1,68.81) size 368x368
-          LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px none #000000)]
+          LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,166) size 4x18
             text run at (180,166) width 4: " "
-          LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px none #000000)]
+          LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (364,166) size 4x18
             text run at (364,166) width 4: " "
           LayoutBR {BR} at (0,0) size 0x0
-          LayoutBlockFlow {DIV} at (10,194) size 160x160 [border: (30px none #000000)]
+          LayoutBlockFlow {DIV} at (10,194) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,350) size 4x18
             text run at (180,350) width 4: " "
-          LayoutBlockFlow {DIV} at (194,194) size 160x160 [border: (30px none #000000)]
+          LayoutBlockFlow {DIV} at (194,194) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (0,0) size 0x0
       LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/svg/as-border-image/svg-as-border-image-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/svg/as-border-image/svg-as-border-image-expected.txt
index 828795e..290e3de 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-retina/svg/as-border-image/svg-as-border-image-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/svg/as-border-image/svg-as-border-image-expected.txt
@@ -1,4 +1,3 @@
-CONSOLE WARNING: Elements using the 'border-image' CSS property with no 'border-style' set should have no border, but currently do. Setting 'border-style' will be required in M51, around May 2016. See https://www.chromestatus.com/features/5542503914668032 for more details.
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
 layer at (0,0) size 800x600
@@ -9,17 +8,17 @@
           LayoutText {#text} at (0,0) size 195x28
             text run at (0,0) width 195: "SVG border-image"
         LayoutBlockFlow (anonymous) at (1,68.81) size 368x368
-          LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px none #000000)]
+          LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,166) size 4x18
             text run at (180,166) width 4: " "
-          LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px none #000000)]
+          LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (364,166) size 4x18
             text run at (364,166) width 4: " "
           LayoutBR {BR} at (0,0) size 0x0
-          LayoutBlockFlow {DIV} at (10,194) size 160x160 [border: (30px none #000000)]
+          LayoutBlockFlow {DIV} at (10,194) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,350) size 4x18
             text run at (180,350) width 4: " "
-          LayoutBlockFlow {DIV} at (194,194) size 160x160 [border: (30px none #000000)]
+          LayoutBlockFlow {DIV} at (194,194) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (0,0) size 0x0
       LayoutText {#text} at (370,418) size 4x18
         text run at (370,418) width 4: " "
@@ -28,16 +27,16 @@
           LayoutText {#text} at (0,0) size 196x28
             text run at (0,0) width 196: "PNG border-image"
         LayoutBlockFlow (anonymous) at (1,68.81) size 368x368
-          LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px none #000000)]
+          LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,166) size 4x18
             text run at (180,166) width 4: " "
-          LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px none #000000)]
+          LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (364,166) size 4x18
             text run at (364,166) width 4: " "
           LayoutBR {BR} at (0,0) size 0x0
-          LayoutBlockFlow {DIV} at (10,194) size 160x160 [border: (30px none #000000)]
+          LayoutBlockFlow {DIV} at (10,194) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,350) size 4x18
             text run at (180,350) width 4: " "
-          LayoutBlockFlow {DIV} at (194,194) size 160x160 [border: (30px none #000000)]
+          LayoutBlockFlow {DIV} at (194,194) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (0,0) size 0x0
       LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/svg/as-list-image/svg-list-image-intrinsic-size-zoom.html b/third_party/WebKit/LayoutTests/svg/as-list-image/svg-list-image-intrinsic-size-zoom.html
index 7e9f7f5..67c687a 100644
--- a/third_party/WebKit/LayoutTests/svg/as-list-image/svg-list-image-intrinsic-size-zoom.html
+++ b/third_party/WebKit/LayoutTests/svg/as-list-image/svg-list-image-intrinsic-size-zoom.html
@@ -1,24 +1,29 @@
 <!DOCTYPE html>
-<title>Zoomed SVG in list-style-image</title>
+<title>Zoomed SVG and raster image in list-style-image</title>
 <script src="../../resources/testharness.js"></script>
 <script src="../../resources/testharnessreport.js"></script>
 <style>
   ul { font-family: Ahem; }
   ul li {
-      list-style-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'><rect width='1' height='1' fill='green'/></svg>");
-      font-size: 30px;
+      font-size: 250px;
       color: green;
       list-style-position: inside;
       line-height: 1em;
   }
+  ul li.svg {
+      list-style-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'><rect width='1' height='1' fill='green'/></svg>");
+  }
+  ul li.png {
+      list-style-image: url("../filters/resources/green.png");
+  }
 </style>
-<ul><li></ul>
+<ul><li class="svg"><li class="png"></ul>
 <script>
   var ul = document.querySelector('ul');
-  [ 2, 3, 4, 5, 1].forEach(function(zoom) {
+  [ 2, 3, 4, 5, 0.5, 0.2, 1].forEach(function(zoom) {
       test(function() {
           document.body.style.zoom = zoom;
-          assert_approx_equals(ul.getBoundingClientRect().height, 30, 0.5);
+          assert_approx_equals(ul.getBoundingClientRect().height, 500, 0.5);
       }, 'Zoom to ' + zoom + " and list height should be equal to line-height");
   });
 </script>
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/animations/inline-block-transform.html b/third_party/WebKit/LayoutTests/virtual/threaded/animations/inline-block-transform.html
new file mode 100644
index 0000000..cb7efc3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/threaded/animations/inline-block-transform.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<div id=target style="display:inline-block"></div>
+<script>
+var test = async_test('inline-block should run compositor animations');
+var anim = target.animate({transform: ['rotate(0deg)', 'rotate(180deg)']}, 100000);
+anim.ready.then(() => {
+  test.step(() => assert_true(internals.isCompositedAnimation(anim)));
+  test.done();
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
index ff3cd52d..1c761a13 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -451,8 +451,21 @@
 [Worker]     getter height
 [Worker]     getter width
 [Worker]     method constructor
+[Worker]     method getContext
 [Worker]     setter height
 [Worker]     setter width
+[Worker] interface OffscreenCanvasRenderingContext2D
+[Worker]     getter offscreenCanvas
+[Worker]     method arc
+[Worker]     method arcTo
+[Worker]     method bezierCurveTo
+[Worker]     method closePath
+[Worker]     method constructor
+[Worker]     method ellipse
+[Worker]     method lineTo
+[Worker]     method moveTo
+[Worker]     method quadraticCurveTo
+[Worker]     method rect
 [Worker] interface PerformanceObserverEntryList
 [Worker]     method constructor
 [Worker]     method getEntries
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index db02c2af..204bbd11 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -3696,8 +3696,21 @@
     getter height
     getter width
     method constructor
+    method getContext
     setter height
     setter width
+interface OffscreenCanvasRenderingContext2D
+    getter offscreenCanvas
+    method arc
+    method arcTo
+    method bezierCurveTo
+    method closePath
+    method constructor
+    method ellipse
+    method lineTo
+    method moveTo
+    method quadraticCurveTo
+    method rect
 interface Option
     method constructor
 interface OscillatorNode : AudioSourceNode
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
index 389dc39..2893e6f 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -439,8 +439,21 @@
 [Worker]     getter height
 [Worker]     getter width
 [Worker]     method constructor
+[Worker]     method getContext
 [Worker]     setter height
 [Worker]     setter width
+[Worker] interface OffscreenCanvasRenderingContext2D
+[Worker]     getter offscreenCanvas
+[Worker]     method arc
+[Worker]     method arcTo
+[Worker]     method bezierCurveTo
+[Worker]     method closePath
+[Worker]     method constructor
+[Worker]     method ellipse
+[Worker]     method lineTo
+[Worker]     method moveTo
+[Worker]     method quadraticCurveTo
+[Worker]     method rect
 [Worker] interface PerformanceObserverEntryList
 [Worker]     method constructor
 [Worker]     method getEntries
diff --git a/third_party/WebKit/Source/bindings/core/v8/ReadableStreamOperationsTest.cpp b/third_party/WebKit/Source/bindings/core/v8/ReadableStreamOperationsTest.cpp
index 49ddfe5..a76e6d0 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ReadableStreamOperationsTest.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ReadableStreamOperationsTest.cpp
@@ -12,7 +12,6 @@
 #include "bindings/core/v8/V8BindingForTesting.h"
 #include "bindings/core/v8/V8BindingMacros.h"
 #include "bindings/core/v8/V8IteratorResultValue.h"
-#include "bindings/core/v8/V8RecursionScope.h"
 #include "bindings/core/v8/V8ThrowException.h"
 #include "core/dom/Document.h"
 #include "core/streams/ReadableStreamController.h"
@@ -139,7 +138,7 @@
     ~ReadableStreamOperationsTest() override
     {
         // Execute all pending microtasks
-        v8::MicrotasksScope::PerformCheckpoint(isolate());
+        isolate()->RunMicrotasks();
         EXPECT_FALSE(m_block.HasCaught());
     }
 
@@ -150,7 +149,6 @@
     {
         v8::Local<v8::String> source;
         v8::Local<v8::Script> script;
-        V8RecursionScope::MicrotaskSuppression microtasks(isolate());
         if (!v8Call(v8::String::NewFromUtf8(isolate(), s, v8::NewStringType::kNormal), source)) {
             ADD_FAILURE();
             return ScriptValue();
@@ -255,12 +253,12 @@
         Function::createFunction(scriptState(), it2),
         NotReached::createFunction(scriptState()));
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     EXPECT_FALSE(it1->isSet());
     EXPECT_FALSE(it2->isSet());
 
     ASSERT_FALSE(evalWithPrintingError("controller.enqueue('hello')").isEmpty());
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     EXPECT_TRUE(it1->isSet());
     EXPECT_TRUE(it1->isValid());
     EXPECT_FALSE(it1->isDone());
@@ -268,7 +266,7 @@
     EXPECT_FALSE(it2->isSet());
 
     ASSERT_FALSE(evalWithPrintingError("controller.close()").isEmpty());
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     EXPECT_TRUE(it1->isSet());
     EXPECT_TRUE(it1->isValid());
     EXPECT_FALSE(it1->isDone());
@@ -311,7 +309,7 @@
     ReadableStreamOperations::read(scriptState(), reader).then(Function::createFunction(scriptState(), it2), NotReached::createFunction(scriptState()));
     ReadableStreamOperations::read(scriptState(), reader).then(Function::createFunction(scriptState(), it3), NotReached::createFunction(scriptState()));
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_EQ(10, underlyingSource->desiredSize());
 
@@ -328,7 +326,7 @@
     EXPECT_FALSE(it3->isSet());
 
     underlyingSource->close();
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_TRUE(it3->isSet());
     EXPECT_TRUE(it3->isValid());
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptPromisePropertyTest.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptPromisePropertyTest.cpp
index f6601dd3..34f2d7ca 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptPromisePropertyTest.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptPromisePropertyTest.cpp
@@ -281,7 +281,7 @@
     property()->resolve(value);
     EXPECT_EQ(Property::Resolved, property()->getState());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     EXPECT_EQ(1u, nResolveCalls);
     EXPECT_EQ(1u, nOtherResolveCalls);
     EXPECT_EQ(wrap(mainWorld(), value), actual);
@@ -307,7 +307,7 @@
     property()->resolve(value);
     EXPECT_EQ(Property::Resolved, property()->getState());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     EXPECT_EQ(1u, nResolveCalls);
     EXPECT_EQ(0u, nOtherResolveCalls);
 
@@ -316,7 +316,7 @@
         otherPromise.then(stub(currentScriptState(), otherActual, nOtherResolveCalls), notReached(currentScriptState()));
     }
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     EXPECT_EQ(1u, nResolveCalls);
     EXPECT_EQ(1u, nOtherResolveCalls);
     EXPECT_EQ(wrap(mainWorld(), value), actual);
@@ -343,7 +343,7 @@
         property()->promise(otherWorld()).then(notReached(currentScriptState()), stub(currentScriptState(), otherActual, nOtherRejectCalls));
     }
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     EXPECT_EQ(1u, nRejectCalls);
     EXPECT_EQ(wrap(mainWorld(), reason), actual);
     EXPECT_EQ(1u, nOtherRejectCalls);
@@ -374,7 +374,7 @@
     property()->resolve(new GarbageCollectedScriptWrappable("value"));
     EXPECT_EQ(Property::Pending, property()->getState());
 
-    v8::MicrotasksScope::PerformCheckpoint(v8::Isolate::GetCurrent());
+    v8::Isolate::GetCurrent()->RunMicrotasks();
 }
 
 TEST_F(ScriptPromisePropertyGarbageCollectedTest, Reset)
@@ -405,7 +405,7 @@
     EXPECT_EQ(0u, nOldResolveCalls);
     EXPECT_EQ(0u, nNewRejectCalls);
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     EXPECT_EQ(1u, nOldResolveCalls);
     EXPECT_EQ(1u, nNewRejectCalls);
     EXPECT_NE(oldPromise, newPromise);
@@ -445,7 +445,7 @@
     property()->resolve(value.get());
     EXPECT_EQ(Property::Resolved, property()->getState());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     EXPECT_EQ(1u, nResolveCalls);
     EXPECT_EQ(wrap(mainWorld(), value), actual);
 }
@@ -464,7 +464,7 @@
     property()->reject(reason);
     EXPECT_EQ(Property::Rejected, property()->getState());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     EXPECT_EQ(1u, nRejectCalls);
     EXPECT_EQ(wrap(mainWorld(), reason), actual);
 }
@@ -514,7 +514,7 @@
             property->promise(DOMWrapperWorld::mainWorld()).then(stub(currentScriptState(), actualValue, nResolveCalls), notReached(currentScriptState()));
         }
         property->resolve(value);
-        v8::MicrotasksScope::PerformCheckpoint(isolate());
+        isolate()->RunMicrotasks();
         {
             ScriptState::Scope scope(mainScriptState());
             actual = toCoreString(actualValue.v8Value()->ToString(mainScriptState()->context()).ToLocalChecked());
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseResolverTest.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseResolverTest.cpp
index 1c946d9..b6cf586 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseResolverTest.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseResolverTest.cpp
@@ -60,7 +60,7 @@
         createClosure(callback, v8::Undefined(isolate()), isolate());
 
         // Execute all pending microtasks
-        v8::MicrotasksScope::PerformCheckpoint(isolate());
+        isolate()->RunMicrotasks();
     }
 
     OwnPtr<DummyPageHolder> m_pageHolder;
@@ -96,7 +96,7 @@
     EXPECT_EQ(String(), onFulfilled);
     EXPECT_EQ(String(), onRejected);
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_EQ(String(), onFulfilled);
     EXPECT_EQ(String(), onRejected);
@@ -111,14 +111,14 @@
     EXPECT_EQ(String(), onFulfilled);
     EXPECT_EQ(String(), onRejected);
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_EQ("hello", onFulfilled);
     EXPECT_EQ(String(), onRejected);
 
     resolver->resolve("bye");
     resolver->reject("bye");
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_EQ("hello", onFulfilled);
     EXPECT_EQ(String(), onRejected);
@@ -144,7 +144,7 @@
     EXPECT_EQ(String(), onFulfilled);
     EXPECT_EQ(String(), onRejected);
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_EQ(String(), onFulfilled);
     EXPECT_EQ(String(), onRejected);
@@ -159,14 +159,14 @@
     EXPECT_EQ(String(), onFulfilled);
     EXPECT_EQ(String(), onRejected);
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_EQ(String(), onFulfilled);
     EXPECT_EQ("hello", onRejected);
 
     resolver->resolve("bye");
     resolver->reject("bye");
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_EQ(String(), onFulfilled);
     EXPECT_EQ("hello", onRejected);
@@ -196,7 +196,7 @@
     }
 
     resolver->resolve("hello");
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_EQ(String(), onFulfilled);
     EXPECT_EQ(String(), onRejected);
@@ -321,7 +321,7 @@
     }
 
     resolver->resolve();
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_EQ("undefined", onFulfilled);
     EXPECT_EQ(String(), onRejected);
@@ -345,7 +345,7 @@
     }
 
     resolver->reject();
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_EQ(String(), onFulfilled);
     EXPECT_EQ("undefined", onRejected);
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseTest.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseTest.cpp
index 01d144e..5c3fec7 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseTest.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseTest.cpp
@@ -83,7 +83,7 @@
         createClosure(callback, v8::Undefined(m_scope.isolate()), m_scope.isolate());
 
         // Execute all pending microtasks
-        v8::MicrotasksScope::PerformCheckpoint(isolate());
+        isolate()->RunMicrotasks();
     }
 
     String toString(const ScriptValue& value)
@@ -124,13 +124,13 @@
     EXPECT_TRUE(onFulfilled.isEmpty());
     EXPECT_TRUE(onRejected.isEmpty());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     resolver.resolve(v8String(isolate(), "hello"));
 
     EXPECT_TRUE(onFulfilled.isEmpty());
     EXPECT_TRUE(onRejected.isEmpty());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_EQ("hello", toString(onFulfilled));
     EXPECT_TRUE(onRejected.isEmpty());
@@ -148,7 +148,7 @@
     EXPECT_TRUE(onFulfilled.isEmpty());
     EXPECT_TRUE(onRejected.isEmpty());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_EQ("hello", toString(onFulfilled));
     EXPECT_TRUE(onRejected.isEmpty());
@@ -165,13 +165,13 @@
     EXPECT_TRUE(onFulfilled.isEmpty());
     EXPECT_TRUE(onRejected.isEmpty());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     resolver.reject(v8String(isolate(), "hello"));
 
     EXPECT_TRUE(onFulfilled.isEmpty());
     EXPECT_TRUE(onRejected.isEmpty());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_TRUE(onFulfilled.isEmpty());
     EXPECT_EQ("hello", toString(onRejected));
@@ -189,7 +189,7 @@
     EXPECT_TRUE(onFulfilled.isEmpty());
     EXPECT_TRUE(onRejected.isEmpty());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_TRUE(onFulfilled.isEmpty());
     EXPECT_EQ("hello", toString(onRejected));
@@ -226,7 +226,7 @@
     EXPECT_TRUE(onRejected1.isEmpty());
     EXPECT_TRUE(onRejected2.isEmpty());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_EQ("hello", toString(onFulfilled1));
     EXPECT_EQ("hello", toString(onFulfilled2));
@@ -248,7 +248,7 @@
     EXPECT_TRUE(onFulfilled.isEmpty());
     EXPECT_TRUE(onRejected.isEmpty());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_TRUE(onFulfilled.isEmpty());
     EXPECT_EQ("hello", toString(onRejected));
@@ -264,7 +264,7 @@
     EXPECT_TRUE(onFulfilled.isEmpty());
     EXPECT_TRUE(onRejected.isEmpty());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_TRUE(onFulfilled.isEmpty());
     EXPECT_EQ("SyntaxError: some syntax error", toString(onRejected));
@@ -282,7 +282,7 @@
     EXPECT_TRUE(onFulfilled.isEmpty());
     EXPECT_TRUE(onRejected.isEmpty());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_FALSE(onFulfilled.isEmpty());
     EXPECT_TRUE(toStringArray(onFulfilled).isEmpty());
@@ -304,7 +304,7 @@
     EXPECT_TRUE(onFulfilled.isEmpty());
     EXPECT_TRUE(onRejected.isEmpty());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_FALSE(onFulfilled.isEmpty());
     Vector<String> values = toStringArray(onFulfilled);
@@ -329,7 +329,7 @@
     EXPECT_TRUE(onFulfilled.isEmpty());
     EXPECT_TRUE(onRejected.isEmpty());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_TRUE(onFulfilled.isEmpty());
     EXPECT_FALSE(onRejected.isEmpty());
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp b/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp
index f0a8dfd..bafc93d7 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp
@@ -321,7 +321,7 @@
 
     v8::Debug::SetLiveEditEnabled(isolate, false);
 
-    isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kScoped);
+    isolate->SetAutorunMicrotasks(false);
 }
 
 namespace {
@@ -351,15 +351,10 @@
 
 } // namespace
 
-void V8Initializer::initializeMainThreadIfNeeded()
+void V8Initializer::initializeMainThread()
 {
     ASSERT(isMainThread());
 
-    static bool initialized = false;
-    if (initialized)
-        return;
-    initialized = true;
-
     DEFINE_STATIC_LOCAL(ArrayBufferAllocator, arrayBufferAllocator, ());
     auto v8ExtrasMode = RuntimeEnabledFeatures::experimentalV8ExtrasEnabled() ? gin::IsolateHolder::kStableAndExperimentalV8Extras : gin::IsolateHolder::kStableV8Extras;
     gin::IsolateHolder::Initialize(gin::IsolateHolder::kNonStrictMode, v8ExtrasMode, &arrayBufferAllocator);
@@ -384,6 +379,14 @@
         profiler->SetWrapperClassInfoProvider(WrapperTypeInfo::NodeClassId, &RetainedDOMInfo::createRetainedDOMInfo);
 }
 
+void V8Initializer::shutdownMainThread()
+{
+    ASSERT(isMainThread());
+    v8::Isolate* isolate = V8PerIsolateData::mainThreadIsolate();
+    V8PerIsolateData::willBeDestroyed(isolate);
+    V8PerIsolateData::destroy(isolate);
+}
+
 static void reportFatalErrorInWorker(const char* location, const char* message)
 {
     // FIXME: We temporarily deal with V8 internal error situations such as out-of-memory by crashing the worker.
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8Initializer.h b/third_party/WebKit/Source/bindings/core/v8/V8Initializer.h
index c17256d..7fe4bbf 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8Initializer.h
+++ b/third_party/WebKit/Source/bindings/core/v8/V8Initializer.h
@@ -35,7 +35,8 @@
 class CORE_EXPORT V8Initializer {
     STATIC_ONLY(V8Initializer);
 public:
-    static void initializeMainThreadIfNeeded();
+    static void initializeMainThread();
+    static void shutdownMainThread();
     static void initializeWorker(v8::Isolate*);
 
     static void reportRejectedPromisesOnMainThread();
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8PerIsolateData.cpp b/third_party/WebKit/Source/bindings/core/v8/V8PerIsolateData.cpp
index 65c02bc..0a2cfcb9 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8PerIsolateData.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8PerIsolateData.cpp
@@ -30,6 +30,7 @@
 #include "bindings/core/v8/V8Binding.h"
 #include "bindings/core/v8/V8HiddenValue.h"
 #include "bindings/core/v8/V8ObjectConstructor.h"
+#include "bindings/core/v8/V8RecursionScope.h"
 #include "bindings/core/v8/V8ScriptRunner.h"
 #include "core/frame/Deprecation.h"
 #include "core/inspector/MainThreadDebugger.h"
@@ -52,6 +53,18 @@
     V8PerIsolateData::from(isolate)->runEndOfScopeTasks();
 }
 
+#if ENABLE(ASSERT)
+static void assertV8RecursionScope(v8::Isolate* isolate)
+{
+    ASSERT(V8RecursionScope::properlyUsed(isolate));
+}
+
+static bool runningUnitTest()
+{
+    return Platform::current()->unitTestSupport();
+}
+#endif
+
 static void useCounterCallback(v8::Isolate* isolate, v8::Isolate::UseCounterFeature feature)
 {
     UseCounter::Feature blinkFeature;
@@ -130,15 +143,25 @@
 }
 
 V8PerIsolateData::V8PerIsolateData()
-    : m_isolateHolder(adoptPtr(new gin::IsolateHolder()))
+    : m_destructionPending(false)
+    , m_isolateHolder(adoptPtr(new gin::IsolateHolder()))
     , m_stringCache(adoptPtr(new StringCache(isolate())))
     , m_hiddenValue(V8HiddenValue::create())
     , m_constructorMode(ConstructorMode::CreateNewObject)
+    , m_recursionLevel(0)
     , m_isHandlingRecursionLevelError(false)
     , m_isReportingException(false)
+#if ENABLE(ASSERT)
+    , m_internalScriptRecursionLevel(0)
+#endif
+    , m_performingMicrotaskCheckpoint(false)
 {
     // FIXME: Remove once all v8::Isolate::GetCurrent() calls are gone.
     isolate()->Enter();
+#if ENABLE(ASSERT)
+    if (!runningUnitTest())
+        isolate()->AddCallCompletedCallback(&assertV8RecursionScope);
+#endif
     isolate()->AddBeforeCallEnteredCallback(&beforeCallEnteredCallback);
     isolate()->AddMicrotasksCompletedCallback(&microtasksCompletedCallback);
     if (isMainThread())
@@ -183,6 +206,9 @@
 {
     V8PerIsolateData* data = from(isolate);
 
+    ASSERT(!data->m_destructionPending);
+    data->m_destructionPending = true;
+
     data->m_threadDebugger.clear();
     // Clear any data that may have handles into the heap,
     // prior to calling ThreadState::detach().
@@ -193,6 +219,10 @@
 // gets called but before the Isolate exits.
 void V8PerIsolateData::destroy(v8::Isolate* isolate)
 {
+#if ENABLE(ASSERT)
+    if (!runningUnitTest())
+        isolate->RemoveCallCompletedCallback(&assertV8RecursionScope);
+#endif
     isolate->RemoveBeforeCallEnteredCallback(&beforeCallEnteredCallback);
     isolate->RemoveMicrotasksCompletedCallback(&microtasksCompletedCallback);
     V8PerIsolateData* data = from(isolate);
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8PerIsolateData.h b/third_party/WebKit/Source/bindings/core/v8/V8PerIsolateData.h
index 33ed8dc8..5d709e736 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8PerIsolateData.h
+++ b/third_party/WebKit/Source/bindings/core/v8/V8PerIsolateData.h
@@ -74,18 +74,31 @@
 
     static void enableIdleTasks(v8::Isolate*, PassOwnPtr<gin::V8IdleTaskRunner>);
 
+    bool destructionPending() const { return m_destructionPending; }
     v8::Isolate* isolate() { return m_isolateHolder->isolate(); }
 
     StringCache* stringCache() { return m_stringCache.get(); }
 
     v8::Persistent<v8::Value>& ensureLiveRoot();
 
+    int recursionLevel() const { return m_recursionLevel; }
+    int incrementRecursionLevel() { return ++m_recursionLevel; }
+    int decrementRecursionLevel() { return --m_recursionLevel; }
     bool isHandlingRecursionLevelError() const { return m_isHandlingRecursionLevelError; }
     void setIsHandlingRecursionLevelError(bool value) { m_isHandlingRecursionLevelError = value; }
 
     bool isReportingException() const { return m_isReportingException; }
     void setReportingException(bool value) { m_isReportingException = value; }
 
+    bool performingMicrotaskCheckpoint() const { return m_performingMicrotaskCheckpoint; }
+    void setPerformingMicrotaskCheckpoint(bool performingMicrotaskCheckpoint) { m_performingMicrotaskCheckpoint = performingMicrotaskCheckpoint; }
+
+#if ENABLE(ASSERT)
+    int internalScriptRecursionLevel() const { return m_internalScriptRecursionLevel; }
+    int incrementInternalScriptRecursionLevel() { return ++m_internalScriptRecursionLevel; }
+    int decrementInternalScriptRecursionLevel() { return --m_internalScriptRecursionLevel; }
+#endif
+
     V8HiddenValue* hiddenValue() { return m_hiddenValue.get(); }
 
     v8::Local<v8::FunctionTemplate> domTemplate(const void* domTemplateKey, v8::FunctionCallback = 0, v8::Local<v8::Value> data = v8::Local<v8::Value>(), v8::Local<v8::Signature> = v8::Local<v8::Signature>(), int length = 0);
@@ -118,6 +131,7 @@
     bool hasInstance(const WrapperTypeInfo* untrusted, v8::Local<v8::Value>, DOMTemplateMap&);
     v8::Local<v8::Object> findInstanceInPrototypeChain(const WrapperTypeInfo*, v8::Local<v8::Value>, DOMTemplateMap&);
 
+    bool m_destructionPending;
     OwnPtr<gin::IsolateHolder> m_isolateHolder;
     DOMTemplateMap m_domTemplateMapForMainWorld;
     DOMTemplateMap m_domTemplateMapForNonMainWorld;
@@ -129,9 +143,15 @@
     bool m_constructorMode;
     friend class ConstructorMode;
 
+    int m_recursionLevel;
     bool m_isHandlingRecursionLevelError;
     bool m_isReportingException;
 
+#if ENABLE(ASSERT)
+    int m_internalScriptRecursionLevel;
+#endif
+    bool m_performingMicrotaskCheckpoint;
+
     Vector<OwnPtr<EndOfScopeTask>> m_endOfScopeTasks;
     OwnPtr<ThreadDebugger> m_threadDebugger;
 };
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8RecursionScope.cpp b/third_party/WebKit/Source/bindings/core/v8/V8RecursionScope.cpp
index b4c3acf7..ed10e86 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8RecursionScope.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8RecursionScope.cpp
@@ -30,6 +30,13 @@
 
 #include "bindings/core/v8/V8RecursionScope.h"
 
+#include "core/dom/Microtask.h"
+
 namespace blink {
 
+void V8RecursionScope::didLeaveScriptContext()
+{
+    Microtask::performCheckpoint(m_isolate);
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8RecursionScope.h b/third_party/WebKit/Source/bindings/core/v8/V8RecursionScope.h
index 8bbd26c..dd9a51f 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8RecursionScope.h
+++ b/third_party/WebKit/Source/bindings/core/v8/V8RecursionScope.h
@@ -59,39 +59,63 @@
     STACK_ALLOCATED();
 public:
     explicit V8RecursionScope(v8::Isolate* isolate)
-        : m_scope(isolate, v8::MicrotasksScope::kRunMicrotasks)
+        : m_isolate(isolate)
     {
-        ASSERT(isolate->GetMicrotasksPolicy() == v8::MicrotasksPolicy::kScoped);
+        V8PerIsolateData::from(m_isolate)->incrementRecursionLevel();
+        // If you want V8 to autorun microtasks, this class needs to have a
+        // v8::Isolate::SuppressMicrotaskExecutionScope member.
+        ASSERT(!isolate->WillAutorunMicrotasks());
     }
 
     ~V8RecursionScope()
     {
+        if (!V8PerIsolateData::from(m_isolate)->decrementRecursionLevel())
+            didLeaveScriptContext();
     }
 
     static int recursionLevel(v8::Isolate* isolate)
     {
-        return v8::MicrotasksScope::GetCurrentDepth(isolate);
+        return V8PerIsolateData::from(isolate)->recursionLevel();
     }
 
+#if ENABLE(ASSERT)
+    static bool properlyUsed(v8::Isolate* isolate)
+    {
+        return recursionLevel(isolate) > 0 || V8PerIsolateData::from(isolate)->internalScriptRecursionLevel() > 0;
+    }
+#endif
+
     class MicrotaskSuppression {
         USING_FAST_MALLOC(MicrotaskSuppression);
         WTF_MAKE_NONCOPYABLE(MicrotaskSuppression);
     public:
-        explicit MicrotaskSuppression(v8::Isolate* isolate)
-            : m_scope(isolate, v8::MicrotasksScope::kDoNotRunMicrotasks)
+        MicrotaskSuppression(v8::Isolate* isolate)
+#if ENABLE(ASSERT)
+            : m_isolate(isolate)
+#endif
         {
+#if ENABLE(ASSERT)
+            V8PerIsolateData::from(m_isolate)->incrementInternalScriptRecursionLevel();
+#endif
         }
 
         ~MicrotaskSuppression()
         {
+#if ENABLE(ASSERT)
+            V8PerIsolateData::from(m_isolate)->decrementInternalScriptRecursionLevel();
+#endif
         }
 
     private:
-        v8::MicrotasksScope m_scope;
+#if ENABLE(ASSERT)
+        v8::Isolate* m_isolate;
+#endif
     };
 
 private:
-    v8::MicrotasksScope m_scope;
+    void didLeaveScriptContext();
+
+    v8::Isolate* m_isolate;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/animation/CompositorAnimations.cpp b/third_party/WebKit/Source/core/animation/CompositorAnimations.cpp
index 221fe6bc..ba39698 100644
--- a/third_party/WebKit/Source/core/animation/CompositorAnimations.cpp
+++ b/third_party/WebKit/Source/core/animation/CompositorAnimations.cpp
@@ -254,7 +254,7 @@
             return false;
 
         if (isTransformRelatedCSSProperty(property)) {
-            if (targetElement.layoutObject() && targetElement.layoutObject()->isInline()) {
+            if (targetElement.layoutObject() && targetElement.layoutObject()->isInline() && !targetElement.layoutObject()->isInlineBlockOrInlineTable()) {
                 return false;
             }
             transformPropertyCount++;
diff --git a/third_party/WebKit/Source/core/core.gypi b/third_party/WebKit/Source/core/core.gypi
index ebc628c8..ce975660 100644
--- a/third_party/WebKit/Source/core/core.gypi
+++ b/third_party/WebKit/Source/core/core.gypi
@@ -242,7 +242,6 @@
             'html/TimeRanges.idl',
             'html/ValidityState.idl',
             'html/VoidCallback.idl',
-            'html/canvas/OffscreenCanvas.idl',
             'html/track/AudioTrack.idl',
             'html/track/AudioTrackList.idl',
             'html/track/TextTrack.idl',
@@ -806,6 +805,7 @@
             'style/StyleBoxData.cpp',
             'style/StyleContentAlignmentData.h',
             'style/StyleDeprecatedFlexibleBoxData.cpp',
+            'style/StyleImage.cpp',
             'style/StyleFetchedImage.cpp',
             'style/StyleFetchedImageSet.cpp',
             'style/StyleFilterData.cpp',
@@ -1528,8 +1528,6 @@
             'editing/commands/SplitTextNodeCommand.h',
             'editing/commands/SplitTextNodeContainingElementCommand.cpp',
             'editing/commands/SplitTextNodeContainingElementCommand.h',
-            'editing/commands/TextInsertionBaseCommand.cpp',
-            'editing/commands/TextInsertionBaseCommand.h',
             'editing/commands/TypingCommand.cpp',
             'editing/commands/TypingCommand.h',
             'editing/commands/UndoStack.cpp',
@@ -2986,8 +2984,6 @@
             'html/canvas/CanvasRenderingContext.cpp',
             'html/canvas/CanvasRenderingContext.h',
             'html/canvas/CanvasRenderingContextFactory.h',
-            'html/canvas/OffscreenCanvas.cpp',
-            'html/canvas/OffscreenCanvas.h',
             'html/forms/BaseButtonInputType.cpp',
             'html/forms/BaseButtonInputType.h',
             'html/forms/BaseCheckableInputType.cpp',
diff --git a/third_party/WebKit/Source/core/css/CSSCrossfadeValue.cpp b/third_party/WebKit/Source/core/css/CSSCrossfadeValue.cpp
index 426c6b5..c657f2b 100644
--- a/third_party/WebKit/Source/core/css/CSSCrossfadeValue.cpp
+++ b/third_party/WebKit/Source/core/css/CSSCrossfadeValue.cpp
@@ -159,7 +159,7 @@
     return CSSCrossfadeValue::create(fromValue.release(), toValue.release(), m_percentageValue);
 }
 
-IntSize CSSCrossfadeValue::fixedSize(const LayoutObject* layoutObject)
+IntSize CSSCrossfadeValue::fixedSize(const LayoutObject* layoutObject, const FloatSize& defaultObjectSize)
 {
     Image* fromImage = renderableImageForCSSValue(m_fromValue.get(), layoutObject);
     Image* toImage = renderableImageForCSSValue(m_toValue.get(), layoutObject);
@@ -170,6 +170,12 @@
     IntSize fromImageSize = fromImage->size();
     IntSize toImageSize = toImage->size();
 
+    if (fromImage->isSVGImage())
+        fromImageSize = roundedIntSize(toSVGImage(fromImage)->concreteObjectSize(defaultObjectSize));
+
+    if (toImage->isSVGImage())
+        toImageSize = roundedIntSize(toSVGImage(toImage)->concreteObjectSize(defaultObjectSize));
+
     // Rounding issues can cause transitions between images of equal size to return
     // a different fixed size; avoid performing the interpolation if the images are the same size.
     if (fromImageSize == toImageSize)
@@ -237,7 +243,7 @@
     if (toImage->isSVGImage())
         toImageRef = SVGImageForContainer::create(toSVGImage(toImage), size, 1, urlForCSSValue(m_toValue.get()));
 
-    m_generatedImage = CrossfadeGeneratedImage::create(fromImageRef, toImageRef, m_percentageValue->getFloatValue(), fixedSize(layoutObject), size);
+    m_generatedImage = CrossfadeGeneratedImage::create(fromImageRef, toImageRef, m_percentageValue->getFloatValue(), fixedSize(layoutObject, FloatSize(size)), size);
 
     return m_generatedImage.release();
 }
diff --git a/third_party/WebKit/Source/core/css/CSSCrossfadeValue.h b/third_party/WebKit/Source/core/css/CSSCrossfadeValue.h
index 0a3a9d6..4ecacbe 100644
--- a/third_party/WebKit/Source/core/css/CSSCrossfadeValue.h
+++ b/third_party/WebKit/Source/core/css/CSSCrossfadeValue.h
@@ -54,7 +54,7 @@
 
     PassRefPtr<Image> image(const LayoutObject*, const IntSize&);
     bool isFixedSize() const { return true; }
-    IntSize fixedSize(const LayoutObject*);
+    IntSize fixedSize(const LayoutObject*, const FloatSize&);
 
     bool isPending() const;
     bool knownToBeOpaque(const LayoutObject*) const;
diff --git a/third_party/WebKit/Source/core/css/CSSFontSelector.cpp b/third_party/WebKit/Source/core/css/CSSFontSelector.cpp
index 7c432eb..65b0d4d 100644
--- a/third_party/WebKit/Source/core/css/CSSFontSelector.cpp
+++ b/third_party/WebKit/Source/core/css/CSSFontSelector.cpp
@@ -176,8 +176,7 @@
     if (!document.settings())
         return;
     m_genericFontFamilySettings = document.settings()->genericFontFamilySettings();
-    // Need to increment FontFaceCache version to update ComputedStyles.
-    m_fontFaceCache.incrementVersion();
+    fontCacheInvalidated();
 }
 
 DEFINE_TRACE(CSSFontSelector)
diff --git a/third_party/WebKit/Source/core/css/CSSImageGeneratorValue.cpp b/third_party/WebKit/Source/core/css/CSSImageGeneratorValue.cpp
index df434dd..e1bf097 100644
--- a/third_party/WebKit/Source/core/css/CSSImageGeneratorValue.cpp
+++ b/third_party/WebKit/Source/core/css/CSSImageGeneratorValue.cpp
@@ -155,11 +155,11 @@
     return false;
 }
 
-IntSize CSSImageGeneratorValue::fixedSize(const LayoutObject* layoutObject)
+IntSize CSSImageGeneratorValue::fixedSize(const LayoutObject* layoutObject, const FloatSize& defaultObjectSize)
 {
     switch (getClassType()) {
     case CrossfadeClass:
-        return toCSSCrossfadeValue(this)->fixedSize(layoutObject);
+        return toCSSCrossfadeValue(this)->fixedSize(layoutObject, defaultObjectSize);
     case LinearGradientClass:
         return toCSSLinearGradientValue(this)->fixedSize(layoutObject);
     case RadialGradientClass:
diff --git a/third_party/WebKit/Source/core/css/CSSImageGeneratorValue.h b/third_party/WebKit/Source/core/css/CSSImageGeneratorValue.h
index f286127..0291834 100644
--- a/third_party/WebKit/Source/core/css/CSSImageGeneratorValue.h
+++ b/third_party/WebKit/Source/core/css/CSSImageGeneratorValue.h
@@ -37,6 +37,7 @@
 class Document;
 class Image;
 class LayoutObject;
+class FloatSize;
 
 struct SizeAndCount {
     DISALLOW_NEW();
@@ -61,7 +62,7 @@
     PassRefPtr<Image> image(const LayoutObject*, const IntSize&);
 
     bool isFixedSize() const;
-    IntSize fixedSize(const LayoutObject*);
+    IntSize fixedSize(const LayoutObject*, const FloatSize& defaultObjectSize);
 
     bool isPending() const;
     bool knownToBeOpaque(const LayoutObject*) const;
diff --git a/third_party/WebKit/Source/core/css/StylePropertySerializer.cpp b/third_party/WebKit/Source/core/css/StylePropertySerializer.cpp
index 7596bafd..8f8cf72 100644
--- a/third_party/WebKit/Source/core/css/StylePropertySerializer.cpp
+++ b/third_party/WebKit/Source/core/css/StylePropertySerializer.cpp
@@ -60,6 +60,8 @@
                 continue;
             m_needToExpandAll = true;
         }
+        if (property.id() < firstCSSProperty || property.id() > lastCSSProperty)
+            continue;
         m_longhandPropertyUsed.set(property.id() - firstCSSProperty);
     }
 }
@@ -105,6 +107,8 @@
         StylePropertySet::PropertyReference property = m_propertySet->propertyAt(index);
         if (property.id() == CSSPropertyAll || !CSSProperty::isAffectedByAllProperty(property.id()))
             return true;
+        if (property.id() < firstCSSProperty || property.id() > lastCSSProperty)
+            return false;
         return m_longhandPropertyUsed.get(property.id() - firstCSSProperty);
     }
 
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
index c1c015f..6e57c22 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -4560,6 +4560,93 @@
     return true;
 }
 
+// Note: consumeBackgroundShorthand assumes y properties (for example background-position-y) follow
+// the x properties in the shorthand array.
+bool CSSPropertyParser::consumeBackgroundShorthand(const StylePropertyShorthand& shorthand, bool important)
+{
+    const unsigned longhandCount = shorthand.length();
+    RefPtrWillBeRawPtr<CSSValue> longhands[10];
+    ASSERT(longhandCount <= 10);
+#if ENABLE(OILPAN)
+    // Zero initialize the array of raw pointers.
+    memset(&longhands, 0, sizeof(longhands));
+#endif
+    bool implicit = false;
+    do {
+        bool parsedLonghand[10] = { false };
+        RefPtrWillBeRawPtr<CSSValue> originValue = nullptr;
+        do {
+            bool foundProperty = false;
+            for (size_t i = 0; i < longhandCount; ++i) {
+                if (parsedLonghand[i])
+                    continue;
+
+                RefPtrWillBeRawPtr<CSSValue> value = nullptr;
+                RefPtrWillBeRawPtr<CSSValue> valueY = nullptr;
+                CSSPropertyID property = shorthand.properties()[i];
+                if (property == CSSPropertyBackgroundRepeatX || property == CSSPropertyWebkitMaskRepeatX) {
+                    consumeRepeatStyleComponent(m_range, value, valueY, implicit);
+                } else if (property == CSSPropertyBackgroundPositionX || property == CSSPropertyWebkitMaskPositionX) {
+                    CSSParserTokenRange rangeCopy = m_range;
+                    if (!consumePosition(rangeCopy, m_context.mode(), UnitlessQuirk::Forbid, value, valueY))
+                        continue;
+                    m_range = rangeCopy;
+                } else if (property == CSSPropertyBackgroundSize || property == CSSPropertyWebkitMaskSize) {
+                    if (!consumeSlashIncludingWhitespace(m_range))
+                        continue;
+                    value = consumeBackgroundSize(property, m_range, m_context.mode());
+                    if (!value || !parsedLonghand[i - 1]) // Position must have been parsed in the current layer.
+                        return false;
+                } else if (property == CSSPropertyBackgroundPositionY || property == CSSPropertyBackgroundRepeatY
+                    || property == CSSPropertyWebkitMaskPositionY || property == CSSPropertyWebkitMaskRepeatY) {
+                    continue;
+                } else {
+                    value = consumeBackgroundComponent(property, m_range, m_context);
+                }
+                if (value) {
+                    if (property == CSSPropertyBackgroundOrigin || property == CSSPropertyWebkitMaskOrigin)
+                        originValue = value;
+                    parsedLonghand[i] = true;
+                    foundProperty = true;
+                    addBackgroundValue(longhands[i], value.release());
+                    if (valueY) {
+                        parsedLonghand[i + 1] = true;
+                        addBackgroundValue(longhands[i + 1], valueY.release());
+                    }
+                }
+            }
+            if (!foundProperty)
+                return false;
+        } while (!m_range.atEnd() && m_range.peek().type() != CommaToken);
+
+        // TODO(timloh): This will make invalid longhands, see crbug.com/386459
+        for (size_t i = 0; i < longhandCount; ++i) {
+            CSSPropertyID property = shorthand.properties()[i];
+            if (property == CSSPropertyBackgroundColor && !m_range.atEnd()) {
+                if (parsedLonghand[i])
+                    return false; // Colors are only allowed in the last layer.
+                continue;
+            }
+            if ((property == CSSPropertyBackgroundClip || property == CSSPropertyWebkitMaskClip) && !parsedLonghand[i] && originValue) {
+                addBackgroundValue(longhands[i], originValue.release());
+                continue;
+            }
+            if (!parsedLonghand[i])
+                addBackgroundValue(longhands[i], cssValuePool().createImplicitInitialValue());
+        }
+    } while (consumeCommaIncludingWhitespace(m_range));
+    if (!m_range.atEnd())
+        return false;
+
+    for (size_t i = 0; i < longhandCount; ++i) {
+        CSSPropertyID property = shorthand.properties()[i];
+        if (property == CSSPropertyBackgroundSize && longhands[i] && m_context.useLegacyBackgroundSizeShorthandBehavior())
+            continue;
+        addProperty(property, longhands[i].release(), important, implicit);
+    }
+    return true;
+}
+
 bool CSSPropertyParser::parseShorthand(CSSPropertyID unresolvedProperty, bool important)
 {
     CSSPropertyID property = resolveCSSPropertyID(unresolvedProperty);
@@ -4722,6 +4809,10 @@
         addProperty(property == CSSPropertyBackgroundRepeat ? CSSPropertyBackgroundRepeatY : CSSPropertyWebkitMaskRepeatY, resultY.release(), important, implicit);
         return true;
     }
+    case CSSPropertyBackground:
+        return consumeBackgroundShorthand(backgroundShorthand(), important);
+    case CSSPropertyWebkitMask:
+        return consumeBackgroundShorthand(webkitMaskShorthand(), important);
     default:
         m_currentShorthand = oldShorthand;
         CSSParserValueList valueList(m_range);
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
index 63148814..82c214f 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
@@ -154,6 +154,7 @@
 
     // Legacy parsing allows <string>s for animation-name
     bool consumeAnimationShorthand(const StylePropertyShorthand&, bool useLegacyParsing, bool important);
+    bool consumeBackgroundShorthand(const StylePropertyShorthand&, bool important);
 
     bool consumeColumns(bool important);
 
diff --git a/third_party/WebKit/Source/core/css/parser/CSSVariableParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSVariableParser.cpp
index a54302e..f75d27d 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSVariableParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSVariableParser.cpp
@@ -48,10 +48,14 @@
         const CSSParserToken& token = range.consume();
         switch (token.type()) {
         case AtKeywordToken: {
-            // This might have false positives if the @apply doesn't actually match
-            // the syntax, but that just means we do extra computation work.
-            if (token.valueEqualsIgnoringASCIICase("apply"))
+            if (token.valueEqualsIgnoringASCIICase("apply")) {
+                range.consumeWhitespace();
+                const CSSParserToken& variableName = range.consumeIncludingWhitespace();
+                if (!CSSVariableParser::isValidVariableName(variableName)
+                    || !(range.atEnd() || range.peek().type() == SemicolonToken || range.peek().type() == RightBraceToken))
+                    return false;
                 hasReferences = true;
+            }
             break;
         }
         case DelimiterToken: {
diff --git a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
index bc966ffb..2535a38 100644
--- a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
@@ -362,20 +362,6 @@
         ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
         return parseGridShorthand(important);
 
-    case CSSPropertyBackground: {
-        // Position must come before color in this array because a plain old "0" is a legal color
-        // in quirks mode but it's usually the X coordinate of a position.
-        const CSSPropertyID properties[] = { CSSPropertyBackgroundImage, CSSPropertyBackgroundRepeat,
-                                   CSSPropertyBackgroundAttachment, CSSPropertyBackgroundPosition, CSSPropertyBackgroundOrigin,
-                                   CSSPropertyBackgroundClip, CSSPropertyBackgroundColor, CSSPropertyBackgroundSize };
-        return parseFillShorthand(propertyID, properties, WTF_ARRAY_LENGTH(properties), important);
-    }
-    case CSSPropertyWebkitMask: {
-        const CSSPropertyID properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat,
-            CSSPropertyWebkitMaskPosition, CSSPropertyWebkitMaskOrigin, CSSPropertyWebkitMaskClip, CSSPropertyWebkitMaskSize };
-        return parseFillShorthand(propertyID, properties, WTF_ARRAY_LENGTH(properties), important);
-    }
-
     // The remaining shorthands are handled in CSSPropertyParser.cpp
     default:
         return false;
diff --git a/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp b/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp
index 135aa41..936cb2d 100644
--- a/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp
@@ -15,7 +15,6 @@
 #include "core/css/parser/CSSParserTokenRange.h"
 #include "core/css/parser/CSSParserValues.h"
 #include "core/css/parser/CSSPropertyParser.h"
-#include "core/css/parser/CSSVariableParser.h"
 #include "core/css/resolver/StyleBuilder.h"
 #include "core/css/resolver/StyleResolverState.h"
 #include "core/style/StyleVariableData.h"
@@ -92,16 +91,9 @@
     Vector<CSSParserToken>& result)
 {
     ASSERT(range.peek().type() == AtKeywordToken && range.peek().valueEqualsIgnoringASCIICase("apply"));
-    CSSParserTokenRange originalRange = range;
-
     range.consumeIncludingWhitespace();
     const CSSParserToken& variableName = range.consumeIncludingWhitespace();
-    if (!CSSVariableParser::isValidVariableName(variableName)
-        || !(range.atEnd() || range.peek().type() == SemicolonToken || range.peek().type() == RightBraceToken)) {
-        range = originalRange;
-        result.append(range.consume());
-        return;
-    }
+    // TODO(timloh): Should we actually be consuming this?
     if (range.peek().type() == SemicolonToken)
         range.consume();
 
diff --git a/third_party/WebKit/Source/core/dom/ContainerNode.cpp b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
index 94afd0d..1dc3583e 100644
--- a/third_party/WebKit/Source/core/dom/ContainerNode.cpp
+++ b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
@@ -327,7 +327,7 @@
 
         treeScope().adoptIfNeeded(*newChild);
         insertBeforeCommon(nextChild, *newChild);
-        newChild->updateAncestorConnectedSubframeCountForInsertion();
+        ASSERT(newChild->connectedSubframeCount() == 0);
         ChildListMutationScope(*this).childAdded(*newChild);
     }
 
@@ -807,7 +807,7 @@
 
         treeScope().adoptIfNeeded(*newChild);
         appendChildCommon(*newChild);
-        newChild->updateAncestorConnectedSubframeCountForInsertion();
+        ASSERT(newChild->connectedSubframeCount() == 0);
         ChildListMutationScope(*this).childAdded(*newChild);
     }
 
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 81263fb2..a1cf59d 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -3440,7 +3440,6 @@
 void Document::setSelectedStylesheetSet(const String& aString)
 {
     styleEngine().setSelectedStylesheetSetName(aString);
-    styleEngine().resolverChanged(FullStyleUpdate);
 }
 
 void Document::evaluateMediaQueryListIfNeeded()
diff --git a/third_party/WebKit/Source/core/dom/DocumentStyleSheetCollection.cpp b/third_party/WebKit/Source/core/dom/DocumentStyleSheetCollection.cpp
index 8de17ce..028b48bc 100644
--- a/third_party/WebKit/Source/core/dom/DocumentStyleSheetCollection.cpp
+++ b/third_party/WebKit/Source/core/dom/DocumentStyleSheetCollection.cpp
@@ -62,8 +62,8 @@
 
         if (candidate.isEnabledAndLoading()) {
             // it is loading but we should still decide which style sheet set to use
-            if (candidate.hasPreferrableName(engine.preferredStylesheetSetName()))
-                engine.selectStylesheetSetName(candidate.title());
+            if (candidate.hasPreferrableName())
+                engine.setPreferredStylesheetSetNameIfNotSet(candidate.title());
             continue;
         }
 
@@ -71,8 +71,8 @@
         if (!sheet)
             continue;
 
-        if (candidate.hasPreferrableName(engine.preferredStylesheetSetName()))
-            engine.selectStylesheetSetName(candidate.title());
+        if (candidate.hasPreferrableName())
+            engine.setPreferredStylesheetSetNameIfNotSet(candidate.title());
         collector.appendSheetForList(sheet);
         if (candidate.canBeActivated(engine.preferredStylesheetSetName()))
             collector.appendActiveStyleSheet(toCSSStyleSheet(sheet));
diff --git a/third_party/WebKit/Source/core/dom/Microtask.cpp b/third_party/WebKit/Source/core/dom/Microtask.cpp
index 344c9e01..7c3ec6ed 100644
--- a/third_party/WebKit/Source/core/dom/Microtask.cpp
+++ b/third_party/WebKit/Source/core/dom/Microtask.cpp
@@ -40,9 +40,13 @@
 
 void Microtask::performCheckpoint(v8::Isolate* isolate)
 {
-    if (ScriptForbiddenScope::isScriptForbidden())
+    V8PerIsolateData* isolateData = V8PerIsolateData::from(isolate);
+    ASSERT(isolateData);
+    if (isolateData->recursionLevel() || isolateData->performingMicrotaskCheckpoint() || isolateData->destructionPending() || ScriptForbiddenScope::isScriptForbidden())
         return;
-    v8::MicrotasksScope::PerformCheckpoint(isolate);
+    isolateData->setPerformingMicrotaskCheckpoint(true);
+    isolate->RunMicrotasks();
+    isolateData->setPerformingMicrotaskCheckpoint(false);
 }
 
 static void microtaskFunctionCallback(void* data)
diff --git a/third_party/WebKit/Source/core/dom/Node.cpp b/third_party/WebKit/Source/core/dom/Node.cpp
index a9c7a70..604f1c7 100644
--- a/third_party/WebKit/Source/core/dom/Node.cpp
+++ b/third_party/WebKit/Source/core/dom/Node.cpp
@@ -2234,27 +2234,15 @@
     return hasRareData() ? rareData()->connectedSubframeCount() : 0;
 }
 
-void Node::incrementConnectedSubframeCount(unsigned amount)
+void Node::incrementConnectedSubframeCount()
 {
     ASSERT(isContainerNode());
-    ensureRareData().incrementConnectedSubframeCount(amount);
+    ensureRareData().incrementConnectedSubframeCount();
 }
 
-void Node::decrementConnectedSubframeCount(unsigned amount)
+void Node::decrementConnectedSubframeCount()
 {
-    rareData()->decrementConnectedSubframeCount(amount);
-}
-
-void Node::updateAncestorConnectedSubframeCountForInsertion() const
-{
-    unsigned count = connectedSubframeCount();
-
-    if (!count)
-        return;
-
-    ScriptForbiddenScope forbidScriptDuringRawIteration;
-    for (Node* node = parentOrShadowHostNode(); node; node = node->parentOrShadowHostNode())
-        node->incrementConnectedSubframeCount(count);
+    rareData()->decrementConnectedSubframeCount();
 }
 
 PassRefPtrWillBeRawPtr<StaticNodeList> Node::getDestinationInsertionPoints()
diff --git a/third_party/WebKit/Source/core/dom/Node.h b/third_party/WebKit/Source/core/dom/Node.h
index 8f3aead06f..b6749f7 100644
--- a/third_party/WebKit/Source/core/dom/Node.h
+++ b/third_party/WebKit/Source/core/dom/Node.h
@@ -665,9 +665,8 @@
     void notifyMutationObserversNodeWillDetach();
 
     unsigned connectedSubframeCount() const;
-    void incrementConnectedSubframeCount(unsigned amount = 1);
-    void decrementConnectedSubframeCount(unsigned amount = 1);
-    void updateAncestorConnectedSubframeCountForInsertion() const;
+    void incrementConnectedSubframeCount();
+    void decrementConnectedSubframeCount();
 
     PassRefPtrWillBeRawPtr<StaticNodeList> getDestinationInsertionPoints();
     HTMLSlotElement* assignedSlot() const;
diff --git a/third_party/WebKit/Source/core/dom/NodeRareData.cpp b/third_party/WebKit/Source/core/dom/NodeRareData.cpp
index 7ed6f61..8805a2b8 100644
--- a/third_party/WebKit/Source/core/dom/NodeRareData.cpp
+++ b/third_party/WebKit/Source/core/dom/NodeRareData.cpp
@@ -73,10 +73,10 @@
         this->~NodeRareData();
 }
 
-void NodeRareData::incrementConnectedSubframeCount(unsigned amount)
+void NodeRareData::incrementConnectedSubframeCount()
 {
-    RELEASE_ASSERT_WITH_SECURITY_IMPLICATION((m_connectedFrameCount + amount) <= FrameHost::maxNumberOfFrames);
-    m_connectedFrameCount += amount;
+    RELEASE_ASSERT_WITH_SECURITY_IMPLICATION((m_connectedFrameCount + 1) <= FrameHost::maxNumberOfFrames);
+    ++m_connectedFrameCount;
 }
 
 // Ensure the 10 bits reserved for the m_connectedFrameCount cannot overflow
diff --git a/third_party/WebKit/Source/core/dom/NodeRareData.h b/third_party/WebKit/Source/core/dom/NodeRareData.h
index 4621a0c..3cf6e50 100644
--- a/third_party/WebKit/Source/core/dom/NodeRareData.h
+++ b/third_party/WebKit/Source/core/dom/NodeRareData.h
@@ -82,12 +82,11 @@
     }
 
     unsigned connectedSubframeCount() const { return m_connectedFrameCount; }
-    void incrementConnectedSubframeCount(unsigned amount);
-    void decrementConnectedSubframeCount(unsigned amount)
+    void incrementConnectedSubframeCount();
+    void decrementConnectedSubframeCount()
     {
         ASSERT(m_connectedFrameCount);
-        ASSERT(amount <= m_connectedFrameCount);
-        m_connectedFrameCount -= amount;
+        --m_connectedFrameCount;
     }
 
     bool hasElementFlag(ElementFlags mask) const { return m_elementFlags & mask; }
diff --git a/third_party/WebKit/Source/core/dom/StyleChangeReason.cpp b/third_party/WebKit/Source/core/dom/StyleChangeReason.cpp
index e3eda0fe..659990e 100644
--- a/third_party/WebKit/Source/core/dom/StyleChangeReason.cpp
+++ b/third_party/WebKit/Source/core/dom/StyleChangeReason.cpp
@@ -35,6 +35,7 @@
 const char SVGContainerSizeChange[] = "SVGContainerSizeChange";
 const char SVGCursor[] = "SVGCursor";
 const char SVGFilterLayerUpdate[] = "SVGFilterLayerUpdate";
+const char Settings[] = "Settings";
 const char Shadow[] = "Shadow";
 const char SiblingSelector[] = "SiblingSelector";
 const char StyleInvalidator[] = "StyleInvalidator";
diff --git a/third_party/WebKit/Source/core/dom/StyleChangeReason.h b/third_party/WebKit/Source/core/dom/StyleChangeReason.h
index f9ca4ebd..62414193 100644
--- a/third_party/WebKit/Source/core/dom/StyleChangeReason.h
+++ b/third_party/WebKit/Source/core/dom/StyleChangeReason.h
@@ -39,6 +39,7 @@
 extern const char SVGContainerSizeChange[];
 extern const char SVGCursor[];
 extern const char SVGFilterLayerUpdate[];
+extern const char Settings[];
 extern const char Shadow[];
 extern const char SiblingSelector[];
 extern const char StyleInvalidator[];
diff --git a/third_party/WebKit/Source/core/dom/StyleEngine.cpp b/third_party/WebKit/Source/core/dom/StyleEngine.cpp
index 284f782..62bc9c8 100644
--- a/third_party/WebKit/Source/core/dom/StyleEngine.cpp
+++ b/third_party/WebKit/Source/core/dom/StyleEngine.cpp
@@ -723,6 +723,38 @@
         m_styleResolverStats->reset();
 }
 
+void StyleEngine::setPreferredStylesheetSetNameIfNotSet(const String& name)
+{
+    if (!m_preferredStylesheetSetName.isEmpty())
+        return;
+    m_preferredStylesheetSetName = name;
+    // TODO(rune@opera.com): Setting the selected set here is wrong if the set
+    // has been previously set by through Document.selectedStylesheetSet. Our
+    // current implementation ignores the effect of Document.selectedStylesheetSet
+    // and either only collects persistent style, or additionally preferred
+    // style when present. We are currently not marking the document scope dirty
+    // because preferred style is updated during active stylesheet update which
+    // would make this method re-entrant. Will need to change for async update.
+    m_selectedStylesheetSetName = name;
+}
+
+void StyleEngine::setSelectedStylesheetSetName(const String& name)
+{
+    m_selectedStylesheetSetName = name;
+    // TODO(rune@opera.com): Setting Document.selectedStylesheetSet currently
+    // has no other effect than the ability to read back the set value using
+    // the same api. If it did have an effect, we should have marked the
+    // document scope dirty and triggered an update of the active stylesheets
+    // from here.
+}
+
+void StyleEngine::setHttpDefaultStyle(const String& content)
+{
+    setPreferredStylesheetSetNameIfNotSet(content);
+    markDocumentDirty();
+    resolverChanged(FullStyleUpdate);
+}
+
 DEFINE_TRACE(StyleEngine)
 {
 #if ENABLE(OILPAN)
diff --git a/third_party/WebKit/Source/core/dom/StyleEngine.h b/third_party/WebKit/Source/core/dom/StyleEngine.h
index 96d41060..b44b364 100644
--- a/third_party/WebKit/Source/core/dom/StyleEngine.h
+++ b/third_party/WebKit/Source/core/dom/StyleEngine.h
@@ -100,14 +100,9 @@
 
     String preferredStylesheetSetName() const { return m_preferredStylesheetSetName; }
     String selectedStylesheetSetName() const { return m_selectedStylesheetSetName; }
-    void setPreferredStylesheetSetName(const String& name) { m_preferredStylesheetSetName = name; }
-    void setSelectedStylesheetSetName(const String& name) { m_selectedStylesheetSetName = name; }
-
-    void selectStylesheetSetName(const String& name)
-    {
-        setPreferredStylesheetSetName(name);
-        setSelectedStylesheetSetName(name);
-    }
+    void setPreferredStylesheetSetNameIfNotSet(const String&);
+    void setSelectedStylesheetSetName(const String&);
+    void setHttpDefaultStyle(const String&);
 
     void addPendingSheet();
     void removePendingSheet(Node* styleSheetCandidateNode);
diff --git a/third_party/WebKit/Source/core/dom/StyleSheetCandidate.cpp b/third_party/WebKit/Source/core/dom/StyleSheetCandidate.cpp
index 4db3173b..f4e5551a 100644
--- a/third_party/WebKit/Source/core/dom/StyleSheetCandidate.cpp
+++ b/third_party/WebKit/Source/core/dom/StyleSheetCandidate.cpp
@@ -82,10 +82,10 @@
     return isHTMLLink() && !toHTMLLinkElement(node()).isDisabled() && toHTMLLinkElement(node()).styleSheetIsLoading();
 }
 
-bool StyleSheetCandidate::hasPreferrableName(const String& currentPreferrableName) const
+bool StyleSheetCandidate::hasPreferrableName() const
 {
     ASSERT(isEnabledAndLoading() || sheet());
-    return !isEnabledViaScript() && !title().isEmpty() && !isAlternate() && currentPreferrableName.isEmpty();
+    return !isEnabledViaScript() && !title().isEmpty() && !isAlternate();
 }
 
 bool StyleSheetCandidate::canBeActivated(const String& currentPreferrableName) const
diff --git a/third_party/WebKit/Source/core/dom/StyleSheetCandidate.h b/third_party/WebKit/Source/core/dom/StyleSheetCandidate.h
index 366e30cb..7d38b71 100644
--- a/third_party/WebKit/Source/core/dom/StyleSheetCandidate.h
+++ b/third_party/WebKit/Source/core/dom/StyleSheetCandidate.h
@@ -57,7 +57,7 @@
     bool isAlternate() const;
     bool isEnabledViaScript() const;
     bool isEnabledAndLoading() const;
-    bool hasPreferrableName(const String& currentPreferrableName) const;
+    bool hasPreferrableName() const;
     bool canBeActivated(const String& currentPreferrableName) const;
     bool isCSSStyle() const;
 
diff --git a/third_party/WebKit/Source/core/editing/EditingTestBase.cpp b/third_party/WebKit/Source/core/editing/EditingTestBase.cpp
index 825df36..13afe508 100644
--- a/third_party/WebKit/Source/core/editing/EditingTestBase.cpp
+++ b/third_party/WebKit/Source/core/editing/EditingTestBase.cpp
@@ -35,20 +35,18 @@
 {
     RefPtrWillBeRawPtr<ShadowRoot> shadowRoot = scope.getElementById(AtomicString::fromUTF8(hostElementID))->createShadowRootInternal(ShadowRootType::V0, ASSERT_NO_EXCEPTION);
     shadowRoot->setInnerHTML(String::fromUTF8(shadowRootContent), ASSERT_NO_EXCEPTION);
-    scope.document().view()->updateAllLifecyclePhases();
     return shadowRoot.release();
 }
 
 void EditingTestBase::setBodyContent(const char* bodyContent)
 {
     document().body()->setInnerHTML(String::fromUTF8(bodyContent), ASSERT_NO_EXCEPTION);
-    updateLayoutAndStyleForPainting();
 }
 
 PassRefPtrWillBeRawPtr<ShadowRoot> EditingTestBase::setShadowContent(const char* shadowContent, const char* host)
 {
     RefPtrWillBeRawPtr<ShadowRoot> shadowRoot = createShadowRootForElementWithIDAndSetInnerHTML(document(), host, shadowContent);
-    updateLayoutAndStyleForPainting();
+    document().updateDistribution();
     return shadowRoot.release();
 }
 
diff --git a/third_party/WebKit/Source/core/editing/PlainTextRange.cpp b/third_party/WebKit/Source/core/editing/PlainTextRange.cpp
index 3fb2866..7cfb84d 100644
--- a/third_party/WebKit/Source/core/editing/PlainTextRange.cpp
+++ b/third_party/WebKit/Source/core/editing/PlainTextRange.cpp
@@ -82,11 +82,6 @@
     if (getRangeFor == ForSelection)
         behaviorFlags |= TextIteratorEmitsCharactersBetweenAllVisiblePositions;
     auto range = EphemeralRange::rangeOfContents(scope);
-
-    // TODO(dglazkov): The use of updateLayoutIgnorePendingStylesheets needs to be audited.
-    // see http://crbug.com/590369 for more details.
-    scope.document().updateLayoutIgnorePendingStylesheets();
-
     TextIterator it(range.startPosition(), range.endPosition(), behaviorFlags);
 
     // FIXME: the atEnd() check shouldn't be necessary, workaround for
diff --git a/third_party/WebKit/Source/core/editing/commands/TextInsertionBaseCommand.cpp b/third_party/WebKit/Source/core/editing/commands/TextInsertionBaseCommand.cpp
deleted file mode 100644
index 4cfbda5..0000000
--- a/third_party/WebKit/Source/core/editing/commands/TextInsertionBaseCommand.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "core/editing/commands/TextInsertionBaseCommand.h"
-
-#include "bindings/core/v8/ExceptionStatePlaceholder.h"
-#include "core/dom/Element.h"
-#include "core/dom/Node.h"
-#include "core/editing/FrameSelection.h"
-#include "core/events/BeforeTextInsertedEvent.h"
-#include "core/frame/LocalFrame.h"
-
-namespace blink {
-
-TextInsertionBaseCommand::TextInsertionBaseCommand(Document& document)
-    : CompositeEditCommand(document)
-{
-}
-
-void TextInsertionBaseCommand::applyTextInsertionCommand(LocalFrame* frame, PassRefPtrWillBeRawPtr<TextInsertionBaseCommand> command, const VisibleSelection& selectionForInsertion, const VisibleSelection& endingSelection)
-{
-    bool changeSelection = !equalSelectionsInDOMTree(selectionForInsertion, endingSelection);
-    if (changeSelection) {
-        command->setStartingSelection(selectionForInsertion);
-        command->setEndingSelection(selectionForInsertion);
-    }
-    command->apply();
-    if (changeSelection) {
-        command->setEndingSelection(endingSelection);
-        frame->selection().setSelection(endingSelection);
-    }
-}
-
-} // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/commands/TextInsertionBaseCommand.h b/third_party/WebKit/Source/core/editing/commands/TextInsertionBaseCommand.h
deleted file mode 100644
index 40c0f01c..0000000
--- a/third_party/WebKit/Source/core/editing/commands/TextInsertionBaseCommand.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef TextInsertionBaseCommand_h
-#define TextInsertionBaseCommand_h
-
-#include "core/editing/VisibleSelection.h"
-#include "core/editing/commands/CompositeEditCommand.h"
-#include "wtf/text/WTFString.h"
-
-namespace blink {
-
-class Document;
-
-class TextInsertionBaseCommand : public CompositeEditCommand {
-public:
-    ~TextInsertionBaseCommand() override { }
-
-protected:
-    explicit TextInsertionBaseCommand(Document&);
-    static void applyTextInsertionCommand(LocalFrame*, PassRefPtrWillBeRawPtr<TextInsertionBaseCommand>, const VisibleSelection& selectionForInsertion, const VisibleSelection& endingSelection);
-};
-
-} // namespace blink
-
-#endif
diff --git a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
index 65a3e20..38456b6d 100644
--- a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
@@ -48,41 +48,8 @@
 
 using namespace HTMLNames;
 
-class TypingCommandLineOperation {
-    STACK_ALLOCATED();
-public:
-    TypingCommandLineOperation(TypingCommand* typingCommand, bool selectInsertedText, const String& text)
-    : m_typingCommand(typingCommand)
-    , m_selectInsertedText(selectInsertedText)
-    , m_text(text)
-    { }
-
-    void operator()(size_t lineOffset, size_t lineLength, bool isLastLine, EditingState* editingState) const
-    {
-        if (isLastLine) {
-            if (!lineOffset || lineLength > 0) {
-                m_typingCommand->insertTextRunWithoutNewlines(m_text.substring(lineOffset, lineLength), m_selectInsertedText, editingState);
-                if (editingState->isAborted())
-                    return;
-            }
-        } else {
-            if (lineLength > 0) {
-                m_typingCommand->insertTextRunWithoutNewlines(m_text.substring(lineOffset, lineLength), false, editingState);
-                if (editingState->isAborted())
-                    return;
-            }
-            m_typingCommand->insertParagraphSeparator(editingState);
-        }
-    }
-
-private:
-    RawPtrWillBeMember<TypingCommand> m_typingCommand;
-    bool m_selectInsertedText;
-    const String& m_text;
-};
-
 TypingCommand::TypingCommand(Document& document, ETypingCommand commandType, const String &textToInsert, Options options, TextGranularity granularity, TextCompositionType compositionType)
-    : TextInsertionBaseCommand(document)
+    : CompositeEditCommand(document)
     , m_commandType(commandType)
     , m_textToInsert(textToInsert)
     , m_openForMoreTyping(true)
@@ -222,8 +189,17 @@
         return;
     }
 
-    RefPtrWillBeRawPtr<TypingCommand> cmd = TypingCommand::create(document, InsertText, newText, options, compositionType);
-    applyTextInsertionCommand(frame.get(), cmd, selectionForInsertion, currentSelection);
+    RefPtrWillBeRawPtr<TypingCommand> command = TypingCommand::create(document, InsertText, newText, options, compositionType);
+    bool changeSelection = !equalSelectionsInDOMTree(selectionForInsertion, currentSelection);
+    if (changeSelection) {
+        command->setStartingSelection(selectionForInsertion);
+        command->setEndingSelection(selectionForInsertion);
+    }
+    command->apply();
+    if (changeSelection) {
+        command->setEndingSelection(currentSelection);
+        frame->selection().setSelection(currentSelection);
+    }
 }
 
 bool TypingCommand::insertLineBreak(Document& document)
@@ -365,37 +341,42 @@
     frame->editor().appliedEditing(this);
 }
 
-// LineOperation should define member function "opeartor (size_t lineOffset, size_t lineLength, bool isLastLine)".
-// lienLength doesn't include the newline character. So the value of lineLength could be 0.
-template <class LineOperation>
-static void forEachLineInString(const String& string, const LineOperation& operation, EditingState* editingState)
-{
-    unsigned offset = 0;
-    size_t newline;
-    while ((newline = string.find('\n', offset)) != kNotFound) {
-        operation(offset, newline - offset, false, editingState);
-        if (editingState->isAborted())
-            return;
-        offset = newline + 1;
-    }
-    if (!offset) {
-        operation(0, string.length(), true, editingState);
-    } else {
-        unsigned length = string.length();
-        if (length != offset)
-            operation(offset, length - offset, true, editingState);
-    }
-}
-
 void TypingCommand::insertText(const String &text, bool selectInsertedText, EditingState* editingState)
 {
+    if (text.isEmpty()) {
+        insertTextRunWithoutNewlines(text, selectInsertedText, editingState);
+        return;
+    }
     // FIXME: Need to implement selectInsertedText for cases where more than one insert is involved.
     // This requires support from insertTextRunWithoutNewlines and insertParagraphSeparator for extending
     // an existing selection; at the moment they can either put the caret after what's inserted or
     // select what's inserted, but there's no way to "extend selection" to include both an old selection
     // that ends just before where we want to insert text and the newly inserted text.
-    TypingCommandLineOperation operation(this, selectInsertedText, text);
-    forEachLineInString(text, operation, editingState);
+    unsigned offset = 0;
+    size_t newline;
+    while ((newline = text.find('\n', offset)) != kNotFound) {
+        if (newline > offset) {
+            const bool notSelectInsertedText = false;
+            insertTextRunWithoutNewlines(text.substring(offset, newline - offset), notSelectInsertedText, editingState);
+            if (editingState->isAborted())
+                return;
+        }
+
+        insertParagraphSeparator(editingState);
+        if (editingState->isAborted())
+            return;
+
+        offset = newline + 1;
+    }
+
+    if (!offset) {
+        insertTextRunWithoutNewlines(text, selectInsertedText, editingState);
+        return;
+    }
+
+    if (text.length() > offset)
+        insertTextRunWithoutNewlines(text.substring(offset, text.length() - offset), selectInsertedText, editingState);
+
 }
 
 void TypingCommand::insertTextRunWithoutNewlines(const String &text, bool selectInsertedText, EditingState* editingState)
diff --git a/third_party/WebKit/Source/core/editing/commands/TypingCommand.h b/third_party/WebKit/Source/core/editing/commands/TypingCommand.h
index a2fc7f7..56120ab 100644
--- a/third_party/WebKit/Source/core/editing/commands/TypingCommand.h
+++ b/third_party/WebKit/Source/core/editing/commands/TypingCommand.h
@@ -26,11 +26,11 @@
 #ifndef TypingCommand_h
 #define TypingCommand_h
 
-#include "core/editing/commands/TextInsertionBaseCommand.h"
+#include "core/editing/commands/CompositeEditCommand.h"
 
 namespace blink {
 
-class TypingCommand final : public TextInsertionBaseCommand {
+class TypingCommand final : public CompositeEditCommand {
 public:
     enum ETypingCommand {
         DeleteSelection,
diff --git a/third_party/WebKit/Source/core/editing/iterators/SearchBuffer.cpp b/third_party/WebKit/Source/core/editing/iterators/SearchBuffer.cpp
index e22ad5a..f9d370e 100644
--- a/third_party/WebKit/Source/core/editing/iterators/SearchBuffer.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/SearchBuffer.cpp
@@ -434,9 +434,6 @@
         TextIteratorBehaviorFlags behavior = iteratorFlagsForFindPlainText;
         if (options & FindAPICall)
             behavior |= TextIteratorForWindowFind;
-        // TODO(dglazkov): The use of updateLayoutIgnorePendingStylesheets needs to be audited.
-        // see http://crbug.com/590369 for more details.
-        inputRange.startPosition().document()->updateLayoutIgnorePendingStylesheets();
         CharacterIteratorAlgorithm<Strategy> findIterator(inputRange, behavior);
         matchLength = findPlainTextInternal(findIterator, target, options, matchStart);
         if (!matchLength)
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
index a7f1da5..3fbca07 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
@@ -146,11 +146,9 @@
 {
     ASSERT(start.isNotNull());
     ASSERT(end.isNotNull());
-
-    // TODO(dglazkov): TextIterator should not be created for documents that don't have a frame,
-    // but it currently still happens in some cases. See http://crbug.com/591877 for details.
-    ASSERT(!start.document()->view() || !start.document()->view()->needsLayout());
-    ASSERT(!start.document()->needsLayoutTreeUpdate());
+    // Updates layout here since, |Position.compareTo()| and |initialize()|
+    // assume layout tree is up-to-date.
+    start.document()->updateLayoutIgnorePendingStylesheets();
     if (start.compareTo(end) > 0) {
         initialize(end.computeContainerNode(), end.computeOffsetInContainerNode(), start.computeContainerNode(), start.computeOffsetInContainerNode());
         return;
@@ -1092,10 +1090,6 @@
 template<typename Strategy>
 int TextIteratorAlgorithm<Strategy>::rangeLength(const PositionTemplate<Strategy>& start, const PositionTemplate<Strategy>& end, bool forSelectionPreservation)
 {
-    // TODO(dglazkov): The use of updateLayoutIgnorePendingStylesheets needs to be audited.
-    // see http://crbug.com/590369 for more details.
-    start.document()->updateLayoutIgnorePendingStylesheets();
-
     int length = 0;
     TextIteratorBehaviorFlags behaviorFlags = TextIteratorEmitsObjectReplacementCharacter;
     if (forSelectionPreservation)
@@ -1150,10 +1144,6 @@
     if (range.isNull())
         return emptyString();
 
-    // TODO(dglazkov): The use of updateLayoutIgnorePendingStylesheets needs to be audited.
-    // see http://crbug.com/590369 for more details.
-    range.startPosition().document()->updateLayoutIgnorePendingStylesheets();
-
     TextIteratorAlgorithm<Strategy> it(range.startPosition(), range.endPosition(), behavior);
 
     if (it.atEnd())
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp
index 2cc2a91a..b7211a6 100644
--- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp
@@ -99,11 +99,6 @@
 
 void DocumentMarkerController::addMarker(const Position& start, const Position& end, DocumentMarker::MarkerType type, const String& description, uint32_t hash)
 {
-
-    // TODO(dglazkov): The use of updateLayoutIgnorePendingStylesheets needs to be audited.
-    // see http://crbug.com/590369 for more details.
-    start.document()->updateLayoutIgnorePendingStylesheets();
-
     // Use a TextIterator to visit the potentially multiple nodes the range covers.
     for (TextIterator markedText(start, end); !markedText.atEnd(); markedText.advance()) {
         addMarker(markedText.currentContainer(), DocumentMarker(type, markedText.startOffsetInCurrentContainer(), markedText.endOffsetInCurrentContainer(), description, hash));
@@ -112,10 +107,6 @@
 
 void DocumentMarkerController::addTextMatchMarker(const Range* range, bool activeMatch)
 {
-    // TODO(dglazkov): The use of updateLayoutIgnorePendingStylesheets needs to be audited.
-    // see http://crbug.com/590369 for more details.
-    range->startPosition().document()->updateLayoutIgnorePendingStylesheets();
-
     // Use a TextIterator to visit the potentially multiple nodes the range covers.
     for (TextIterator markedText(range->startPosition(), range->endPosition()); !markedText.atEnd(); markedText.advance())
         addMarker(markedText.currentContainer(), DocumentMarker(markedText.startOffsetInCurrentContainer(), markedText.endOffsetInCurrentContainer(), activeMatch));
@@ -124,10 +115,6 @@
 
 void DocumentMarkerController::addCompositionMarker(const Position& start, const Position& end, Color underlineColor, bool thick, Color backgroundColor)
 {
-    // TODO(dglazkov): The use of updateLayoutIgnorePendingStylesheets needs to be audited.
-    // see http://crbug.com/590369 for more details.
-    start.document()->updateLayoutIgnorePendingStylesheets();
-
     for (TextIterator markedText(start, end); !markedText.atEnd(); markedText.advance())
         addMarker(markedText.currentContainer(), DocumentMarker(markedText.startOffsetInCurrentContainer(), markedText.endOffsetInCurrentContainer(), underlineColor, thick, backgroundColor));
 }
@@ -152,10 +139,6 @@
 
 void DocumentMarkerController::removeMarkers(const EphemeralRange& range, DocumentMarker::MarkerTypes markerTypes, RemovePartiallyOverlappingMarkerOrNot shouldRemovePartiallyOverlappingMarker)
 {
-    // TODO(dglazkov): The use of updateLayoutIgnorePendingStylesheets needs to be audited.
-    // see http://crbug.com/590369 for more details.
-    range.startPosition().document()->updateLayoutIgnorePendingStylesheets();
-
     TextIterator markedText(range.startPosition(), range.endPosition());
     DocumentMarkerController::removeMarkers(markedText, markerTypes, shouldRemovePartiallyOverlappingMarker);
 }
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.cpp b/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.cpp
index 1ccce6f1d..ea5dd9c8 100644
--- a/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.cpp
+++ b/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.cpp
@@ -236,10 +236,6 @@
 
 String TextCheckingHelper::findFirstMisspelling(int& firstMisspellingOffset, bool markAll)
 {
-    // TODO(dglazkov): The use of updateLayoutIgnorePendingStylesheets needs to be audited.
-    // see http://crbug.com/590369 for more details.
-    m_start.document()->updateLayoutIgnorePendingStylesheets();
-
     WordAwareIterator it(m_start, m_end);
     firstMisspellingOffset = 0;
 
diff --git a/third_party/WebKit/Source/core/html/HTMLInputElement.cpp b/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
index 93a646b..b7294bf0 100644
--- a/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
@@ -722,6 +722,7 @@
             setChecked(!value.isNull());
             m_reflectsCheckedAttribute = true;
         }
+        pseudoStateChanged(CSSSelector::PseudoDefault);
     } else if (name == maxlengthAttr) {
         parseMaxLengthAttribute(value);
     } else if (name == minlengthAttr) {
diff --git a/third_party/WebKit/Source/core/html/HTMLOptionElement.cpp b/third_party/WebKit/Source/core/html/HTMLOptionElement.cpp
index 3a1b25d0..f159f098 100644
--- a/third_party/WebKit/Source/core/html/HTMLOptionElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLOptionElement.cpp
@@ -216,6 +216,7 @@
     } else if (name == selectedAttr) {
         if (oldValue.isNull() != value.isNull() && !m_isDirty)
             setSelected(!value.isNull());
+        pseudoStateChanged(CSSSelector::PseudoDefault);
     } else if (name == labelAttr) {
         updateLabel();
     } else {
diff --git a/third_party/WebKit/Source/core/html/HTMLTableSectionElement.cpp b/third_party/WebKit/Source/core/html/HTMLTableSectionElement.cpp
index 4c602ca..89198c3 100644
--- a/third_party/WebKit/Source/core/html/HTMLTableSectionElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLTableSectionElement.cpp
@@ -74,8 +74,11 @@
 {
     RefPtrWillBeRawPtr<HTMLCollection> children = rows();
     int numRows = children ? (int)children->length() : 0;
-    if (index == -1)
+    if (index == -1) {
+        if (!numRows)
+            return;
         index = numRows - 1;
+    }
     if (index >= 0 && index < numRows) {
         RefPtrWillBeRawPtr<Element> row = children->item(index);
         HTMLElement::removeChild(row.get(), exceptionState);
diff --git a/third_party/WebKit/Source/core/html/HTMLTextFormControlElementTest.cpp b/third_party/WebKit/Source/core/html/HTMLTextFormControlElementTest.cpp
index f2ad8b4..22cce6c 100644
--- a/third_party/WebKit/Source/core/html/HTMLTextFormControlElementTest.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLTextFormControlElementTest.cpp
@@ -168,7 +168,13 @@
     }
 }
 
-TEST_F(HTMLTextFormControlElementTest, WordAndSentenceBoundary)
+// Flakily failing under MAC ASAN. See https://crbug.com/592880.
+#if OS(MACOSX) && defined(ADDRESS_SANITIZER)
+#define MAYBE_WordAndSentenceBoundary DISABLED_WordAndSentenceBoundary
+#else
+#define MAYBE_WordAndSentenceBoundary WordAndSentenceBoundary
+#endif
+TEST_F(HTMLTextFormControlElementTest, MAYBE_WordAndSentenceBoundary)
 {
     HTMLElement* innerText = textControl().innerEditorElement();
     {
diff --git a/third_party/WebKit/Source/core/html/HTMLVideoElementTest.cpp b/third_party/WebKit/Source/core/html/HTMLVideoElementTest.cpp
index 47686fe..4a605ce 100644
--- a/third_party/WebKit/Source/core/html/HTMLVideoElementTest.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLVideoElementTest.cpp
@@ -46,8 +46,8 @@
     double mediaTimeForTimeValue(double timeValue) const override { return timeValue; };
     unsigned decodedFrameCount() const override { return 0; };
     unsigned droppedFrameCount() const override { return 0; };
-    unsigned audioDecodedByteCount() const override { return 0; };
-    unsigned videoDecodedByteCount() const override { return 0; };
+    size_t audioDecodedByteCount() const override { return 0; };
+    size_t videoDecodedByteCount() const override { return 0; };
     void paint(WebCanvas*, const WebRect&, unsigned char alpha, SkXfermode::Mode) override { };
 };
 
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h
index 14935387..3900487 100644
--- a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h
@@ -28,7 +28,6 @@
 
 #include "core/CoreExport.h"
 #include "core/html/HTMLCanvasElement.h"
-#include "platform/heap/Handle.h"
 #include "wtf/HashSet.h"
 #include "wtf/Noncopyable.h"
 #include "wtf/text/StringHash.h"
@@ -126,7 +125,6 @@
 protected:
     CanvasRenderingContext(HTMLCanvasElement*);
     DECLARE_VIRTUAL_TRACE();
-
     virtual void stop() = 0;
 
 private:
diff --git a/third_party/WebKit/Source/core/html/canvas/OffscreenCanvas.cpp b/third_party/WebKit/Source/core/html/canvas/OffscreenCanvas.cpp
deleted file mode 100644
index c227f47..0000000
--- a/third_party/WebKit/Source/core/html/canvas/OffscreenCanvas.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "core/html/canvas/OffscreenCanvas.h"
-
-#include "wtf/MathExtras.h"
-
-namespace blink {
-
-OffscreenCanvas* OffscreenCanvas::create(unsigned width, unsigned height)
-{
-    return new OffscreenCanvas(IntSize(clampTo<int>(width), clampTo<int>(height)));
-}
-
-void OffscreenCanvas::setWidth(unsigned width)
-{
-    m_size.setWidth(clampTo<int>(width));
-}
-
-void OffscreenCanvas::setHeight(unsigned height)
-{
-    m_size.setHeight(clampTo<int>(height));
-}
-
-OffscreenCanvas::OffscreenCanvas(const IntSize& size)
-    : m_size(size)
-{
-}
-
-DEFINE_TRACE(OffscreenCanvas)
-{
-}
-
-} // namespace blink
diff --git a/third_party/WebKit/Source/core/html/canvas/OffscreenCanvas.h b/third_party/WebKit/Source/core/html/canvas/OffscreenCanvas.h
deleted file mode 100644
index a9a14b2..0000000
--- a/third_party/WebKit/Source/core/html/canvas/OffscreenCanvas.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef OffscreenCanvas_h
-#define OffscreenCanvas_h
-
-#include "bindings/core/v8/ScriptPromise.h"
-#include "bindings/core/v8/ScriptState.h"
-#include "bindings/core/v8/ScriptWrappable.h"
-#include "core/CoreExport.h"
-#include "platform/geometry/IntSize.h"
-#include "platform/heap/Handle.h"
-
-namespace blink {
-
-class CORE_EXPORT OffscreenCanvas final : public GarbageCollectedFinalized<OffscreenCanvas>, public ScriptWrappable {
-    DEFINE_WRAPPERTYPEINFO();
-public:
-    static OffscreenCanvas* create(unsigned width, unsigned height);
-
-    IntSize size() const { return m_size; }
-    unsigned width() const { return m_size.width(); }
-    unsigned height() const { return m_size.height(); }
-
-    void setWidth(unsigned);
-    void setHeight(unsigned);
-
-    DECLARE_VIRTUAL_TRACE();
-
-private:
-    OffscreenCanvas(const IntSize&);
-
-    IntSize m_size;
-};
-
-} // namespace blink
-
-#endif // OffscreenCanvas_h
diff --git a/third_party/WebKit/Source/core/input/PointerEventManager.cpp b/third_party/WebKit/Source/core/input/PointerEventManager.cpp
index 1179aa8..3ae14e61 100644
--- a/third_party/WebKit/Source/core/input/PointerEventManager.cpp
+++ b/third_party/WebKit/Source/core/input/PointerEventManager.cpp
@@ -100,11 +100,13 @@
 
 // Sends node transition events (pointer|mouse)(out|leave|over|enter) to the corresponding targets
 void PointerEventManager::sendNodeTransitionEvents(
-    PassRefPtrWillBeRawPtr<Node> exitedNode,
-    PassRefPtrWillBeRawPtr<Node> enteredNode,
+    PassRefPtrWillBeRawPtr<Node> prpExitedNode,
+    PassRefPtrWillBeRawPtr<Node> prpEnteredNode,
     const PlatformMouseEvent& mouseEvent,
     PassRefPtrWillBeRawPtr<AbstractView> view)
 {
+    RefPtrWillBeRawPtr<Node> exitedNode = prpExitedNode;
+    RefPtrWillBeRawPtr<Node> enteredNode = prpEnteredNode;
     RefPtrWillBeRawPtr<PointerEvent> pointerEvent =
         m_pointerEventFactory.create(EventTypeNames::mouseout, mouseEvent,
         nullptr, view);
@@ -272,11 +274,10 @@
     }
 }
 
-void PointerEventManager::sendTouchCancelPointerEvent(PassRefPtrWillBeRawPtr<EventTarget> target,
-    const PlatformTouchPoint& point)
+void PointerEventManager::sendTouchCancelPointerEvent(PassRefPtrWillBeRawPtr<EventTarget> prpTarget, const PlatformTouchPoint& point)
 {
-    RefPtrWillBeRawPtr<PointerEvent> pointerEvent =
-        m_pointerEventFactory.createPointerCancel(point);
+    RefPtrWillBeRawPtr<EventTarget> target = prpTarget;
+    RefPtrWillBeRawPtr<PointerEvent> pointerEvent = m_pointerEventFactory.createPointerCancel(point);
 
     processPendingPointerCapture(pointerEvent, target);
 
@@ -322,11 +323,12 @@
 }
 
 WebInputEventResult PointerEventManager::sendMousePointerEvent(
-    PassRefPtrWillBeRawPtr<Node> target, const AtomicString& mouseEventType,
+    PassRefPtrWillBeRawPtr<Node> prpTarget, const AtomicString& mouseEventType,
     int clickCount, const PlatformMouseEvent& mouseEvent,
     PassRefPtrWillBeRawPtr<Node> relatedTarget,
     PassRefPtrWillBeRawPtr<AbstractView> view)
 {
+    RefPtrWillBeRawPtr<Node> target = prpTarget;
     RefPtrWillBeRawPtr<PointerEvent> pointerEvent =
         m_pointerEventFactory.create(mouseEventType, mouseEvent,
         relatedTarget, view);
@@ -449,8 +451,9 @@
 }
 
 void PointerEventManager::removePointer(
-    const PassRefPtrWillBeRawPtr<PointerEvent> pointerEvent)
+    const PassRefPtrWillBeRawPtr<PointerEvent> prpPointerEvent)
 {
+    RefPtrWillBeRawPtr<PointerEvent> pointerEvent = prpPointerEvent;
     if (m_pointerEventFactory.remove(pointerEvent)) {
         int pointerId = pointerEvent->pointerId();
         m_pendingPointerCaptureTarget.remove(pointerId);
diff --git a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp
index f7c413e7..cc61a139 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp
@@ -690,93 +690,6 @@
     return minimumValueForLength(padding, w);
 }
 
-static inline LayoutUnit resolveWidthForRatio(LayoutUnit height, const FloatSize& intrinsicRatio)
-{
-    return LayoutUnit(height * intrinsicRatio.width() / intrinsicRatio.height());
-}
-
-static inline LayoutUnit resolveHeightForRatio(LayoutUnit width, const FloatSize& intrinsicRatio)
-{
-    return LayoutUnit(width * intrinsicRatio.height() / intrinsicRatio.width());
-}
-
-static inline LayoutSize resolveAgainstIntrinsicWidthOrHeightAndRatio(const LayoutSize& size, const FloatSize& intrinsicRatio, LayoutUnit useWidth, LayoutUnit useHeight)
-{
-    if (intrinsicRatio.isEmpty()) {
-        if (useWidth)
-            return LayoutSize(useWidth, size.height());
-        return LayoutSize(size.width(), useHeight);
-    }
-
-    if (useWidth)
-        return LayoutSize(useWidth, resolveHeightForRatio(useWidth, intrinsicRatio));
-    return LayoutSize(resolveWidthForRatio(useHeight, intrinsicRatio), useHeight);
-}
-
-static inline LayoutSize resolveAgainstIntrinsicRatio(const LayoutSize& size, const FloatSize& intrinsicRatio)
-{
-    // Two possible solutions: (size.width(), solutionHeight) or (solutionWidth, size.height())
-    // "... must be assumed to be the largest dimensions..." = easiest answer: the rect with the largest surface area.
-
-    LayoutUnit solutionWidth = resolveWidthForRatio(size.height(), intrinsicRatio);
-    LayoutUnit solutionHeight = resolveHeightForRatio(size.width(), intrinsicRatio);
-    if (solutionWidth <= size.width()) {
-        if (solutionHeight <= size.height()) {
-            // If both solutions fit, choose the one covering the larger area.
-            LayoutUnit areaOne = solutionWidth * size.height();
-            LayoutUnit areaTwo = size.width() * solutionHeight;
-            if (areaOne < areaTwo)
-                return LayoutSize(size.width(), solutionHeight);
-            return LayoutSize(solutionWidth, size.height());
-        }
-
-        // Only the first solution fits.
-        return LayoutSize(solutionWidth, size.height());
-    }
-
-    // Only the second solution fits, assert that.
-    ASSERT(solutionHeight <= size.height());
-    return LayoutSize(size.width(), solutionHeight);
-}
-
-LayoutSize LayoutBoxModelObject::calculateImageIntrinsicDimensions(StyleImage* image, const LayoutSize& positioningAreaSize, ScaleByEffectiveZoomOrNot shouldScaleOrNot) const
-{
-    // A generated image without a fixed size, will always return the container size as intrinsic size.
-    if (image->isGeneratedImage() && image->usesImageContainerSize())
-        return positioningAreaSize;
-
-    FloatSize intrinsicSize;
-    FloatSize intrinsicRatio;
-    image->computeIntrinsicDimensions(this, intrinsicSize, intrinsicRatio);
-
-    LayoutSize resolvedSize(intrinsicSize);
-    LayoutSize minimumSize(resolvedSize.width() > LayoutUnit() ? LayoutUnit(1) : LayoutUnit(),
-        resolvedSize.height() > LayoutUnit() ? LayoutUnit(1) : LayoutUnit());
-    if (shouldScaleOrNot == ScaleByEffectiveZoom)
-        resolvedSize.scale(style()->effectiveZoom());
-    resolvedSize.clampToMinimumSize(minimumSize);
-
-    if (!resolvedSize.isEmpty())
-        return resolvedSize;
-
-    // If the image has one of either an intrinsic width or an intrinsic height:
-    // * and an intrinsic aspect ratio, then the missing dimension is calculated from the given dimension and the ratio.
-    // * and no intrinsic aspect ratio, then the missing dimension is assumed to be the size of the rectangle that
-    //   establishes the coordinate system for the 'background-position' property.
-    if (resolvedSize.width() > LayoutUnit() || resolvedSize.height() > LayoutUnit())
-        return resolveAgainstIntrinsicWidthOrHeightAndRatio(positioningAreaSize, intrinsicRatio, resolvedSize.width(), resolvedSize.height());
-
-    // If the image has no intrinsic dimensions and has an intrinsic ratio the dimensions must be assumed to be the
-    // largest dimensions at that ratio such that neither dimension exceeds the dimensions of the rectangle that
-    // establishes the coordinate system for the 'background-position' property.
-    if (!intrinsicRatio.isEmpty())
-        return resolveAgainstIntrinsicRatio(positioningAreaSize, intrinsicRatio);
-
-    // If the image has no intrinsic ratio either, then the dimensions must be assumed to be the rectangle that
-    // establishes the coordinate system for the 'background-position' property.
-    return positioningAreaSize;
-}
-
 bool LayoutBoxModelObject::boxShadowShouldBeAppliedToBackground(BackgroundBleedAvoidance bleedAvoidance, const InlineFlowBox* inlineFlowBox) const
 {
     if (bleedAvoidance != BackgroundBleedNone)
diff --git a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h
index 05730ac..1301c75 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h
@@ -353,9 +353,6 @@
     }
     virtual void moveChildrenTo(LayoutBoxModelObject* toBoxModelObject, LayoutObject* startChild, LayoutObject* endChild, LayoutObject* beforeChild, bool fullRemoveInsert = false);
 
-    enum ScaleByEffectiveZoomOrNot { ScaleByEffectiveZoom, DoNotScaleByEffectiveZoom };
-    LayoutSize calculateImageIntrinsicDimensions(StyleImage*, const LayoutSize& scaledPositioningAreaSize, ScaleByEffectiveZoomOrNot) const;
-
 private:
     void createLayer(PaintLayerType);
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutImageResourceStyleImage.h b/third_party/WebKit/Source/core/layout/LayoutImageResourceStyleImage.h
index 284bb93..80bcdbe 100644
--- a/third_party/WebKit/Source/core/layout/LayoutImageResourceStyleImage.h
+++ b/third_party/WebKit/Source/core/layout/LayoutImageResourceStyleImage.h
@@ -51,7 +51,11 @@
 
     bool imageHasRelativeSize() const override { return m_styleImage->imageHasRelativeSize(); }
 
-    LayoutSize imageSize(float multiplier) const override { return m_styleImage->imageSize(m_layoutObject, multiplier); }
+    LayoutSize imageSize(float multiplier) const override
+    {
+        // TODO(davve): Find out the default object size, if any, in this context.
+        return m_styleImage->imageSize(m_layoutObject, multiplier, LayoutSize());
+    }
 
     WrappedImagePtr imagePtr() const override { return m_styleImage->data(); }
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutListMarker.cpp b/third_party/WebKit/Source/core/layout/LayoutListMarker.cpp
index de63ab1..0cc2c5c6 100644
--- a/third_party/WebKit/Source/core/layout/LayoutListMarker.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutListMarker.cpp
@@ -72,8 +72,7 @@
     // become particularly useful until we support the CSS3 marker pseudoclass to allow control over
     // the width and height of the marker box.
     LayoutUnit bulletWidth = style()->fontMetrics().ascent() / LayoutUnit(2);
-    LayoutSize defaultBulletSize(bulletWidth, bulletWidth);
-    return calculateImageIntrinsicDimensions(m_image.get(), defaultBulletSize, DoNotScaleByEffectiveZoom);
+    return m_image->imageSize(this, style()->effectiveZoom(), LayoutSize(bulletWidth, bulletWidth));
 }
 
 void LayoutListMarker::styleWillChange(StyleDifference diff, const ComputedStyle& newStyle)
diff --git a/third_party/WebKit/Source/core/layout/shapes/ShapeOutsideInfo.cpp b/third_party/WebKit/Source/core/layout/shapes/ShapeOutsideInfo.cpp
index 6abfec0a..9aafdd4 100644
--- a/third_party/WebKit/Source/core/layout/shapes/ShapeOutsideInfo.cpp
+++ b/third_party/WebKit/Source/core/layout/shapes/ShapeOutsideInfo.cpp
@@ -121,7 +121,7 @@
 
 PassOwnPtr<Shape> ShapeOutsideInfo::createShapeForImage(StyleImage* styleImage, float shapeImageThreshold, WritingMode writingMode, float margin) const
 {
-    const LayoutSize& imageSize = m_layoutBox.calculateImageIntrinsicDimensions(styleImage, m_referenceBoxLogicalSize, LayoutImage::ScaleByEffectiveZoom);
+    const LayoutSize& imageSize = styleImage->imageSize(&m_layoutBox, m_layoutBox.style()->effectiveZoom(), m_referenceBoxLogicalSize);
 
     const LayoutRect& marginRect = getShapeImageMarginRect(m_layoutBox, m_referenceBoxLogicalSize);
     const LayoutRect& imageRect = (m_layoutBox.isLayoutImage())
diff --git a/third_party/WebKit/Source/core/loader/HttpEquiv.cpp b/third_party/WebKit/Source/core/loader/HttpEquiv.cpp
index e6537eea..2f5f664 100644
--- a/third_party/WebKit/Source/core/loader/HttpEquiv.cpp
+++ b/third_party/WebKit/Source/core/loader/HttpEquiv.cpp
@@ -69,15 +69,7 @@
 
 void HttpEquiv::processHttpEquivDefaultStyle(Document& document, const AtomicString& content)
 {
-    // The preferred style set has been overridden as per section
-    // 14.3.2 of the HTML4.0 specification. We need to update the
-    // sheet used variable and then update our style selector.
-    // For more info, see the test at:
-    // http://www.hixie.ch/tests/evil/css/import/main/preferred.html
-    // -dwh
-    document.styleEngine().setSelectedStylesheetSetName(content);
-    document.styleEngine().setPreferredStylesheetSetName(content);
-    document.styleEngine().resolverChanged(FullStyleUpdate);
+    document.styleEngine().setHttpDefaultStyle(content);
 }
 
 void HttpEquiv::processHttpEquivRefresh(Document& document, const AtomicString& content)
diff --git a/third_party/WebKit/Source/core/page/Page.cpp b/third_party/WebKit/Source/core/page/Page.cpp
index 474628f9..20c93d47 100644
--- a/third_party/WebKit/Source/core/page/Page.cpp
+++ b/third_party/WebKit/Source/core/page/Page.cpp
@@ -21,6 +21,7 @@
 
 #include "core/css/resolver/ViewportStyleResolver.h"
 #include "core/dom/ClientRectList.h"
+#include "core/dom/StyleChangeReason.h"
 #include "core/dom/VisitedLinkState.h"
 #include "core/editing/DragCaretController.h"
 #include "core/editing/commands/UndoStack.h"
@@ -241,7 +242,7 @@
 {
     for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
         if (frame->isLocalFrame())
-            toLocalFrame(frame)->document()->styleEngine().resolverChanged(FullStyleUpdate);
+            toLocalFrame(frame)->document()->setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::Settings));
     }
 }
 
@@ -315,7 +316,6 @@
         return;
 
     m_deviceScaleFactor = scaleFactor;
-    setNeedsRecalcStyleInAllFrames();
 
     if (mainFrame() && mainFrame()->isLocalFrame())
         deprecatedLocalMainFrame()->deviceScaleFactorChanged();
@@ -443,7 +443,6 @@
             if (frame->isLocalFrame())
                 toLocalFrame(frame)->document()->styleEngine().updateGenericFontFamilySettings();
         }
-        setNeedsRecalcStyleInAllFrames();
         break;
     case SettingsDelegate::AcceleratedCompositingChange:
         updateAcceleratedCompositingSettings();
diff --git a/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp b/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
index 5de58bf..06a8269 100644
--- a/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
+++ b/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
@@ -53,8 +53,7 @@
     StyleImage* image = fillLayer.image();
     EFillSizeType type = fillLayer.size().type;
 
-    LayoutSize imageIntrinsicSize = obj.calculateImageIntrinsicDimensions(image, positioningAreaSize, LayoutBoxModelObject::ScaleByEffectiveZoom);
-    imageIntrinsicSize.scale(1 / image->imageScaleFactor(), 1 / image->imageScaleFactor());
+    LayoutSize imageIntrinsicSize = image->imageSize(&obj, obj.style()->effectiveZoom(), positioningAreaSize);
     switch (type) {
     case SizeLength: {
         LayoutSize tileSize(positioningAreaSize);
diff --git a/third_party/WebKit/Source/core/paint/BoxPainter.cpp b/third_party/WebKit/Source/core/paint/BoxPainter.cpp
index 94500cd3..d1d135e 100644
--- a/third_party/WebKit/Source/core/paint/BoxPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/BoxPainter.cpp
@@ -136,9 +136,11 @@
 
 bool BoxPainter::isFillLayerOpaque(const FillLayer& layer, const LayoutObject& imageClient)
 {
+    // The default object size passed down to imageSize is empty with the implication that images
+    // with no intrinsic size are treated as empty.
     return layer.hasOpaqueImage(&imageClient)
         && layer.image()->canRender()
-        && !layer.image()->imageSize(&imageClient, imageClient.style()->effectiveZoom()).isEmpty()
+        && !layer.image()->imageSize(&imageClient, imageClient.style()->effectiveZoom(), LayoutSize()).isEmpty()
         && layer.hasRepeatXY();
 }
 
diff --git a/third_party/WebKit/Source/core/paint/NinePieceImageGrid.cpp b/third_party/WebKit/Source/core/paint/NinePieceImageGrid.cpp
index 2feb67c..16c1dad 100644
--- a/third_party/WebKit/Source/core/paint/NinePieceImageGrid.cpp
+++ b/third_party/WebKit/Source/core/paint/NinePieceImageGrid.cpp
@@ -35,14 +35,10 @@
     , m_verticalTileRule((Image::TileRule)ninePieceImage.verticalRule())
     , m_fill(ninePieceImage.fill())
 {
-    StyleImage* styleImage = ninePieceImage.image();
-    ASSERT(styleImage);
-
-    float imageScaleFactor = styleImage->imageScaleFactor();
-    m_top.slice = computeEdgeSlice(ninePieceImage.imageSlices().top(), imageSize.height()) * imageScaleFactor;
-    m_right.slice = computeEdgeSlice(ninePieceImage.imageSlices().right(), imageSize.width()) * imageScaleFactor;
-    m_bottom.slice = computeEdgeSlice(ninePieceImage.imageSlices().bottom(), imageSize.height()) * imageScaleFactor;
-    m_left.slice = computeEdgeSlice(ninePieceImage.imageSlices().left(), imageSize.width()) * imageScaleFactor;
+    m_top.slice = computeEdgeSlice(ninePieceImage.imageSlices().top(), imageSize.height());
+    m_right.slice = computeEdgeSlice(ninePieceImage.imageSlices().right(), imageSize.width());
+    m_bottom.slice = computeEdgeSlice(ninePieceImage.imageSlices().bottom(), imageSize.height());
+    m_left.slice = computeEdgeSlice(ninePieceImage.imageSlices().left(), imageSize.width());
 
     m_top.width = computeEdgeWidth(ninePieceImage.borderSlices().top(), borderWidths.top(), m_top.slice,
         borderImageArea.height());
diff --git a/third_party/WebKit/Source/core/paint/NinePieceImagePainter.cpp b/third_party/WebKit/Source/core/paint/NinePieceImagePainter.cpp
index 6518917..bbc4941 100644
--- a/third_party/WebKit/Source/core/paint/NinePieceImagePainter.cpp
+++ b/third_party/WebKit/Source/core/paint/NinePieceImagePainter.cpp
@@ -49,8 +49,7 @@
     rectWithOutsets.expand(style.imageOutsets(ninePieceImage));
     LayoutRect borderImageRect = rectWithOutsets;
 
-    IntSize imageSize = roundedIntSize(m_layoutObject.calculateImageIntrinsicDimensions(styleImage, borderImageRect.size(),
-        LayoutBoxModelObject::DoNotScaleByEffectiveZoom));
+    IntSize imageSize = roundedIntSize(styleImage->imageSize(&m_layoutObject, 1, borderImageRect.size()));
 
     IntRectOutsets borderWidths(style.borderTopWidth(), style.borderRightWidth(),
         style.borderBottomWidth(), style.borderLeftWidth());
@@ -68,6 +67,10 @@
     for (NinePiece piece = MinPiece; piece < MaxPiece; ++piece) {
         NinePieceImageGrid::NinePieceDrawInfo drawInfo = grid.getNinePieceDrawInfo(piece);
 
+        // The nine piece grid is computed in unscaled image coordinates but must be drawn using
+        // scaled image coordinates.
+        drawInfo.source.scale(styleImage->imageScaleFactor());
+
         if (drawInfo.isDrawable) {
             if (drawInfo.isCornerPiece) {
                 graphicsContext.drawImage(image.get(), drawInfo.destination, drawInfo.source, op);
diff --git a/third_party/WebKit/Source/core/streams/ReadableStreamReaderTest.cpp b/third_party/WebKit/Source/core/streams/ReadableStreamReaderTest.cpp
index 352a30f..f7e12f89 100644
--- a/third_party/WebKit/Source/core/streams/ReadableStreamReaderTest.cpp
+++ b/third_party/WebKit/Source/core/streams/ReadableStreamReaderTest.cpp
@@ -179,7 +179,7 @@
     EXPECT_TRUE(onFulfilled.isNull());
     EXPECT_TRUE(onRejected.isNull());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     EXPECT_TRUE(onFulfilled.isNull());
     EXPECT_EQ("AbortError: the reader is already released", onRejected);
 
@@ -208,7 +208,7 @@
 
     EXPECT_FALSE(result.isSet);
     EXPECT_TRUE(onRejected.isNull());
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_FALSE(result.isSet);
     EXPECT_EQ("TypeError: the reader is already released", onRejected);
@@ -250,7 +250,7 @@
     EXPECT_FALSE(result.isSet);
     EXPECT_TRUE(onRejected.isNull());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_TRUE(result.isSet);
     EXPECT_FALSE(result.isDone);
@@ -264,7 +264,7 @@
     EXPECT_FALSE(result2.isSet);
     EXPECT_TRUE(onRejected2.isNull());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_TRUE(result2.isSet);
     EXPECT_FALSE(result2.isDone);
@@ -290,7 +290,7 @@
     EXPECT_FALSE(result2.isSet);
     EXPECT_TRUE(onRejected2.isNull());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_FALSE(result.isSet);
     EXPECT_TRUE(onRejected.isNull());
@@ -298,7 +298,7 @@
     EXPECT_TRUE(onRejected2.isNull());
 
     m_stream->enqueue("hello");
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_TRUE(result.isSet);
     EXPECT_FALSE(result.isDone);
@@ -308,7 +308,7 @@
     EXPECT_TRUE(onRejected2.isNull());
 
     m_stream->enqueue("world");
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_TRUE(result2.isSet);
     EXPECT_FALSE(result2.isDone);
@@ -330,7 +330,7 @@
     String onClosedFulfilled, onClosedRejected;
     ReadResult result;
     String onReadRejected;
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     reader->closed(scriptState()).then(createCaptor(&onClosedFulfilled), createCaptor(&onClosedRejected));
     reader->read(scriptState()).then(createResultCaptor(&result), createCaptor(&onReadRejected));
     EXPECT_TRUE(onClosedFulfilled.isNull());
@@ -338,7 +338,7 @@
     EXPECT_FALSE(result.isSet);
     EXPECT_TRUE(onReadRejected.isNull());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     EXPECT_EQ("undefined", onClosedFulfilled);
     EXPECT_TRUE(onClosedRejected.isNull());
     EXPECT_TRUE(result.isSet);
@@ -361,7 +361,7 @@
 
     String onClosedFulfilled, onClosedRejected;
     String onReadFulfilled, onReadRejected;
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     reader->closed(scriptState()).then(createCaptor(&onClosedFulfilled), createCaptor(&onClosedRejected));
     reader->read(scriptState()).then(createCaptor(&onReadFulfilled), createCaptor(&onReadRejected));
     EXPECT_TRUE(onClosedFulfilled.isNull());
@@ -369,7 +369,7 @@
     EXPECT_TRUE(onReadFulfilled.isNull());
     EXPECT_TRUE(onReadRejected.isNull());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     EXPECT_TRUE(onClosedFulfilled.isNull());
     EXPECT_EQ("SyntaxError: some error", onClosedRejected);
     EXPECT_TRUE(onReadFulfilled.isNull());
@@ -389,7 +389,7 @@
     reader->read(scriptState()).then(createResultCaptor(&result), createCaptor(&onRejected));
     reader->read(scriptState()).then(createResultCaptor(&result2), createCaptor(&onRejected2));
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     EXPECT_FALSE(result.isSet);
     EXPECT_TRUE(onRejected.isNull());
     EXPECT_FALSE(result2.isSet);
@@ -401,7 +401,7 @@
     EXPECT_FALSE(result2.isSet);
     EXPECT_TRUE(onRejected2.isNull());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_TRUE(result.isSet);
     EXPECT_TRUE(result.isDone);
@@ -427,7 +427,7 @@
     reader->read(scriptState()).then(createCaptor(&onFulfilled), createCaptor(&onRejected));
     reader->read(scriptState()).then(createCaptor(&onFulfilled2), createCaptor(&onRejected2));
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     EXPECT_TRUE(onFulfilled.isNull());
     EXPECT_TRUE(onRejected.isNull());
     EXPECT_TRUE(onFulfilled2.isNull());
@@ -439,7 +439,7 @@
     EXPECT_TRUE(onFulfilled2.isNull());
     EXPECT_TRUE(onRejected2.isNull());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_TRUE(onFulfilled.isNull());
     EXPECT_EQ(onRejected, "SyntaxError: some error");
@@ -460,7 +460,7 @@
     reader->read(scriptState()).then(createResultCaptor(&result), createCaptor(&onRejected));
     reader->read(scriptState()).then(createResultCaptor(&result2), createCaptor(&onRejected2));
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     EXPECT_FALSE(result.isSet);
     EXPECT_TRUE(onRejected.isNull());
     EXPECT_FALSE(result2.isSet);
@@ -473,7 +473,7 @@
     EXPECT_FALSE(result2.isSet);
     EXPECT_TRUE(onRejected2.isNull());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_TRUE(result.isSet);
     EXPECT_TRUE(result.isDone);
@@ -502,7 +502,7 @@
     EXPECT_TRUE(onFulfilled.isNull());
     EXPECT_TRUE(onRejected.isNull());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_TRUE(onFulfilled.isNull());
     EXPECT_EQ("TypeError: the reader is already released", onRejected);
@@ -528,7 +528,7 @@
     EXPECT_TRUE(onCancelFulfilled.isNull());
     EXPECT_TRUE(onCancelRejected.isNull());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     EXPECT_EQ("undefined", onClosedFulfilled);
     EXPECT_TRUE(onClosedRejected.isNull());
     EXPECT_EQ("undefined", onCancelFulfilled);
@@ -552,7 +552,7 @@
     EXPECT_TRUE(onFulfilled.isNull());
     EXPECT_TRUE(onRejected.isNull());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     EXPECT_EQ("undefined", onFulfilled);
     EXPECT_TRUE(onRejected.isNull());
     EXPECT_FALSE(exceptionState.hadException());
@@ -574,7 +574,7 @@
     EXPECT_TRUE(onFulfilled.isNull());
     EXPECT_TRUE(onRejected.isNull());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     EXPECT_TRUE(onFulfilled.isNull());
     EXPECT_EQ("SyntaxError: some error", onRejected);
     EXPECT_FALSE(exceptionState.hadException());
diff --git a/third_party/WebKit/Source/core/streams/ReadableStreamTest.cpp b/third_party/WebKit/Source/core/streams/ReadableStreamTest.cpp
index 031ecdd..fb52f46 100644
--- a/third_party/WebKit/Source/core/streams/ReadableStreamTest.cpp
+++ b/third_party/WebKit/Source/core/streams/ReadableStreamTest.cpp
@@ -304,7 +304,7 @@
 
     stream->read(scriptState());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_EQ(ReadableStream::Readable, stream->stateInternal());
     EXPECT_FALSE(stream->isPulling());
@@ -335,7 +335,7 @@
     EXPECT_TRUE(onFulfilled.isNull());
     EXPECT_TRUE(onRejected.isNull());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     EXPECT_EQ("undefined", onFulfilled);
     EXPECT_TRUE(onRejected.isNull());
 }
@@ -358,7 +358,7 @@
     EXPECT_TRUE(onFulfilled.isNull());
     EXPECT_TRUE(onRejected.isNull());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     EXPECT_TRUE(onFulfilled.isNull());
     EXPECT_EQ("NotFoundError: error", onRejected);
 }
@@ -392,7 +392,7 @@
     EXPECT_TRUE(onCancelFulfilled.isNull());
     EXPECT_TRUE(onCancelRejected.isNull());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     EXPECT_EQ("undefined", onCancelFulfilled);
     EXPECT_TRUE(onCancelRejected.isNull());
 }
@@ -416,7 +416,7 @@
     EXPECT_TRUE(onFulfilled.isNull());
     EXPECT_TRUE(onRejected.isNull());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
 
     EXPECT_TRUE(onFulfilled.isNull());
     EXPECT_EQ("TypeError: this stream is locked to a ReadableStreamReader", onRejected);
@@ -563,7 +563,7 @@
     EXPECT_TRUE(onFulfilled.isNull());
     EXPECT_TRUE(onRejected.isNull());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     EXPECT_EQ("undefined", onFulfilled);
     EXPECT_TRUE(onRejected.isNull());
 }
@@ -586,7 +586,7 @@
     EXPECT_TRUE(onFulfilled.isNull());
     EXPECT_TRUE(onRejected.isNull());
 
-    v8::MicrotasksScope::PerformCheckpoint(isolate());
+    isolate()->RunMicrotasks();
     EXPECT_TRUE(onFulfilled.isNull());
     EXPECT_EQ("SyntaxError: some error", onRejected);
 }
diff --git a/third_party/WebKit/Source/core/style/StyleFetchedImage.cpp b/third_party/WebKit/Source/core/style/StyleFetchedImage.cpp
index 938f53e..94a3d82 100644
--- a/third_party/WebKit/Source/core/style/StyleFetchedImage.cpp
+++ b/third_party/WebKit/Source/core/style/StyleFetchedImage.cpp
@@ -91,9 +91,17 @@
     return m_image->errorOccurred();
 }
 
-LayoutSize StyleFetchedImage::imageSize(const LayoutObject* layoutObject, float multiplier) const
+LayoutSize StyleFetchedImage::imageSize(const LayoutObject* layoutObject, float multiplier, const LayoutSize& defaultObjectSize) const
 {
-    return m_image->imageSize(LayoutObject::shouldRespectImageOrientation(layoutObject), multiplier);
+    if (m_image->image() && m_image->image()->isSVGImage())
+        return imageSizeForSVGImage(toSVGImage(m_image->image()), multiplier, defaultObjectSize);
+
+    // Image orientation should only be respected for content images,
+    // not decorative images such as StyleImage (backgrounds,
+    // border-image, etc.)
+    //
+    // https://drafts.csswg.org/css-images-3/#the-image-orientation
+    return m_image->imageSize(DoNotRespectImageOrientation, multiplier);
 }
 
 bool StyleFetchedImage::imageHasRelativeSize() const
diff --git a/third_party/WebKit/Source/core/style/StyleFetchedImage.h b/third_party/WebKit/Source/core/style/StyleFetchedImage.h
index b20b31ad..863852d 100644
--- a/third_party/WebKit/Source/core/style/StyleFetchedImage.h
+++ b/third_party/WebKit/Source/core/style/StyleFetchedImage.h
@@ -50,7 +50,7 @@
     bool canRender() const override;
     bool isLoaded() const override;
     bool errorOccurred() const override;
-    LayoutSize imageSize(const LayoutObject*, float multiplier) const override;
+    LayoutSize imageSize(const LayoutObject*, float multiplier, const LayoutSize& defaultObjectSize) const override;
     bool imageHasRelativeSize() const override;
     void computeIntrinsicDimensions(const LayoutObject*, FloatSize& intrinsicSize, FloatSize& intrinsicRatio) override;
     bool usesImageContainerSize() const override;
diff --git a/third_party/WebKit/Source/core/style/StyleFetchedImageSet.cpp b/third_party/WebKit/Source/core/style/StyleFetchedImageSet.cpp
index e42aefb..f3c10499 100644
--- a/third_party/WebKit/Source/core/style/StyleFetchedImageSet.cpp
+++ b/third_party/WebKit/Source/core/style/StyleFetchedImageSet.cpp
@@ -93,9 +93,17 @@
     return m_bestFitImage->errorOccurred();
 }
 
-LayoutSize StyleFetchedImageSet::imageSize(const LayoutObject* layoutObject, float multiplier) const
+LayoutSize StyleFetchedImageSet::imageSize(const LayoutObject*, float multiplier, const LayoutSize& defaultObjectSize) const
 {
-    LayoutSize scaledImageSize = m_bestFitImage->imageSize(LayoutObject::shouldRespectImageOrientation(layoutObject), multiplier);
+    if (m_bestFitImage->image() && m_bestFitImage->image()->isSVGImage())
+        return imageSizeForSVGImage(toSVGImage(m_bestFitImage->image()), multiplier, defaultObjectSize);
+
+    // Image orientation should only be respected for content images,
+    // not decorative ones such as StyleImage (backgrounds,
+    // border-image, etc.)
+    //
+    // https://drafts.csswg.org/css-images-3/#the-image-orientation
+    LayoutSize scaledImageSize = m_bestFitImage->imageSize(DoNotRespectImageOrientation, multiplier);
     scaledImageSize.scale(1 / m_imageScaleFactor);
     return scaledImageSize;
 }
diff --git a/third_party/WebKit/Source/core/style/StyleFetchedImageSet.h b/third_party/WebKit/Source/core/style/StyleFetchedImageSet.h
index 615eeff..1703d2f 100644
--- a/third_party/WebKit/Source/core/style/StyleFetchedImageSet.h
+++ b/third_party/WebKit/Source/core/style/StyleFetchedImageSet.h
@@ -62,7 +62,7 @@
     bool canRender() const override;
     bool isLoaded() const override;
     bool errorOccurred() const override;
-    LayoutSize imageSize(const LayoutObject*, float multiplier) const override;
+    LayoutSize imageSize(const LayoutObject*, float multiplier, const LayoutSize& defaultObjectSize) const override;
     bool imageHasRelativeSize() const override;
     void computeIntrinsicDimensions(const LayoutObject*, FloatSize& intrinsicSize, FloatSize& intrinsicRatio) override;
     bool usesImageContainerSize() const override;
diff --git a/third_party/WebKit/Source/core/style/StyleGeneratedImage.cpp b/third_party/WebKit/Source/core/style/StyleGeneratedImage.cpp
index 68aaf42..435b937 100644
--- a/third_party/WebKit/Source/core/style/StyleGeneratedImage.cpp
+++ b/third_party/WebKit/Source/core/style/StyleGeneratedImage.cpp
@@ -46,33 +46,21 @@
     return m_imageGeneratorValue->valueWithURLsMadeAbsolute();
 }
 
-LayoutSize StyleGeneratedImage::imageSize(const LayoutObject* layoutObject, float multiplier) const
+LayoutSize StyleGeneratedImage::imageSize(const LayoutObject* layoutObject, float multiplier, const LayoutSize& defaultObjectSize) const
 {
     if (m_fixedSize) {
-        LayoutSize fixedSize(m_imageGeneratorValue->fixedSize(layoutObject));
-        if (multiplier == 1.0f)
-            return fixedSize;
-
-        LayoutUnit width(fixedSize.width() * multiplier);
-        LayoutUnit height(fixedSize.height() * multiplier);
-
-        // Don't let images that have a width/height >= 1 shrink below 1 when zoomed.
-        if (fixedSize.width() > LayoutUnit())
-            width = max(LayoutUnit(1), width);
-
-        if (fixedSize.height() > LayoutUnit())
-            height = max(LayoutUnit(1), height);
-
-        return LayoutSize(width, height);
+        FloatSize unzoomedDefaultObjectSize(defaultObjectSize);
+        unzoomedDefaultObjectSize.scale(1 / multiplier);
+        return applyZoom(LayoutSize(m_imageGeneratorValue->fixedSize(layoutObject, unzoomedDefaultObjectSize)), multiplier);
     }
 
-    return LayoutSize();
+    return defaultObjectSize;
 }
 
 void StyleGeneratedImage::computeIntrinsicDimensions(const LayoutObject* layoutObject, FloatSize& intrinsicSize, FloatSize& intrinsicRatio)
 {
     // At a zoom level of 1 the image is guaranteed to have an integer size.
-    LayoutSize size = imageSize(layoutObject, 1);
+    LayoutSize size = imageSize(layoutObject, 1, LayoutSize());
     ASSERT(size.fraction().isZero());
     intrinsicSize = intrinsicRatio = FloatSize(size);
 }
diff --git a/third_party/WebKit/Source/core/style/StyleGeneratedImage.h b/third_party/WebKit/Source/core/style/StyleGeneratedImage.h
index 17a4cdd..2b94f78 100644
--- a/third_party/WebKit/Source/core/style/StyleGeneratedImage.h
+++ b/third_party/WebKit/Source/core/style/StyleGeneratedImage.h
@@ -44,7 +44,7 @@
     PassRefPtrWillBeRawPtr<CSSValue> cssValue() const override;
     PassRefPtrWillBeRawPtr<CSSValue> computedCSSValue() const override;
 
-    LayoutSize imageSize(const LayoutObject*, float multiplier) const override;
+    LayoutSize imageSize(const LayoutObject*, float multiplier, const LayoutSize& defaultObjectSize) const override;
     bool imageHasRelativeSize() const override { return !m_fixedSize; }
     void computeIntrinsicDimensions(const LayoutObject*, FloatSize& intrinsicSize, FloatSize& intrinsicRatio) override;
     bool usesImageContainerSize() const override { return !m_fixedSize; }
diff --git a/third_party/WebKit/Source/core/style/StyleImage.cpp b/third_party/WebKit/Source/core/style/StyleImage.cpp
new file mode 100644
index 0000000..b56d90dd
--- /dev/null
+++ b/third_party/WebKit/Source/core/style/StyleImage.cpp
@@ -0,0 +1,37 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/style/StyleImage.h"
+
+#include "core/svg/graphics/SVGImage.h"
+#include "core/svg/graphics/SVGImageForContainer.h"
+
+namespace blink {
+
+LayoutSize StyleImage::applyZoom(const LayoutSize& size, float multiplier)
+{
+    if (multiplier == 1.0f)
+        return size;
+
+    LayoutUnit width(size.width() * multiplier);
+    LayoutUnit height(size.height() * multiplier);
+
+    // Don't let images that have a width/height >= 1 shrink below 1 when zoomed.
+    if (size.width() > LayoutUnit())
+        width = std::max(LayoutUnit(1), width);
+
+    if (size.height() > LayoutUnit())
+        height = std::max(LayoutUnit(1), height);
+
+    return LayoutSize(width, height);
+}
+
+LayoutSize StyleImage::imageSizeForSVGImage(SVGImage* svgImage, float multiplier, const LayoutSize& defaultObjectSize) const
+{
+    FloatSize unzoomedDefaultObjectSize(defaultObjectSize);
+    unzoomedDefaultObjectSize.scale(1 / multiplier);
+    return applyZoom(LayoutSize(svgImage->concreteObjectSize(svgImage->concreteObjectSize(unzoomedDefaultObjectSize))), multiplier);
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/core/style/StyleImage.h b/third_party/WebKit/Source/core/style/StyleImage.h
index 49a050c5..4caa2c42 100644
--- a/third_party/WebKit/Source/core/style/StyleImage.h
+++ b/third_party/WebKit/Source/core/style/StyleImage.h
@@ -38,6 +38,7 @@
 class ImageResource;
 class CSSValue;
 class LayoutObject;
+class SVGImage;
 
 typedef void* WrappedImagePtr;
 
@@ -56,7 +57,7 @@
     virtual bool canRender() const { return true; }
     virtual bool isLoaded() const { return true; }
     virtual bool errorOccurred() const { return false; }
-    virtual LayoutSize imageSize(const LayoutObject*, float multiplier) const = 0;
+    virtual LayoutSize imageSize(const LayoutObject*, float multiplier, const LayoutSize& defaultObjectSize) const = 0;
     virtual void computeIntrinsicDimensions(const LayoutObject*, FloatSize& intrinsicSize, FloatSize& intrinsicRatio) = 0;
     virtual bool imageHasRelativeSize() const = 0;
     virtual bool usesImageContainerSize() const = 0;
@@ -90,6 +91,9 @@
     bool m_isGeneratedImage:1;
     bool m_isImageResourceSet:1;
     bool m_isInvalidImage:1;
+
+    static LayoutSize applyZoom(const LayoutSize&, float multiplier);
+    LayoutSize imageSizeForSVGImage(SVGImage*, float multiplier, const LayoutSize& defaultObjectSize) const;
 };
 
 #define DEFINE_STYLE_IMAGE_TYPE_CASTS(thisType, function) \
diff --git a/third_party/WebKit/Source/core/style/StyleInvalidImage.h b/third_party/WebKit/Source/core/style/StyleInvalidImage.h
index d1004022..79e78993 100644
--- a/third_party/WebKit/Source/core/style/StyleInvalidImage.h
+++ b/third_party/WebKit/Source/core/style/StyleInvalidImage.h
@@ -23,7 +23,7 @@
 
     PassRefPtrWillBeRawPtr<CSSValue> computedCSSValue() const override { return cssValue(); }
 
-    LayoutSize imageSize(const LayoutObject*, float /*multiplier*/) const override { return LayoutSize(); }
+    LayoutSize imageSize(const LayoutObject*, float /*multiplier*/, const LayoutSize& /*defaultObjectSize*/) const override { return LayoutSize(); }
     bool imageHasRelativeSize() const override { return false; }
     void computeIntrinsicDimensions(const LayoutObject*, FloatSize& /* intrinsicSize */, FloatSize& /* intrinsicRatio */) override { }
     bool usesImageContainerSize() const override { return false; }
diff --git a/third_party/WebKit/Source/core/style/StylePendingImage.h b/third_party/WebKit/Source/core/style/StylePendingImage.h
index 95f8c6e1..ee165802 100644
--- a/third_party/WebKit/Source/core/style/StylePendingImage.h
+++ b/third_party/WebKit/Source/core/style/StylePendingImage.h
@@ -61,7 +61,7 @@
     CSSCursorImageValue* cssCursorImageValue() const { return m_value->isCursorImageValue() ? toCSSCursorImageValue(m_value.get()) : 0; }
     CSSImageSetValue* cssImageSetValue() const { return m_value->isImageSetValue() ? toCSSImageSetValue(m_value.get()) : 0; }
 
-    LayoutSize imageSize(const LayoutObject*, float /*multiplier*/) const override { return LayoutSize(); }
+    LayoutSize imageSize(const LayoutObject*, float /*multiplier*/, const LayoutSize& /*defaultObjectSize*/) const override { return LayoutSize(); }
     bool imageHasRelativeSize() const override { return false; }
     void computeIntrinsicDimensions(const LayoutObject*, FloatSize& /* intrinsicSize */, FloatSize& /* intrinsicRatio */) override { }
     bool usesImageContainerSize() const override { return false; }
diff --git a/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp b/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp
index b1141564..aaccff3 100644
--- a/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp
+++ b/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp
@@ -155,7 +155,7 @@
     ASSERT(layoutObject->style()->effectiveZoom() == 1);
 
     // No set container size; use concrete object size.
-    return m_concreteObjectSize;
+    return m_intrinsicSize;
 }
 
 static float resolveWidthForRatio(float height, const FloatSize& intrinsicRatio)
@@ -168,7 +168,7 @@
     return width * intrinsicRatio.height() / intrinsicRatio.width();
 }
 
-FloatSize SVGImage::calculateConcreteObjectSize(const FloatSize& defaultObjectSize) const
+FloatSize SVGImage::concreteObjectSize(const FloatSize& defaultObjectSize) const
 {
     SVGSVGElement* svg = svgRootElement(m_page.get());
     if (!svg)
@@ -208,11 +208,25 @@
     }
 
     if (!intrinsicSizingInfo.aspectRatio.isEmpty()) {
-        // TODO(davve): According to the specification, the concrete object size should resolve as a
-        // contain constraint against the default object size at this stage. Until the
-        // defaultObjectSize is context sensitive, right now it's hard-coded to 300x150, we have to
-        // preserve legacy behavior by returning the aspectRatio as the concrete object size.
-        return intrinsicSizingInfo.aspectRatio;
+        // "A contain constraint is resolved by setting the concrete object size to the largest
+        //  rectangle that has the object's intrinsic aspect ratio and additionally has neither
+        //  width nor height larger than the constraint rectangle's width and height, respectively."
+        float solutionWidth = resolveWidthForRatio(defaultObjectSize.height(), intrinsicSizingInfo.aspectRatio);
+        float solutionHeight = resolveHeightForRatio(defaultObjectSize.width(), intrinsicSizingInfo.aspectRatio);
+        if (solutionWidth <= defaultObjectSize.width()) {
+            if (solutionHeight <= defaultObjectSize.height()) {
+                float areaOne = solutionWidth * defaultObjectSize.height();
+                float areaTwo = defaultObjectSize.width() * solutionHeight;
+                if (areaOne < areaTwo)
+                    return FloatSize(defaultObjectSize.width(), solutionHeight);
+                return FloatSize(solutionWidth, defaultObjectSize.height());
+            }
+
+            return FloatSize(solutionWidth, defaultObjectSize.height());
+        }
+
+        ASSERT(solutionHeight <= defaultObjectSize.height());
+        return FloatSize(defaultObjectSize.width(), solutionHeight);
     }
 
     return defaultObjectSize;
@@ -535,7 +549,7 @@
             AtomicString("UTF-8", AtomicString::ConstructFromLiteral), KURL(), ForceSynchronousLoad)));
 
         // Set the concrete object size before a container size is available.
-        m_concreteObjectSize = roundedIntSize(calculateConcreteObjectSize(FloatSize(300, 150)));
+        m_intrinsicSize = roundedIntSize(concreteObjectSize(FloatSize(300, 150)));
     }
 
     return m_page;
diff --git a/third_party/WebKit/Source/core/svg/graphics/SVGImage.h b/third_party/WebKit/Source/core/svg/graphics/SVGImage.h
index 8fc42e6..903b9a8 100644
--- a/third_party/WebKit/Source/core/svg/graphics/SVGImage.h
+++ b/third_party/WebKit/Source/core/svg/graphics/SVGImage.h
@@ -55,7 +55,7 @@
 
     bool isSVGImage() const override { return true; }
     bool isTextureBacked() override { return false; }
-    IntSize size() const override { return m_concreteObjectSize; }
+    IntSize size() const override { return m_intrinsicSize; }
 
     bool currentFrameHasSingleSecurityOrigin() const override;
 
@@ -77,6 +77,8 @@
 
     void updateUseCounters(Document&) const;
 
+    FloatSize concreteObjectSize(const FloatSize&) const;
+
     // DisplayItemClient methods.
     String debugName() const final { return "SVGImage"; }
     LayoutRect visualRect() const override;
@@ -90,7 +92,6 @@
 
     String filenameExtension() const override;
 
-    FloatSize calculateConcreteObjectSize(const FloatSize&) const;
     IntSize containerSize() const;
     bool usesContainerSize() const override { return true; }
     void computeIntrinsicDimensions(FloatSize& intrinsicSize, FloatSize& intrinsicRatio) override;
@@ -116,18 +117,13 @@
     OwnPtrWillBePersistent<SVGImageChromeClient> m_chromeClient;
     OwnPtrWillBePersistent<Page> m_page;
 
-    // "The concrete object size is the result of combining an
-    // object’s intrinsic dimensions and specified size with the
-    // default object size of the context it’s used in, producing a
-    // rectangle with a definite width and height."
-    //
-    // https://drafts.csswg.org/css-images-3/#concrete-object-size
-    //
-    // Note: For SVGImage there are no specified size
-    // constraints. Such constraints are handled by the layout
-    // machinery in LayoutReplaced. An image has only intrinsic size,
-    // aspect ratio and default object size to consider.
-    IntSize m_concreteObjectSize;
+    // When an SVG image has no intrinsic size the size depends on the
+    // default object size, which in turn depends on the
+    // container. SVGImage may belong to multiple containers so the
+    // final image size can't be known in
+    // SVGImage. SVGImageForContainer carried the final image size,
+    // also called concrete object size.
+    IntSize m_intrinsicSize;
 };
 
 DEFINE_IMAGE_TYPE_CASTS(SVGImage);
diff --git a/third_party/WebKit/Source/modules/InitModules.cpp b/third_party/WebKit/Source/modules/InitModules.cpp
index 539c6b25..031048d 100644
--- a/third_party/WebKit/Source/modules/InitModules.cpp
+++ b/third_party/WebKit/Source/modules/InitModules.cpp
@@ -16,6 +16,8 @@
 #include "modules/canvas2d/CanvasRenderingContext2D.h"
 #include "modules/filesystem/DraggedIsolatedFileSystemImpl.h"
 #include "modules/imagebitmap/ImageBitmapRenderingContext.h"
+#include "modules/offscreencanvas/OffscreenCanvas.h"
+#include "modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h"
 #include "modules/webdatabase/DatabaseManager.h"
 #include "modules/webgl/WebGL2RenderingContext.h"
 #include "modules/webgl/WebGLRenderingContext.h"
@@ -48,6 +50,9 @@
     HTMLCanvasElement::registerRenderingContextFactory(adoptPtr(new WebGL2RenderingContext::Factory()));
     HTMLCanvasElement::registerRenderingContextFactory(adoptPtr(new ImageBitmapRenderingContext::Factory()));
 
+    // OffscreenCanvas context types must be registered with the OffscreenCanvas.
+    OffscreenCanvas::registerRenderingContextFactory(adoptPtr(new OffscreenCanvasRenderingContext2D::Factory()));
+
     ASSERT(isInitialized());
 }
 
diff --git a/third_party/WebKit/Source/modules/cachestorage/CacheTest.cpp b/third_party/WebKit/Source/modules/cachestorage/CacheTest.cpp
index 1c4030cb..7834ae9 100644
--- a/third_party/WebKit/Source/modules/cachestorage/CacheTest.cpp
+++ b/third_party/WebKit/Source/modules/cachestorage/CacheTest.cpp
@@ -249,7 +249,7 @@
     {
         ScriptValue onReject;
         promise.then(UnreachableFunction::create(scriptState()), TestFunction::create(scriptState(), &onReject));
-        v8::MicrotasksScope::PerformCheckpoint(isolate());
+        isolate()->RunMicrotasks();
         return onReject;
     }
 
@@ -263,7 +263,7 @@
     {
         ScriptValue onResolve;
         promise.then(TestFunction::create(scriptState(), &onResolve), UnreachableFunction::create(scriptState()));
-        v8::MicrotasksScope::PerformCheckpoint(isolate());
+        isolate()->RunMicrotasks();
         return onResolve;
     }
 
diff --git a/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.h b/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.h
index 8003fed1..8021b8e 100644
--- a/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.h
+++ b/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.h
@@ -7,7 +7,6 @@
 
 #include "bindings/core/v8/UnionTypesCore.h"
 #include "bindings/modules/v8/UnionTypesModules.h"
-#include "core/html/canvas/CanvasRenderingContext.h"
 #include "modules/ModulesExport.h"
 #include "modules/canvas2d/CanvasGradient.h"
 #include "modules/canvas2d/CanvasPathMethods.h"
diff --git a/third_party/WebKit/Source/modules/fetch/ReadableStreamDataConsumerHandleTest.cpp b/third_party/WebKit/Source/modules/fetch/ReadableStreamDataConsumerHandleTest.cpp
index fba225c..9a9daead 100644
--- a/third_party/WebKit/Source/modules/fetch/ReadableStreamDataConsumerHandleTest.cpp
+++ b/third_party/WebKit/Source/modules/fetch/ReadableStreamDataConsumerHandleTest.cpp
@@ -8,7 +8,6 @@
 #include "bindings/core/v8/ScriptState.h"
 #include "bindings/core/v8/V8BindingMacros.h"
 #include "bindings/core/v8/V8GCController.h"
-#include "bindings/core/v8/V8RecursionScope.h"
 #include "core/dom/Document.h"
 #include "core/testing/DummyPageHolder.h"
 #include "modules/fetch/DataConsumerHandleTestUtil.h"
@@ -60,7 +59,6 @@
     {
         v8::Local<v8::String> source;
         v8::Local<v8::Script> script;
-        V8RecursionScope::MicrotaskSuppression microtasks(isolate());
         if (!v8Call(v8::String::NewFromUtf8(isolate(), s, v8::NewStringType::kNormal), source)) {
             ADD_FAILURE();
             return v8::MaybeLocal<v8::Value>();
diff --git a/third_party/WebKit/Source/modules/modules.gypi b/third_party/WebKit/Source/modules/modules.gypi
index 0cd43e1..b06446c 100644
--- a/third_party/WebKit/Source/modules/modules.gypi
+++ b/third_party/WebKit/Source/modules/modules.gypi
@@ -150,6 +150,8 @@
       'notifications/Notification.idl',
       'notifications/NotificationEvent.idl',
       'notifications/NotificationPermissionCallback.idl',
+      'offscreencanvas/OffscreenCanvas.idl',
+      'offscreencanvas2d/OffscreenCanvasRenderingContext2D.idl',
       'payments/PaymentRequest.idl',
       'payments/PaymentResponse.idl',
       'payments/ShippingAddress.idl',
@@ -1318,6 +1320,13 @@
       'notifications/ServiceWorkerGlobalScopeNotifications.h',
       'notifications/ServiceWorkerRegistrationNotifications.cpp',
       'notifications/ServiceWorkerRegistrationNotifications.h',
+      'offscreencanvas/OffscreenCanvas.cpp',
+      'offscreencanvas/OffscreenCanvas.h',
+      'offscreencanvas/OffscreenCanvasRenderingContext.cpp',
+      'offscreencanvas/OffscreenCanvasRenderingContext.h',
+      'offscreencanvas/OffscreenCanvasRenderingContextFactory.h',
+      'offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp',
+      'offscreencanvas2d/OffscreenCanvasRenderingContext2D.h',
       'payments/PaymentRequest.cpp',
       'payments/PaymentRequest.h',
       'payments/PaymentResponse.cpp',
@@ -1958,7 +1967,6 @@
       'mediastream/RTCDataChannelTest.cpp',
       'notifications/NotificationDataTest.cpp',
       'presentation/PresentationAvailabilityTest.cpp',
-      'push_messaging/PushManagerTest.cpp',
       'push_messaging/PushMessageDataTest.cpp',
       'serviceworkers/ServiceWorkerContainerTest.cpp',
       'webaudio/AudioBasicProcessorHandlerTest.cpp',
diff --git a/third_party/WebKit/Source/modules/offscreencanvas/OWNERS b/third_party/WebKit/Source/modules/offscreencanvas/OWNERS
new file mode 100644
index 0000000..28fb2d0
--- /dev/null
+++ b/third_party/WebKit/Source/modules/offscreencanvas/OWNERS
@@ -0,0 +1 @@
+junov@chromium.org
diff --git a/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvas.cpp b/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvas.cpp
new file mode 100644
index 0000000..1a00c5b
--- /dev/null
+++ b/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvas.cpp
@@ -0,0 +1,95 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "modules/offscreencanvas/OffscreenCanvas.h"
+
+#include "core/html/canvas/CanvasContextCreationAttributes.h"
+#include "modules/offscreencanvas/OffscreenCanvasRenderingContext.h"
+#include "modules/offscreencanvas/OffscreenCanvasRenderingContextFactory.h"
+#include "modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h"
+#include "wtf/MathExtras.h"
+
+namespace blink {
+
+OffscreenCanvas* OffscreenCanvas::create(unsigned width, unsigned height)
+{
+    return new OffscreenCanvas(IntSize(clampTo<int>(width), clampTo<int>(height)));
+}
+
+void OffscreenCanvas::setWidth(unsigned width)
+{
+    m_size.setWidth(clampTo<int>(width));
+}
+
+void OffscreenCanvas::setHeight(unsigned height)
+{
+    m_size.setHeight(clampTo<int>(height));
+}
+
+OffscreenCanvas::OffscreenCanvas(const IntSize& size)
+    : m_size(size)
+{
+}
+
+OffscreenCanvasRenderingContext2D* OffscreenCanvas::getContext(const String& id, const CanvasContextCreationAttributes& attributes)
+{
+    OffscreenCanvasRenderingContext::ContextType contextType = OffscreenCanvasRenderingContext::contextTypeFromId(id);
+
+    // Unknown type.
+    if (contextType == OffscreenCanvasRenderingContext::ContextTypeCount)
+        return nullptr;
+
+    OffscreenCanvasRenderingContextFactory* factory = getRenderingContextFactory(contextType);
+    if (!factory)
+        return nullptr;
+
+    if (m_context) {
+        if (m_context->contextType() != contextType) {
+            factory->onError(this, "OffscreenCanvas has an existing context of a different type");
+            return nullptr;
+        }
+    } else {
+        m_context = factory->create(this, attributes);
+    }
+
+    // TODO: When there're more than one context type implemented in the future,
+    // the return type here should be changed to base class of all Offscreen
+    // context types.
+    return static_cast<OffscreenCanvasRenderingContext2D*>(m_context.get());
+}
+
+OffscreenCanvasRenderingContext2D* OffscreenCanvas::renderingContext() const
+{
+    // TODO: When there're more than one context type implemented in the future,
+    // the return type here should be changed to base class of all Offscreen
+    // context types.
+    return static_cast<OffscreenCanvasRenderingContext2D*>(m_context.get());
+}
+
+OffscreenCanvas::ContextFactoryVector& OffscreenCanvas::renderingContextFactories()
+{
+    DEFINE_STATIC_LOCAL(ContextFactoryVector, s_contextFactories, (OffscreenCanvasRenderingContext::ContextTypeCount));
+    return s_contextFactories;
+}
+
+OffscreenCanvasRenderingContextFactory* OffscreenCanvas::getRenderingContextFactory(int type)
+{
+    ASSERT(type < OffscreenCanvasRenderingContext::ContextTypeCount);
+    return renderingContextFactories()[type].get();
+}
+
+void OffscreenCanvas::registerRenderingContextFactory(PassOwnPtr<OffscreenCanvasRenderingContextFactory> renderingContextFactory)
+{
+    OffscreenCanvasRenderingContext::ContextType type = renderingContextFactory->contextType();
+    ASSERT(type < OffscreenCanvasRenderingContext::ContextTypeCount);
+    ASSERT(!renderingContextFactories()[type]);
+    renderingContextFactories()[type] = renderingContextFactory;
+}
+
+DEFINE_TRACE(OffscreenCanvas)
+{
+    visitor->trace(m_context);
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvas.h b/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvas.h
new file mode 100644
index 0000000..abfc419
--- /dev/null
+++ b/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvas.h
@@ -0,0 +1,54 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OffscreenCanvas_h
+#define OffscreenCanvas_h
+
+#include "bindings/core/v8/ScriptPromise.h"
+#include "bindings/core/v8/ScriptState.h"
+#include "bindings/core/v8/ScriptWrappable.h"
+#include "modules/ModulesExport.h"
+#include "platform/geometry/IntSize.h"
+#include "platform/heap/Handle.h"
+
+namespace blink {
+
+class CanvasContextCreationAttributes;
+class OffscreenCanvasRenderingContext;
+class OffscreenCanvasRenderingContext2D;
+class OffscreenCanvasRenderingContextFactory;
+
+class MODULES_EXPORT OffscreenCanvas final : public GarbageCollectedFinalized<OffscreenCanvas>, public ScriptWrappable {
+    DEFINE_WRAPPERTYPEINFO();
+public:
+    static OffscreenCanvas* create(unsigned width, unsigned height);
+    ~OffscreenCanvas() {}
+
+    IntSize size() const { return m_size; }
+    unsigned width() const { return m_size.width(); }
+    unsigned height() const { return m_size.height(); }
+    void setWidth(unsigned);
+    void setHeight(unsigned);
+
+    OffscreenCanvasRenderingContext2D* getContext(const String&, const CanvasContextCreationAttributes&);
+    OffscreenCanvasRenderingContext2D* renderingContext() const;
+
+    static void registerRenderingContextFactory(PassOwnPtr<OffscreenCanvasRenderingContextFactory>);
+
+    DECLARE_VIRTUAL_TRACE();
+
+private:
+    OffscreenCanvas(const IntSize&);
+
+    using ContextFactoryVector = Vector<OwnPtr<OffscreenCanvasRenderingContextFactory>>;
+    static ContextFactoryVector& renderingContextFactories();
+    static OffscreenCanvasRenderingContextFactory* getRenderingContextFactory(int);
+
+    Member<OffscreenCanvasRenderingContext> m_context;
+    IntSize m_size;
+};
+
+} // namespace blink
+
+#endif // OffscreenCanvas_h
diff --git a/third_party/WebKit/Source/core/html/canvas/OffscreenCanvas.idl b/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvas.idl
similarity index 60%
rename from third_party/WebKit/Source/core/html/canvas/OffscreenCanvas.idl
rename to third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvas.idl
index be5bf91..b1436b0 100644
--- a/third_party/WebKit/Source/core/html/canvas/OffscreenCanvas.idl
+++ b/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvas.idl
@@ -2,6 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// Note: If there're more context types implemented, they should be added here
+// to form a union type of OffscreenCanvasRenderingContext
+typedef OffscreenCanvasRenderingContext2D OffscreenRenderingContext;
+
 [
     Constructor([EnforceRange] unsigned long width, [EnforceRange] unsigned long height),
     GarbageCollected,
@@ -10,4 +14,6 @@
 ] interface OffscreenCanvas {
     [EnforceRange] attribute unsigned long width;
     [EnforceRange] attribute unsigned long height;
+
+    OffscreenRenderingContext? getContext(DOMString contextId, optional CanvasContextCreationAttributes attributes); 
 };
diff --git a/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvasRenderingContext.cpp b/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvasRenderingContext.cpp
new file mode 100644
index 0000000..5b3234c6
--- /dev/null
+++ b/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvasRenderingContext.cpp
@@ -0,0 +1,30 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "modules/offscreencanvas/OffscreenCanvasRenderingContext.h"
+
+namespace blink {
+
+OffscreenCanvasRenderingContext::OffscreenCanvasRenderingContext(OffscreenCanvas* canvas)
+    : m_offscreenCanvas(canvas)
+{
+}
+
+OffscreenCanvasRenderingContext::ContextType OffscreenCanvasRenderingContext::contextTypeFromId(const String& id)
+{
+    if (id == "2d")
+        return Context2d;
+    if (id == "webgl")
+        return ContextWebgl;
+    if (id == "webgl2")
+        return ContextWebgl2;
+    return ContextTypeCount;
+}
+
+DEFINE_TRACE(OffscreenCanvasRenderingContext)
+{
+    visitor->trace(m_offscreenCanvas);
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvasRenderingContext.h b/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvasRenderingContext.h
new file mode 100644
index 0000000..b47aa08
--- /dev/null
+++ b/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvasRenderingContext.h
@@ -0,0 +1,40 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OffscreenCanvasRenderingContext_h
+#define OffscreenCanvasRenderingContext_h
+
+#include "modules/ModulesExport.h"
+#include "modules/offscreencanvas/OffscreenCanvas.h"
+
+namespace blink {
+
+class MODULES_EXPORT OffscreenCanvasRenderingContext : public GarbageCollectedFinalized<OffscreenCanvasRenderingContext>, public ScriptWrappable {
+    WTF_MAKE_NONCOPYABLE(OffscreenCanvasRenderingContext);
+public:
+    virtual ~OffscreenCanvasRenderingContext() { }
+    enum ContextType {
+        Context2d = 0,
+        ContextWebgl = 1,
+        ContextWebgl2 = 2,
+        ContextTypeCount
+    };
+    static ContextType contextTypeFromId(const String& id);
+
+    OffscreenCanvas* offscreenCanvas() const { return m_offscreenCanvas; }
+    virtual ContextType contextType() const = 0;
+
+    virtual bool is2d() const { return false; }
+
+protected:
+    OffscreenCanvasRenderingContext(OffscreenCanvas*);
+    DECLARE_VIRTUAL_TRACE();
+
+private:
+    Member<OffscreenCanvas> m_offscreenCanvas;
+};
+
+} // namespace blink
+
+#endif // OffscreenCanvasRenderingContext_h
diff --git a/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvasRenderingContextFactory.h b/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvasRenderingContextFactory.h
new file mode 100644
index 0000000..9892cc7
--- /dev/null
+++ b/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvasRenderingContextFactory.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OffscreenCanvasRenderingContextFactory_h
+#define OffscreenCanvasRenderingContextFactory_h
+
+#include "wtf/Allocator.h"
+#include "wtf/PassRefPtr.h"
+
+namespace blink {
+
+class CanvasContextCreationAttributes;
+class OffscreenCanvas;
+class OffscreenCanvasRenderingContext;
+
+class OffscreenCanvasRenderingContextFactory {
+    USING_FAST_MALLOC(OffscreenCanvasRenderingContextFactory);
+    WTF_MAKE_NONCOPYABLE(OffscreenCanvasRenderingContextFactory);
+public:
+    OffscreenCanvasRenderingContextFactory() = default;
+    virtual ~OffscreenCanvasRenderingContextFactory() { }
+
+    virtual OffscreenCanvasRenderingContext* create(OffscreenCanvas*, const CanvasContextCreationAttributes&) = 0;
+    virtual OffscreenCanvasRenderingContext::ContextType contextType() const = 0;
+    virtual void onError(OffscreenCanvas*, const String& error) = 0;
+};
+
+} // namespace blink
+
+#endif // OffscreenCanvasRenderingContextFactory_h
diff --git a/third_party/WebKit/Source/modules/offscreencanvas2d/OWNERS b/third_party/WebKit/Source/modules/offscreencanvas2d/OWNERS
new file mode 100644
index 0000000..28fb2d0
--- /dev/null
+++ b/third_party/WebKit/Source/modules/offscreencanvas2d/OWNERS
@@ -0,0 +1 @@
+junov@chromium.org
diff --git a/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp b/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp
new file mode 100644
index 0000000..3349165
--- /dev/null
+++ b/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp
@@ -0,0 +1,128 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h"
+
+#include "bindings/modules/v8/UnionTypesModules.h"
+#include "platform/NotImplemented.h"
+#include "wtf/Assertions.h"
+
+#define UNIMPLEMENTED ASSERT_NOT_REACHED
+
+namespace blink {
+
+OffscreenCanvasRenderingContext2D::~OffscreenCanvasRenderingContext2D()
+{
+}
+
+OffscreenCanvasRenderingContext2D::OffscreenCanvasRenderingContext2D(OffscreenCanvas* canvas, const CanvasContextCreationAttributes& attrs)
+    : OffscreenCanvasRenderingContext(canvas)
+    , m_hasAlpha(attrs.alpha())
+{
+}
+
+DEFINE_TRACE(OffscreenCanvasRenderingContext2D)
+{
+    OffscreenCanvasRenderingContext::trace(visitor);
+    BaseRenderingContext2D::trace(visitor);
+}
+
+// BaseRenderingContext2D implementation
+bool OffscreenCanvasRenderingContext2D::originClean() const
+{
+    notImplemented();
+    return true;
+}
+
+void OffscreenCanvasRenderingContext2D::setOriginTainted()
+{
+    notImplemented();
+}
+
+bool OffscreenCanvasRenderingContext2D::wouldTaintOrigin(CanvasImageSource* source)
+{
+    notImplemented();
+    return false;
+}
+
+int OffscreenCanvasRenderingContext2D::width() const
+{
+    return offscreenCanvas()->height();
+}
+
+int OffscreenCanvasRenderingContext2D::height() const
+{
+    return offscreenCanvas()->width();
+}
+
+bool OffscreenCanvasRenderingContext2D::hasImageBuffer() const
+{
+    notImplemented();
+    return false;
+}
+
+ImageBuffer* OffscreenCanvasRenderingContext2D::imageBuffer() const
+{
+    notImplemented();
+    return nullptr;
+}
+
+bool OffscreenCanvasRenderingContext2D::parseColorOrCurrentColor(Color&, const String& colorString) const
+{
+    notImplemented();
+    return false;
+}
+
+SkCanvas* OffscreenCanvasRenderingContext2D::drawingCanvas() const
+{
+    notImplemented();
+    return nullptr;
+}
+
+SkCanvas* OffscreenCanvasRenderingContext2D::existingDrawingCanvas() const
+{
+    notImplemented();
+    return nullptr;
+}
+
+void OffscreenCanvasRenderingContext2D::disableDeferral(DisableDeferralReason)
+{
+    notImplemented();
+}
+
+AffineTransform OffscreenCanvasRenderingContext2D::baseTransform() const
+{
+    notImplemented();
+    return 0;
+}
+
+void OffscreenCanvasRenderingContext2D::didDraw(const SkIRect& dirtyRect)
+{
+    notImplemented();
+}
+
+bool OffscreenCanvasRenderingContext2D::stateHasFilter()
+{
+    notImplemented();
+    return false;
+}
+
+SkImageFilter* OffscreenCanvasRenderingContext2D::stateGetFilter()
+{
+    notImplemented();
+    return nullptr;
+}
+
+void OffscreenCanvasRenderingContext2D::validateStateStack()
+{
+    notImplemented();
+}
+
+bool OffscreenCanvasRenderingContext2D::isContextLost() const
+{
+    notImplemented();
+    return false;
+}
+
+}
diff --git a/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h b/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h
new file mode 100644
index 0000000..1401fbc
--- /dev/null
+++ b/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h
@@ -0,0 +1,80 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OffscreenCanvasRenderingContext2D_h
+#define OffscreenCanvasRenderingContext2D_h
+
+#include "core/html/canvas/CanvasContextCreationAttributes.h"
+#include "modules/canvas2d/BaseRenderingContext2D.h"
+#include "modules/offscreencanvas/OffscreenCanvasRenderingContext.h"
+#include "modules/offscreencanvas/OffscreenCanvasRenderingContextFactory.h"
+
+namespace blink {
+
+class MODULES_EXPORT OffscreenCanvasRenderingContext2D final : public OffscreenCanvasRenderingContext, public BaseRenderingContext2D {
+    DEFINE_WRAPPERTYPEINFO();
+    WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(OffscreenCanvasRenderingContext2D);
+public:
+    class Factory : public OffscreenCanvasRenderingContextFactory {
+    public:
+        Factory() {}
+        ~Factory() override {}
+
+        OffscreenCanvasRenderingContext* create(OffscreenCanvas* canvas, const CanvasContextCreationAttributes& attrs) override
+        {
+            return new OffscreenCanvasRenderingContext2D(canvas, attrs);
+        }
+
+        OffscreenCanvasRenderingContext::ContextType contextType() const override
+        {
+            return OffscreenCanvasRenderingContext::Context2d;
+        }
+
+        void onError(OffscreenCanvas* canvas, const String& error) override {}
+    };
+
+    // OffscreenCanvasRenderingContext implementation
+    ~OffscreenCanvasRenderingContext2D() override;
+    ContextType contextType() const override { return Context2d; }
+    bool is2d() const override { return true; }
+
+    // BaseRenderingContext2D implementation
+    bool originClean() const final;
+    void setOriginTainted() final;
+    bool wouldTaintOrigin(CanvasImageSource*) final;
+
+    int width() const final;
+    int height() const final;
+
+    bool hasImageBuffer() const final;
+    ImageBuffer* imageBuffer() const final;
+
+    bool parseColorOrCurrentColor(Color&, const String& colorString) const final;
+
+    SkCanvas* drawingCanvas() const final;
+    SkCanvas* existingDrawingCanvas() const final;
+    void disableDeferral(DisableDeferralReason) final;
+
+    AffineTransform baseTransform() const final;
+    void didDraw(const SkIRect& dirtyRect) final;
+
+    bool stateHasFilter() final;
+    SkImageFilter* stateGetFilter() final;
+
+    void validateStateStack() final;
+
+    bool hasAlpha() const override { return m_hasAlpha; }
+    bool isContextLost() const override;
+
+protected:
+    OffscreenCanvasRenderingContext2D(OffscreenCanvas*, const CanvasContextCreationAttributes& attrs);
+    DECLARE_VIRTUAL_TRACE();
+
+private:
+    bool m_hasAlpha;
+};
+
+} // namespace blink
+
+#endif // OffscreenCanvasRenderingContext2D_h
diff --git a/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.idl b/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.idl
new file mode 100644
index 0000000..5c33a57
--- /dev/null
+++ b/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.idl
@@ -0,0 +1,16 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Note: The official spec is WIP at wiki.whatwg.org/wiki/OffscreenCanvas.
+
+[
+    GarbageCollected,
+    Exposed=(Window,Worker),
+    RuntimeEnabled=ExperimentalCanvasFeatures,
+] interface OffscreenCanvasRenderingContext2D {
+    // back-reference to the canvas
+    readonly attribute OffscreenCanvas offscreenCanvas;
+};
+
+OffscreenCanvasRenderingContext2D implements CanvasPathMethods;
diff --git a/third_party/WebKit/Source/modules/push_messaging/PushManager.cpp b/third_party/WebKit/Source/modules/push_messaging/PushManager.cpp
index 7d5eacd0..0f5a2ff 100644
--- a/third_party/WebKit/Source/modules/push_messaging/PushManager.cpp
+++ b/third_party/WebKit/Source/modules/push_messaging/PushManager.cpp
@@ -34,29 +34,11 @@
     return webPushProvider;
 }
 
-String bufferSourceToString(const ArrayBufferOrArrayBufferView& applicationServerKey, ExceptionState& exceptionState)
+WebPushSubscriptionOptions toWebPushSubscriptionOptions(const PushSubscriptionOptions& options)
 {
-    // Check the validity of the sender info. It must be a 65 byte unencrypted key,
-    // which has the byte 0x04 as the first byte as a marker.
-    char* input;
-    int length;
-    if (applicationServerKey.isArrayBuffer()) {
-        input = static_cast<char*>(
-            applicationServerKey.getAsArrayBuffer()->data());
-        length = applicationServerKey.getAsArrayBuffer()->byteLength();
-    } else if (applicationServerKey.isArrayBufferView()) {
-        input = static_cast<char*>(
-            applicationServerKey.getAsArrayBufferView()->buffer()->data());
-        length = applicationServerKey.getAsArrayBufferView()->buffer()->byteLength();
-    } else {
-        ASSERT_NOT_REACHED();
-        return String();
-    }
-
-    if (length == 65 && input[0] == 0x04)
-        return WebString::fromUTF8(input, length);
-    exceptionState.throwDOMException(InvalidAccessError, "The provided applicationServerKey is not valid.");
-    return String();
+    WebPushSubscriptionOptions webOptions;
+    webOptions.userVisibleOnly = options.userVisibleOnly();
+    return webOptions;
 }
 
 } // namespace
@@ -67,26 +49,11 @@
     ASSERT(registration);
 }
 
-WebPushSubscriptionOptions PushManager::toWebPushSubscriptionOptions(const PushSubscriptionOptions& options, ExceptionState& exceptionState)
-{
-    WebPushSubscriptionOptions webOptions;
-    webOptions.userVisibleOnly = options.userVisibleOnly();
-    if (options.hasApplicationServerKey()) {
-        webOptions.applicationServerKey = bufferSourceToString(options.applicationServerKey(),
-            exceptionState);
-    }
-    return webOptions;
-}
-
-ScriptPromise PushManager::subscribe(ScriptState* scriptState, const PushSubscriptionOptions& options, ExceptionState& exceptionState)
+ScriptPromise PushManager::subscribe(ScriptState* scriptState, const PushSubscriptionOptions& options)
 {
     if (!m_registration->active())
         return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(AbortError, "Subscription failed - no active Service Worker"));
 
-    const WebPushSubscriptionOptions& webOptions = toWebPushSubscriptionOptions(options, exceptionState);
-    if (exceptionState.hadException())
-        return ScriptPromise();
-
     ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
     ScriptPromise promise = resolver->promise();
 
@@ -97,9 +64,9 @@
         Document* document = toDocument(scriptState->executionContext());
         if (!document->domWindow() || !document->frame())
             return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(InvalidStateError, "Document is detached from window."));
-        PushController::clientFrom(document->frame()).subscribe(m_registration->webRegistration(), webOptions, new PushSubscriptionCallbacks(resolver, m_registration));
+        PushController::clientFrom(document->frame()).subscribe(m_registration->webRegistration(), toWebPushSubscriptionOptions(options), new PushSubscriptionCallbacks(resolver, m_registration));
     } else {
-        pushProvider()->subscribe(m_registration->webRegistration(), webOptions, new PushSubscriptionCallbacks(resolver, m_registration));
+        pushProvider()->subscribe(m_registration->webRegistration(), toWebPushSubscriptionOptions(options), new PushSubscriptionCallbacks(resolver, m_registration));
     }
 
     return promise;
@@ -114,7 +81,7 @@
     return promise;
 }
 
-ScriptPromise PushManager::permissionState(ScriptState* scriptState, const PushSubscriptionOptions& options, ExceptionState& exceptionState)
+ScriptPromise PushManager::permissionState(ScriptState* scriptState, const PushSubscriptionOptions& options)
 {
     if (scriptState->executionContext()->isDocument()) {
         Document* document = toDocument(scriptState->executionContext());
@@ -125,7 +92,7 @@
     ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
     ScriptPromise promise = resolver->promise();
 
-    pushProvider()->getPermissionStatus(m_registration->webRegistration(), toWebPushSubscriptionOptions(options, exceptionState), new PushPermissionStatusCallbacks(resolver));
+    pushProvider()->getPermissionStatus(m_registration->webRegistration(), toWebPushSubscriptionOptions(options), new PushPermissionStatusCallbacks(resolver));
     return promise;
 }
 
diff --git a/third_party/WebKit/Source/modules/push_messaging/PushManager.h b/third_party/WebKit/Source/modules/push_messaging/PushManager.h
index a4c07292..d6d9cfd 100644
--- a/third_party/WebKit/Source/modules/push_messaging/PushManager.h
+++ b/third_party/WebKit/Source/modules/push_messaging/PushManager.h
@@ -6,20 +6,16 @@
 #define PushManager_h
 
 #include "bindings/core/v8/ScriptWrappable.h"
-#include "bindings/modules/v8/UnionTypesModules.h"
-#include "modules/ModulesExport.h"
 #include "platform/heap/Handle.h"
 
 namespace blink {
 
-class ExceptionState;
 class PushSubscriptionOptions;
 class ScriptPromise;
 class ScriptState;
 class ServiceWorkerRegistration;
-struct WebPushSubscriptionOptions;
 
-class MODULES_EXPORT PushManager final : public GarbageCollected<PushManager>, public ScriptWrappable {
+class PushManager final : public GarbageCollected<PushManager>, public ScriptWrappable {
     DEFINE_WRAPPERTYPEINFO();
 public:
     static PushManager* create(ServiceWorkerRegistration* registration)
@@ -27,17 +23,12 @@
         return new PushManager(registration);
     }
 
-    ScriptPromise subscribe(ScriptState*, const PushSubscriptionOptions&,
-        ExceptionState&);
+    ScriptPromise subscribe(ScriptState*, const PushSubscriptionOptions&);
     ScriptPromise getSubscription(ScriptState*);
-    ScriptPromise permissionState(ScriptState*, const PushSubscriptionOptions&,
-        ExceptionState&);
+    ScriptPromise permissionState(ScriptState*, const PushSubscriptionOptions&);
 
     DECLARE_TRACE();
 
-    static WebPushSubscriptionOptions toWebPushSubscriptionOptions(
-        const PushSubscriptionOptions&, ExceptionState&);
-
 private:
     explicit PushManager(ServiceWorkerRegistration*);
 
diff --git a/third_party/WebKit/Source/modules/push_messaging/PushManager.idl b/third_party/WebKit/Source/modules/push_messaging/PushManager.idl
index 0c4ff864..ddb6139 100644
--- a/third_party/WebKit/Source/modules/push_messaging/PushManager.idl
+++ b/third_party/WebKit/Source/modules/push_messaging/PushManager.idl
@@ -9,7 +9,7 @@
     GarbageCollected,
     RuntimeEnabled=PushMessaging,
 ] interface PushManager {
-    [CallWith=ScriptState, RaisesException] Promise<PushSubscription> subscribe(optional PushSubscriptionOptions options);
+    [CallWith=ScriptState] Promise<PushSubscription> subscribe(optional PushSubscriptionOptions options);
     [CallWith=ScriptState] Promise<PushSubscription?> getSubscription();
-    [CallWith=ScriptState, RaisesException] Promise permissionState(optional PushSubscriptionOptions options);
+    [CallWith=ScriptState] Promise permissionState(optional PushSubscriptionOptions options);
 };
diff --git a/third_party/WebKit/Source/modules/push_messaging/PushManagerTest.cpp b/third_party/WebKit/Source/modules/push_messaging/PushManagerTest.cpp
deleted file mode 100644
index e5e7f8f..0000000
--- a/third_party/WebKit/Source/modules/push_messaging/PushManagerTest.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "modules/push_messaging/PushManager.h"
-
-#include "bindings/modules/v8/UnionTypesModules.h"
-#include "core/dom/DOMArrayBuffer.h"
-#include "modules/push_messaging/PushSubscriptionOptions.h"
-#include "public/platform/WebString.h"
-#include "public/platform/modules/push_messaging/WebPushSubscriptionOptions.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace blink {
-namespace {
-
-const char kValidKeyMarker = 0x04;
-const unsigned kValidKeyLength = 65;
-
-TEST(PushManagerTest, ValidSenderKey)
-{
-    uint8_t senderKey[kValidKeyLength];
-    memset(senderKey, 0, sizeof(senderKey));
-    senderKey[0] = kValidKeyMarker;
-    PushSubscriptionOptions options;
-    options.setApplicationServerKey(
-        ArrayBufferOrArrayBufferView::fromArrayBuffer(
-            DOMArrayBuffer::create(senderKey, kValidKeyLength)));
-
-    TrackExceptionState exceptionState;
-    WebPushSubscriptionOptions output = PushManager::toWebPushSubscriptionOptions(options, exceptionState);
-    EXPECT_FALSE(exceptionState.hadException());
-    EXPECT_EQ(output.applicationServerKey.length(), kValidKeyLength);
-    EXPECT_EQ(output.applicationServerKey, WebString::fromUTF8(reinterpret_cast<const char*>(senderKey), kValidKeyLength));
-}
-
-TEST(PushManagerTest, InvalidSenderKeyMarker)
-{
-    uint8_t senderKey[kValidKeyLength];
-    memset(senderKey, 0, sizeof(senderKey));
-    senderKey[0] = 0x05;
-    PushSubscriptionOptions options;
-    options.setApplicationServerKey(
-        ArrayBufferOrArrayBufferView::fromArrayBuffer(
-            DOMArrayBuffer::create(senderKey, kValidKeyLength)));
-
-    TrackExceptionState exceptionState;
-    WebPushSubscriptionOptions output = PushManager::toWebPushSubscriptionOptions(options, exceptionState);
-    EXPECT_TRUE(exceptionState.hadException());
-}
-
-TEST(PushManagerTest, InvalidSenderKeyLength)
-{
-    uint8_t senderKey[kValidKeyLength - 1];
-    memset(senderKey, 0, sizeof(senderKey));
-    senderKey[0] = kValidKeyMarker;
-    PushSubscriptionOptions options;
-    options.setApplicationServerKey(
-        ArrayBufferOrArrayBufferView::fromArrayBuffer(
-            DOMArrayBuffer::create(senderKey, kValidKeyLength - 1)));
-
-    TrackExceptionState exceptionState;
-    WebPushSubscriptionOptions output = PushManager::toWebPushSubscriptionOptions(options, exceptionState);
-    EXPECT_TRUE(exceptionState.hadException());
-}
-
-} // namespace
-} // namespace blink
diff --git a/third_party/WebKit/Source/modules/push_messaging/PushSubscriptionOptions.idl b/third_party/WebKit/Source/modules/push_messaging/PushSubscriptionOptions.idl
index 48af6cc..f034242 100644
--- a/third_party/WebKit/Source/modules/push_messaging/PushSubscriptionOptions.idl
+++ b/third_party/WebKit/Source/modules/push_messaging/PushSubscriptionOptions.idl
@@ -6,5 +6,4 @@
 
 dictionary PushSubscriptionOptions {
     boolean userVisibleOnly = false;
-    [RuntimeEnabled=PushSubscriptionRestrictions] BufferSource applicationServerKey;
 };
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainerTest.cpp b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainerTest.cpp
index cb4e2da8..8c0af13 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainerTest.cpp
+++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainerTest.cpp
@@ -92,7 +92,7 @@
 {
     StubScriptFunction resolved, rejected;
     promise.then(resolved.function(scriptState), rejected.function(scriptState));
-    v8::MicrotasksScope::PerformCheckpoint(promise.isolate());
+    promise.isolate()->RunMicrotasks();
     EXPECT_EQ(0ul, resolved.callCount());
     EXPECT_EQ(1ul, rejected.callCount());
     if (rejected.callCount())
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
index bd06d46..8a0bcf0 100644
--- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
+++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
@@ -151,7 +151,6 @@
 PromiseRejectionEvent status=stable
 PushMessaging status=stable
 PushMessagingData status=stable
-PushSubscriptionRestrictions status=experimental
 QuotaPromise status=experimental
 ReducedReferrerGranularity
 RenderingPipelineThrottling status=experimental
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzFace.cpp b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzFace.cpp
index 48e587b..39c0c02 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzFace.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzFace.cpp
@@ -45,6 +45,7 @@
 #include "platform/fonts/SimpleFontData.h"
 #include "platform/fonts/shaping/HarfBuzzShaper.h"
 #include "wtf/HashMap.h"
+#include "wtf/MathExtras.h"
 
 namespace blink {
 
@@ -138,7 +139,9 @@
 
 static hb_position_t SkiaScalarToHarfBuzzPosition(SkScalar value)
 {
-    return SkScalarToFixed(value);
+    // We treat HarfBuzz hb_position_t as 16.16 fixed-point.
+    static const int kHbPosition1 = 1 << 16;
+    return clampTo<int>(value * kHbPosition1);
 }
 
 static void SkiaGetGlyphWidthAndExtents(SkPaint* paint, hb_codepoint_t codepoint, hb_position_t* width, hb_glyph_extents_t* extents)
diff --git a/third_party/WebKit/Source/platform/heap/Heap.cpp b/third_party/WebKit/Source/platform/heap/Heap.cpp
index 69cbac7..5a67eb1 100644
--- a/third_party/WebKit/Source/platform/heap/Heap.cpp
+++ b/third_party/WebKit/Source/platform/heap/Heap.cpp
@@ -126,6 +126,7 @@
     s_partitionAllocSizeAtLastGC = WTF::Partitions::totalSizeOfCommittedPages();
     s_estimatedMarkingTimePerByte = 0.0;
     s_isLowEndDevice = base::SysInfo::IsLowEndDevice();
+    s_lastGCReason = BlinkGC::NumberOfGCReason;
 #if ENABLE(ASSERT)
     s_gcGeneration = 1;
 #endif
@@ -138,19 +139,14 @@
 
 void Heap::shutdown()
 {
+    ASSERT(s_markingStack);
+
     if (Platform::current() && Platform::current()->currentThread())
         Platform::current()->unregisterMemoryDumpProvider(BlinkGCMemoryDumpProvider::instance());
-    s_shutdownCalled = true;
-    ThreadState::shutdownHeapIfNecessary();
-}
 
-void Heap::doShutdown()
-{
-    // We don't want to call doShutdown() twice.
-    if (!s_markingStack)
-        return;
+    // The main thread must be the last thread that gets detached.
+    RELEASE_ASSERT(ThreadState::attachedThreads().size() == 0);
 
-    ASSERT(!ThreadState::attachedThreads().size());
     delete s_heapDoesNotContainCache;
     s_heapDoesNotContainCache = nullptr;
     delete s_freePagePool;
@@ -425,6 +421,8 @@
     DEFINE_THREAD_SAFE_STATIC_LOCAL(EnumerationHistogram, gcReasonHistogram, new EnumerationHistogram("BlinkGC.GCReason", BlinkGC::NumberOfGCReason));
     gcReasonHistogram.count(reason);
 
+    s_lastGCReason = reason;
+
     Heap::reportMemoryUsageHistogram();
     WTF::Partitions::reportMemoryUsageHistogram();
 
@@ -690,6 +688,7 @@
 size_t Heap::s_partitionAllocSizeAtLastGC = 0;
 double Heap::s_estimatedMarkingTimePerByte = 0.0;
 bool Heap::s_isLowEndDevice = false;
+BlinkGC::GCReason Heap::s_lastGCReason = BlinkGC::NumberOfGCReason;
 #if ENABLE(ASSERT)
 uint16_t Heap::s_gcGeneration = 0;
 #endif
diff --git a/third_party/WebKit/Source/platform/heap/Heap.h b/third_party/WebKit/Source/platform/heap/Heap.h
index a2081bd..95fac29 100644
--- a/third_party/WebKit/Source/platform/heap/Heap.h
+++ b/third_party/WebKit/Source/platform/heap/Heap.h
@@ -108,7 +108,6 @@
 public:
     static void init();
     static void shutdown();
-    static void doShutdown();
 
     static CrossThreadPersistentRegion& crossThreadPersistentRegion();
 
@@ -296,6 +295,7 @@
     static void reportMemoryUsageHistogram();
     static void reportMemoryUsageForTracing();
     static bool isLowEndDevice() { return s_isLowEndDevice; }
+    static BlinkGC::GCReason lastGCReason() { return s_lastGCReason; }
 
 #if ENABLE(ASSERT)
     static uint16_t gcGeneration() { return s_gcGeneration; }
@@ -330,6 +330,7 @@
     static size_t s_partitionAllocSizeAtLastGC;
     static double s_estimatedMarkingTimePerByte;
     static bool s_isLowEndDevice;
+    static BlinkGC::GCReason s_lastGCReason;
 #if ENABLE(ASSERT)
     static uint16_t s_gcGeneration;
 #endif
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.cpp b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
index 01ed8598..8446223 100644
--- a/third_party/WebKit/Source/platform/heap/ThreadState.cpp
+++ b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
@@ -235,19 +235,6 @@
         attachedThreads().remove(state);
         state->~ThreadState();
     }
-    shutdownHeapIfNecessary();
-}
-
-void ThreadState::shutdownHeapIfNecessary()
-{
-    // We don't need to enter a safe point before acquiring threadAttachMutex
-    // because this thread is already detached.
-
-    MutexLocker locker(threadAttachMutex());
-    // We start shutting down the heap if there is no running thread
-    // and Heap::shutdown() is already called.
-    if (!attachedThreads().size() && Heap::s_shutdownCalled)
-        Heap::doShutdown();
 }
 
 void ThreadState::attach()
@@ -323,7 +310,6 @@
     state->cleanup();
     RELEASE_ASSERT(state->gcState() == ThreadState::NoGCScheduled);
     delete state;
-    shutdownHeapIfNecessary();
 }
 
 void ThreadState::visitPersistentRoots(Visitor* visitor)
@@ -1148,6 +1134,26 @@
         collectionRateHistogram.count(static_cast<int>(100 * collectionRate));
         DEFINE_STATIC_LOCAL(CustomCountHistogram, timeForSweepHistogram, ("BlinkGC.TimeForSweepingAllObjects", 1, 10 * 1000, 50));
         timeForSweepHistogram.count(m_accumulatedSweepingTime);
+
+
+#define COUNT_COLLECTION_RATE_HISTOGRAM_BY_GC_REASON(GCReason)                \
+    case BlinkGC::GCReason: {                                                 \
+        DEFINE_STATIC_LOCAL(CustomCountHistogram, histogram,                  \
+            ("BlinkGC.CollectionRate_" #GCReason, 1, 100, 20));             \
+        histogram.count(static_cast<int>(100 * collectionRate));              \
+        break;                                                                \
+    }
+
+        switch (Heap::lastGCReason()) {
+            COUNT_COLLECTION_RATE_HISTOGRAM_BY_GC_REASON(IdleGC)
+            COUNT_COLLECTION_RATE_HISTOGRAM_BY_GC_REASON(PreciseGC)
+            COUNT_COLLECTION_RATE_HISTOGRAM_BY_GC_REASON(ConservativeGC)
+            COUNT_COLLECTION_RATE_HISTOGRAM_BY_GC_REASON(ForcedGC)
+            COUNT_COLLECTION_RATE_HISTOGRAM_BY_GC_REASON(MemoryPressureGC)
+            COUNT_COLLECTION_RATE_HISTOGRAM_BY_GC_REASON(PageNavigationGC)
+        default:
+            break;
+        }
     }
 
     switch (gcState()) {
@@ -1340,18 +1346,6 @@
     }
 }
 
-void ThreadState::removeInterruptor(BlinkGCInterruptor* interruptor)
-{
-    ASSERT(checkThread());
-    SafePointScope scope(BlinkGC::HeapPointersOnStack);
-    {
-        MutexLocker locker(threadAttachMutex());
-        size_t index = m_interruptors.find(interruptor);
-        RELEASE_ASSERT(index != kNotFound);
-        m_interruptors.remove(index);
-    }
-}
-
 #if defined(LEAK_SANITIZER)
 void ThreadState::registerStaticPersistentNode(PersistentNode* node)
 {
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.h b/third_party/WebKit/Source/platform/heap/ThreadState.h
index 3337384..ed066d6 100644
--- a/third_party/WebKit/Source/platform/heap/ThreadState.h
+++ b/third_party/WebKit/Source/platform/heap/ThreadState.h
@@ -186,7 +186,6 @@
     // thread.
     static void init();
     static void shutdown();
-    static void shutdownHeapIfNecessary();
     bool isTerminating() { return m_isTerminating; }
 
     static void attachMainThread();
@@ -343,7 +342,6 @@
     bool isAtSafePoint() const { return m_atSafePoint; }
 
     void addInterruptor(PassOwnPtr<BlinkGCInterruptor>);
-    void removeInterruptor(BlinkGCInterruptor*);
 
     void recordStackEnd(intptr_t* endOfStack)
     {
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8StringUtil.cpp b/third_party/WebKit/Source/platform/v8_inspector/V8StringUtil.cpp
index 58003b0..474708a 100644
--- a/third_party/WebKit/Source/platform/v8_inspector/V8StringUtil.cpp
+++ b/third_party/WebKit/Source/platform/v8_inspector/V8StringUtil.cpp
@@ -153,12 +153,20 @@
 
 v8::Local<v8::String> toV8String(v8::Isolate* isolate, const String& string)
 {
-    return v8::String::NewFromUtf8(isolate, string.utf8().data(), v8::NewStringType::kNormal).ToLocalChecked();
+    if (string.isNull())
+        return v8::String::Empty(isolate);
+    if (string.is8Bit())
+        return v8::String::NewFromOneByte(isolate, string.characters8(), v8::NewStringType::kNormal, string.length()).ToLocalChecked();
+    return v8::String::NewFromTwoByte(isolate, reinterpret_cast<const uint16_t*>(string.characters16()), v8::NewStringType::kNormal, string.length()).ToLocalChecked();
 }
 
 v8::Local<v8::String> toV8StringInternalized(v8::Isolate* isolate, const String& string)
 {
-    return v8::String::NewFromUtf8(isolate, string.utf8().data(), v8::NewStringType::kInternalized).ToLocalChecked();
+    if (string.isNull())
+        return v8::String::Empty(isolate);
+    if (string.is8Bit())
+        return v8::String::NewFromOneByte(isolate, string.characters8(), v8::NewStringType::kInternalized, string.length()).ToLocalChecked();
+    return v8::String::NewFromTwoByte(isolate, reinterpret_cast<const uint16_t*>(string.characters16()), v8::NewStringType::kInternalized, string.length()).ToLocalChecked();
 }
 
 String toWTFString(v8::Local<v8::String> value)
diff --git a/third_party/WebKit/Source/web/WebKit.cpp b/third_party/WebKit/Source/web/WebKit.cpp
index 0b34d329..3fa474fa 100644
--- a/third_party/WebKit/Source/web/WebKit.cpp
+++ b/third_party/WebKit/Source/web/WebKit.cpp
@@ -92,11 +92,20 @@
 // Doing so may cause hard to reproduce crashes.
 static bool s_webKitInitialized = false;
 
+static ModulesInitializer& modulesInitializer()
+{
+    DEFINE_STATIC_LOCAL(OwnPtr<ModulesInitializer>, initializer, (adoptPtr(new ModulesInitializer)));
+    return *initializer;
+}
+
 void initialize(Platform* platform)
 {
     initializeWithoutV8(platform);
 
-    V8Initializer::initializeMainThreadIfNeeded();
+    modulesInitializer().init();
+    setIndexedDBClientCreateFunction(IndexedDBClientImpl::create);
+
+    V8Initializer::initializeMainThread();
 
     OwnPtr<V8IsolateInterruptor> interruptor = adoptPtr(new V8IsolateInterruptor(V8PerIsolateData::mainThreadIsolate()));
     ThreadState::current()->addInterruptor(interruptor.release());
@@ -141,12 +150,6 @@
     v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(size);
 }
 
-static ModulesInitializer& modulesInitializer()
-{
-    DEFINE_STATIC_LOCAL(OwnPtr<ModulesInitializer>, initializer, (adoptPtr(new ModulesInitializer)));
-    return *initializer;
-}
-
 void initializeWithoutV8(Platform* platform)
 {
     ASSERT(!s_webKitInitialized);
@@ -166,10 +169,6 @@
         ASSERT(!s_gcTaskRunner);
         s_gcTaskRunner = new GCTaskRunner(currentThread);
     }
-
-    modulesInitializer().init();
-
-    setIndexedDBClientCreateFunction(IndexedDBClientImpl::create);
 }
 
 void shutdown()
@@ -207,10 +206,9 @@
 
     ThreadState::current()->unregisterTraceDOMWrappers();
 
-    v8::Isolate* isolate = V8PerIsolateData::mainThreadIsolate();
-    V8PerIsolateData::willBeDestroyed(isolate);
+    V8Initializer::shutdownMainThread();
 
-    V8PerIsolateData::destroy(isolate);
+    modulesInitializer().shutdown();
 
     shutdownWithoutV8();
 }
@@ -218,8 +216,6 @@
 void shutdownWithoutV8()
 {
     ASSERT(isMainThread());
-    modulesInitializer().shutdown();
-
     // currentThread() is null if we are running on a thread without a message loop.
     if (Platform::current()->currentThread()) {
         ASSERT(s_gcTaskRunner);
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
index 78c617d0..b9822d6 100644
--- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -310,6 +310,14 @@
     }
 }
 
+// Flakily failing on Mac ASAN.
+// https://crbug.com/592771
+#if OS(MACOSX) && defined(ADDRESS_SANITIZER)
+#define MAYBE(test) DISABLED_##test
+#else
+#define MAYBE(test) test
+#endif
+
 INSTANTIATE_TEST_CASE_P(All, ParameterizedWebFrameTest, ::testing::Values(
     ParameterizedWebFrameTestConfig::Default,
     ParameterizedWebFrameTestConfig::RootLayerScrolls));
@@ -325,7 +333,6 @@
     webViewHelper.initializeAndLoad(m_baseURL + "iframes_test.html");
 
     // Now retrieve the frames text and test it only includes visible elements.
-    webViewHelper.webView()->updateAllLifecyclePhases();
     std::string content = WebFrameContentDumper::dumpFrameTreeAsText(webViewHelper.webView()->mainFrame()->toWebLocalFrame(), 1024).utf8();
     EXPECT_NE(std::string::npos, content.find(" visible paragraph"));
     EXPECT_NE(std::string::npos, content.find(" visible iframe"));
@@ -499,8 +506,6 @@
 
     FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:document.body.textContent = location.href; void 0;");
 
-    webViewHelper.webView()->updateAllLifecyclePhases();
-
     std::string content = WebFrameContentDumper::dumpFrameTreeAsText(webViewHelper.webView()->mainFrame()->toWebLocalFrame(), 1024).utf8();
     EXPECT_EQ("http://internal.test:0/" + fileName, content);
 }
@@ -520,8 +525,6 @@
 
     FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:document.body.textContent = location.href; void 0;");
 
-    webViewHelper.webView()->updateAllLifecyclePhases();
-
     std::string content = WebFrameContentDumper::dumpFrameTreeAsText(webViewHelper.webView()->mainFrame()->toWebLocalFrame(), 1024).utf8();
     EXPECT_EQ("http://internal.test:0/" + fileName, content);
 }
@@ -1040,7 +1043,7 @@
     EXPECT_EQ(1, webViewHelper.webView()->pageScaleFactor());
 
     // Force the layout to happen before leaving the test.
-    webViewHelper.webView()->updateAllLifecyclePhases();
+    WebFrameContentDumper::dumpFrameTreeAsText(webViewHelper.webView()->mainFrame()->toWebLocalFrame(), 1024).utf8();
 }
 
 TEST_P(ParameterizedWebFrameTest, FixedLayoutInitializeAtMinimumScale)
@@ -1383,7 +1386,7 @@
     EXPECT_EQ(enforcedPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
 }
 
-TEST_P(ParameterizedWebFrameTest, SmallPermanentInitialPageScaleFactorIsClobbered)
+TEST_P(ParameterizedWebFrameTest, MAYBE(SmallPermanentInitialPageScaleFactorIsClobbered))
 {
     const char* pages[] = {
         // These pages trigger the clobbering condition. There must be a matching item in "pageScaleFactors" array.
@@ -1635,7 +1638,7 @@
 }
 
 
-TEST_P(ParameterizedWebFrameTest, SetForceZeroLayoutHeightWorksAcrossNavigations)
+TEST_P(ParameterizedWebFrameTest, MAYBE(SetForceZeroLayoutHeightWorksAcrossNavigations))
 {
     registerMockedHttpURLLoad("200-by-300.html");
     registerMockedHttpURLLoad("large-div.html");
@@ -1677,7 +1680,7 @@
     EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
 }
 
-TEST_P(ParameterizedWebFrameTest, WideViewportAndWideContentWithInitialScale)
+TEST_P(ParameterizedWebFrameTest, MAYBE(WideViewportAndWideContentWithInitialScale))
 {
     registerMockedHttpURLLoad("wide_document_width_viewport.html");
     registerMockedHttpURLLoad("white-1x1.png");
@@ -1703,7 +1706,7 @@
     EXPECT_EQ(minimumPageScaleFactor, webViewHelper.webViewImpl()->minimumPageScaleFactor());
 }
 
-TEST_P(ParameterizedWebFrameTest, WideViewportQuirkClobbersHeight)
+TEST_P(ParameterizedWebFrameTest, MAYBE(WideViewportQuirkClobbersHeight))
 {
     registerMockedHttpURLLoad("viewport-height-1000.html");
 
@@ -1726,7 +1729,7 @@
     EXPECT_EQ(1, webViewHelper.webView()->pageScaleFactor());
 }
 
-TEST_P(ParameterizedWebFrameTest, LayoutSize320Quirk)
+TEST_P(ParameterizedWebFrameTest, MAYBE(LayoutSize320Quirk))
 {
     registerMockedHttpURLLoad("viewport/viewport-30.html");
 
@@ -2025,7 +2028,7 @@
     EXPECT_EQ(980, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().width());
 }
 
-TEST_P(ParameterizedWebFrameTest, targetDensityDpiHigh)
+TEST_P(ParameterizedWebFrameTest, MAYBE(targetDensityDpiHigh))
 {
     registerMockedHttpURLLoad("viewport-target-densitydpi-high.html");
 
@@ -2056,7 +2059,7 @@
     }
 }
 
-TEST_P(ParameterizedWebFrameTest, targetDensityDpiDevice)
+TEST_P(ParameterizedWebFrameTest, MAYBE(targetDensityDpiDevice))
 {
     registerMockedHttpURLLoad("viewport-target-densitydpi-device.html");
 
@@ -2081,7 +2084,7 @@
     }
 }
 
-TEST_P(ParameterizedWebFrameTest, targetDensityDpiDeviceAndFixedWidth)
+TEST_P(ParameterizedWebFrameTest, MAYBE(targetDensityDpiDeviceAndFixedWidth))
 {
     registerMockedHttpURLLoad("viewport-target-densitydpi-device-and-fixed-width.html");
 
@@ -2887,7 +2890,7 @@
     EXPECT_RECT_EQ(rectRightBottom, blockBound);
 }
 
-TEST_P(ParameterizedWebFrameTest, DivMultipleTargetZoomMultipleDivsTest)
+TEST_P(ParameterizedWebFrameTest, MAYBE(DivMultipleTargetZoomMultipleDivsTest))
 {
     registerMockedHttpURLLoad("get_multiple_divs_for_auto_zoom_test.html");
 
@@ -3163,7 +3166,7 @@
     EXPECT_FALSE(needAnimation);
 }
 
-TEST_P(ParameterizedWebFrameTest, CharacterIndexAtPointWithPinchZoom)
+TEST_P(ParameterizedWebFrameTest, MAYBE(CharacterIndexAtPointWithPinchZoom))
 {
     registerMockedHttpURLLoad("sometext.html");
 
@@ -3614,7 +3617,6 @@
 
     // Make sure it comes out OK.
     const std::string expected("Foo bar\nbaz");
-    webViewHelper.webView()->updateAllLifecyclePhases();
     WebString text = WebFrameContentDumper::dumpFrameTreeAsText(frame->toWebLocalFrame(), std::numeric_limits<size_t>::max());
     EXPECT_EQ(expected, text.utf8());
 
@@ -3632,7 +3634,6 @@
     ASSERT_TRUE(subframe);
     FrameTestHelpers::loadHTMLString(subframe, "sub<p>text", testURL);
 
-    webViewHelper.webView()->updateAllLifecyclePhases();
     text = WebFrameContentDumper::dumpFrameTreeAsText(frame->toWebLocalFrame(), std::numeric_limits<size_t>::max());
     EXPECT_EQ("Hello world\n\nsub\ntext", text.utf8());
 
@@ -3653,8 +3654,6 @@
     KURL testURL = toKURL("about:blank");
     FrameTestHelpers::loadHTMLString(frame, simpleSource, testURL);
 
-    webViewHelper.webView()->updateAllLifecyclePhases();
-
     WebString text = WebFrameContentDumper::dumpFrameTreeAsText(frame->toWebLocalFrame(), std::numeric_limits<size_t>::max());
     EXPECT_EQ("Hello\n\nWorld", text.utf8());
 
@@ -3665,8 +3664,6 @@
 
     EXPECT_EQ(html, WebFrameContentDumper::dumpAsMarkup(frame->toWebLocalFrame()).utf8());
 
-    webViewHelper.webView()->updateAllLifecyclePhases();
-
     text = WebFrameContentDumper::dumpFrameTreeAsText(frame->toWebLocalFrame(), std::numeric_limits<size_t>::max());
     EXPECT_EQ("Hello\n\nWorld", text.utf8());
 
@@ -4418,7 +4415,7 @@
     // EXPECT_EQ("Editable 1. Editable 2. ]", selectionAsString(frame));
 }
 
-TEST_P(ParameterizedWebFrameTest, MoveRangeSelectionExtent)
+TEST_P(ParameterizedWebFrameTest, MAYBE(MoveRangeSelectionExtent))
 {
     WebLocalFrameImpl* frame;
     WebRect startWebRect;
@@ -4452,7 +4449,7 @@
     EXPECT_EQ("", selectionAsString(frame));
 }
 
-TEST_P(ParameterizedWebFrameTest, MoveRangeSelectionExtentCannotCollapse)
+TEST_P(ParameterizedWebFrameTest, MAYBE(MoveRangeSelectionExtentCannotCollapse))
 {
     WebLocalFrameImpl* frame;
     WebRect startWebRect;
@@ -4477,7 +4474,7 @@
     EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
 }
 
-TEST_P(ParameterizedWebFrameTest, MoveRangeSelectionExtentScollsInputField)
+TEST_P(ParameterizedWebFrameTest, MAYBE(MoveRangeSelectionExtentScollsInputField))
 {
     WebLocalFrameImpl* frame;
     WebRect startWebRect;
@@ -4839,7 +4836,7 @@
     return event;
 }
 
-TEST_P(ParameterizedWebFrameTest, DisambiguationPopup)
+TEST_P(ParameterizedWebFrameTest, MAYBE(DisambiguationPopup))
 {
     const std::string htmlFile = "disambiguation_popup.html";
     registerMockedHttpURLLoad(htmlFile);
@@ -4893,7 +4890,7 @@
     }
 }
 
-TEST_P(ParameterizedWebFrameTest, DisambiguationPopupNoContainer)
+TEST_P(ParameterizedWebFrameTest, MAYBE(DisambiguationPopupNoContainer))
 {
     registerMockedHttpURLLoad("disambiguation_popup_no_container.html");
 
@@ -4910,7 +4907,7 @@
     EXPECT_FALSE(client.triggered());
 }
 
-TEST_P(ParameterizedWebFrameTest, DisambiguationPopupMobileSite)
+TEST_P(ParameterizedWebFrameTest, MAYBE(DisambiguationPopupMobileSite))
 {
     const std::string htmlFile = "disambiguation_popup_mobile_site.html";
     registerMockedHttpURLLoad(htmlFile);
@@ -4944,7 +4941,7 @@
     }
 }
 
-TEST_P(ParameterizedWebFrameTest, DisambiguationPopupViewportSite)
+TEST_P(ParameterizedWebFrameTest, MAYBE(DisambiguationPopupViewportSite))
 {
     const std::string htmlFile = "disambiguation_popup_viewport_site.html";
     registerMockedHttpURLLoad(htmlFile);
@@ -5028,7 +5025,7 @@
     EXPECT_FALSE(client.triggered());
 }
 
-TEST_P(ParameterizedWebFrameTest, DisambiguationPopupBlacklist)
+TEST_P(ParameterizedWebFrameTest, MAYBE(DisambiguationPopupBlacklist))
 {
     const unsigned viewportWidth = 500;
     const unsigned viewportHeight = 1000;
@@ -5060,7 +5057,7 @@
     EXPECT_FALSE(client.triggered());
 }
 
-TEST_P(ParameterizedWebFrameTest, DisambiguationPopupPageScale)
+TEST_P(ParameterizedWebFrameTest, MAYBE(DisambiguationPopupPageScale))
 {
     registerMockedHttpURLLoad("disambiguation_popup_page_scale.html");
 
@@ -5143,8 +5140,6 @@
     Platform::current()->unitTestSupport()->registerMockedErrorURL(URLTestHelpers::toKURL(errorURL), response, error);
     FrameTestHelpers::loadHistoryItem(frame, errorHistoryItem, WebHistoryDifferentDocumentLoad, WebURLRequest::UseProtocolCachePolicy);
 
-    webViewHelper.webView()->updateAllLifecyclePhases();
-
     WebString text = WebFrameContentDumper::dumpFrameTreeAsText(frame->toWebLocalFrame(), std::numeric_limits<size_t>::max());
     EXPECT_EQ("This should appear", text.utf8());
     EXPECT_TRUE(webFrameClient.commitCalled());
@@ -5258,8 +5253,6 @@
     EXPECT_EQ(1U, document->markers().markersInRange(selectionRange, DocumentMarker::Spelling).size());
 
     frame->replaceMisspelledRange("welcome");
-
-    webViewHelper.webView()->updateAllLifecyclePhases();
     EXPECT_EQ("_welcome_.", WebFrameContentDumper::dumpFrameTreeAsText(frame, std::numeric_limits<size_t>::max()).utf8());
 }
 
@@ -6421,7 +6414,7 @@
     EXPECT_EQ(500, leftRightFixed->offsetWidth());
 }
 
-TEST_P(ParameterizedWebFrameTest, FrameViewMoveWithSetFrameRect)
+TEST_P(ParameterizedWebFrameTest, MAYBE(FrameViewMoveWithSetFrameRect))
 {
     FrameTestHelpers::WebViewHelper webViewHelper(this);
     webViewHelper.initializeAndLoad("about:blank");
@@ -6624,7 +6617,7 @@
     ASSERT_TRUE(webScrollLayer->userScrollableVertical());
 }
 
-TEST_P(ParameterizedWebFrameTest, FullscreenSubframe)
+TEST_P(ParameterizedWebFrameTest, MAYBE(FullscreenSubframe))
 {
     FakeCompositingWebViewClient client;
     registerMockedHttpURLLoad("fullscreen_iframe.html");
@@ -6745,7 +6738,7 @@
     EXPECT_FLOAT_EQ(5.0, webViewImpl->maximumPageScaleFactor());
 }
 
-TEST_P(ParameterizedWebFrameTest, LayoutBlockPercentHeightDescendants)
+TEST_P(ParameterizedWebFrameTest, MAYBE(LayoutBlockPercentHeightDescendants))
 {
     registerMockedHttpURLLoad("percent-height-descendants.html");
     FrameTestHelpers::WebViewHelper webViewHelper(this);
@@ -7079,7 +7072,6 @@
     // Finally, make sure an embedder triggered load in the local frame swapped
     // back in works.
     FrameTestHelpers::loadFrame(localFrame, m_baseURL + "subframe-hello.html");
-
     std::string content = WebFrameContentDumper::dumpFrameTreeAsText(localFrame, 1024).utf8();
     EXPECT_EQ("hello", content);
 
diff --git a/third_party/WebKit/Source/web/tests/WebViewTest.cpp b/third_party/WebKit/Source/web/tests/WebViewTest.cpp
index 974b3ce0..cd9d0ce6 100644
--- a/third_party/WebKit/Source/web/tests/WebViewTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebViewTest.cpp
@@ -2210,12 +2210,10 @@
     URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("display_mode.html"));
     WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "display_mode.html", true);
 
-    webView->updateAllLifecyclePhases();
     std::string content = WebFrameContentDumper::dumpFrameTreeAsText(webView->mainFrame()->toWebLocalFrame(), 21).utf8();
     EXPECT_EQ("regular-ui", content);
 
     webView->setDisplayMode(WebDisplayModeMinimalUi);
-    webView->updateAllLifecyclePhases();
     content = WebFrameContentDumper::dumpFrameTreeAsText(webView->mainFrame()->toWebLocalFrame(), 21).utf8();
     EXPECT_EQ("minimal-ui", content);
     m_webViewHelper.reset();
@@ -2687,7 +2685,6 @@
     std::string actual = frame->selectionAsText().utf8();
 
     const int kMaxOutputCharacters = 1024;
-    webView->updateAllLifecyclePhases();
     std::string expected = WebFrameContentDumper::dumpFrameTreeAsText(frame, kMaxOutputCharacters).utf8();
     EXPECT_EQ(expected, actual);
 }
diff --git a/third_party/WebKit/Source/wtf/TypeTraits.h b/third_party/WebKit/Source/wtf/TypeTraits.h
index 002ec4f..d3ef548 100644
--- a/third_party/WebKit/Source/wtf/TypeTraits.h
+++ b/third_party/WebKit/Source/wtf/TypeTraits.h
@@ -64,7 +64,8 @@
     static const bool value = __has_trivial_destructor(T);
 };
 
-template <typename T, typename U> class IsSubclass {
+template <typename T, typename U> struct IsSubclass {
+private:
     typedef char YesType;
     struct NoType {
         char padding[8];
@@ -77,7 +78,8 @@
     static const bool value = sizeof(subclassCheck(t)) == sizeof(YesType);
 };
 
-template <typename T, template <typename... V> class U> class IsSubclassOfTemplate {
+template <typename T, template <typename... V> class U> struct IsSubclassOfTemplate {
+private:
     typedef char YesType;
     struct NoType {
         char padding[8];
@@ -91,7 +93,8 @@
 };
 
 template <typename T, template <typename V, size_t W> class U>
-class IsSubclassOfTemplateTypenameSize {
+struct IsSubclassOfTemplateTypenameSize {
+private:
     typedef char YesType;
     struct NoType {
         char padding[8];
@@ -105,7 +108,8 @@
 };
 
 template <typename T, template <typename V, size_t W, typename X> class U>
-class IsSubclassOfTemplateTypenameSizeTypename {
+struct IsSubclassOfTemplateTypenameSizeTypename {
+private:
     typedef char YesType;
     struct NoType {
         char padding[8];
@@ -137,13 +141,11 @@
 // Here, we use a template specialization for same type case to allow incomplete
 // types.
 
-template <typename T, typename U> class IsBaseOf {
-public:
+template <typename T, typename U> struct IsBaseOf {
     static const bool value = std::is_base_of<T, U>::value;
 };
 
-template <typename T> class IsBaseOf<T, T> {
-public:
+template <typename T> struct IsBaseOf<T, T> {
     static const bool value = true;
 };
 
diff --git a/third_party/WebKit/Source/wtf/TypeTraits.cpp b/third_party/WebKit/Source/wtf/TypeTraitsTest.cpp
similarity index 97%
rename from third_party/WebKit/Source/wtf/TypeTraits.cpp
rename to third_party/WebKit/Source/wtf/TypeTraitsTest.cpp
index 9b8c103..12fec33 100644
--- a/third_party/WebKit/Source/wtf/TypeTraits.cpp
+++ b/third_party/WebKit/Source/wtf/TypeTraitsTest.cpp
@@ -23,8 +23,12 @@
 
 #include "wtf/Noncopyable.h"
 
+// No gtest tests; only static_assert checks.
+
 namespace WTF {
 
+namespace {
+
 struct VirtualClass {
     virtual void A() { }
 };
@@ -99,4 +103,6 @@
 typedef int IntArray[];
 typedef int IntArraySized[4];
 
+} // anonymous namespace
+
 } // namespace WTF
diff --git a/third_party/WebKit/Source/wtf/wtf.gypi b/third_party/WebKit/Source/wtf/wtf.gypi
index 226db2c..eaf57275 100644
--- a/third_party/WebKit/Source/wtf/wtf.gypi
+++ b/third_party/WebKit/Source/wtf/wtf.gypi
@@ -117,7 +117,6 @@
             'ThreadingPthreads.cpp',
             'ThreadingWin.cpp',
             'TreeNode.h',
-            'TypeTraits.cpp',
             'TypeTraits.h',
             'TypedArrayBase.h',
             'Uint16Array.h',
@@ -221,6 +220,7 @@
             'StringHasherTest.cpp',
             'TemporaryChangeTest.cpp',
             'TreeNodeTest.cpp',
+            'TypeTraitsTest.cpp',
             'VectorTest.cpp',
             'dtoa_test.cpp',
             'testing/WTFTestPrintersTest.cpp',
diff --git a/third_party/WebKit/public/platform/WebMediaPlayer.h b/third_party/WebKit/public/platform/WebMediaPlayer.h
index aebc9980..68a8803 100644
--- a/third_party/WebKit/public/platform/WebMediaPlayer.h
+++ b/third_party/WebKit/public/platform/WebMediaPlayer.h
@@ -156,8 +156,8 @@
     virtual unsigned decodedFrameCount() const = 0;
     virtual unsigned droppedFrameCount() const = 0;
     virtual unsigned corruptedFrameCount() const { return 0; }
-    virtual unsigned audioDecodedByteCount() const = 0;
-    virtual unsigned videoDecodedByteCount() const = 0;
+    virtual size_t audioDecodedByteCount() const = 0;
+    virtual size_t videoDecodedByteCount() const = 0;
 
     virtual void paint(WebCanvas*, const WebRect&, unsigned char alpha, SkXfermode::Mode) = 0;
 
diff --git a/third_party/WebKit/public/platform/WebPrivatePtr.h b/third_party/WebKit/public/platform/WebPrivatePtr.h
index 4438864..047d32c 100644
--- a/third_party/WebKit/public/platform/WebPrivatePtr.h
+++ b/third_party/WebKit/public/platform/WebPrivatePtr.h
@@ -69,7 +69,8 @@
 };
 
 template<typename T>
-class LifetimeOf {
+struct LifetimeOf {
+private:
     static const bool isGarbageCollected = WTF::IsSubclassOfTemplate<T, GarbageCollected>::value || IsGarbageCollectedMixin<T>::value;
     static const bool isRefCountedGarbageCollected = WTF::IsSubclassOfTemplate<T, RefCountedGarbageCollected>::value;
 public:
diff --git a/third_party/WebKit/public/platform/modules/push_messaging/WebPushSubscriptionOptions.h b/third_party/WebKit/public/platform/modules/push_messaging/WebPushSubscriptionOptions.h
index ad3db17..bfac23a2 100644
--- a/third_party/WebKit/public/platform/modules/push_messaging/WebPushSubscriptionOptions.h
+++ b/third_party/WebKit/public/platform/modules/push_messaging/WebPushSubscriptionOptions.h
@@ -5,8 +5,6 @@
 #ifndef WebPushSubscriptionOptions_h
 #define WebPushSubscriptionOptions_h
 
-#include "public/platform/WebString.h"
-
 namespace blink {
 
 struct WebPushSubscriptionOptions {
@@ -18,10 +16,6 @@
     // Indicates that the subscription will only be used for push messages
     // that result in UI visible to the user.
     bool userVisibleOnly;
-
-    // P-256 public key, in uncompressed form, of the app server that can send
-    // push messages to this subscription.
-    WebString applicationServerKey;
 };
 
 } // namespace blink
diff --git a/third_party/blimp_fonts/.gitignore b/third_party/blimp_fonts/.gitignore
new file mode 100644
index 0000000..70994af4
--- /dev/null
+++ b/third_party/blimp_fonts/.gitignore
@@ -0,0 +1,2 @@
+*.otf
+*.ttf
diff --git a/third_party/blimp_fonts/AndroidClock.ttf.sha1 b/third_party/blimp_fonts/AndroidClock.ttf.sha1
new file mode 100644
index 0000000..ab7fba0
--- /dev/null
+++ b/third_party/blimp_fonts/AndroidClock.ttf.sha1
@@ -0,0 +1 @@
+c2a20ced561bb57426484d8de4136817b4edcdfb
\ No newline at end of file
diff --git a/third_party/blimp_fonts/AndroidClock_Highlight.ttf.sha1 b/third_party/blimp_fonts/AndroidClock_Highlight.ttf.sha1
new file mode 100644
index 0000000..4abd6d36
--- /dev/null
+++ b/third_party/blimp_fonts/AndroidClock_Highlight.ttf.sha1
@@ -0,0 +1 @@
+6a7bba11c859c6698addcab7052c257caa762774
\ No newline at end of file
diff --git a/third_party/blimp_fonts/AndroidClock_Solid.ttf.sha1 b/third_party/blimp_fonts/AndroidClock_Solid.ttf.sha1
new file mode 100644
index 0000000..4abd6d36
--- /dev/null
+++ b/third_party/blimp_fonts/AndroidClock_Solid.ttf.sha1
@@ -0,0 +1 @@
+6a7bba11c859c6698addcab7052c257caa762774
\ No newline at end of file
diff --git a/third_party/blimp_fonts/BUILD.gn b/third_party/blimp_fonts/BUILD.gn
new file mode 100644
index 0000000..0d3154f
--- /dev/null
+++ b/third_party/blimp_fonts/BUILD.gn
@@ -0,0 +1,217 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+copy("blimp_fonts") {
+  sources = [
+    "AndroidClock.ttf",
+    "AndroidClock_Highlight.ttf",
+    "AndroidClock_Solid.ttf",
+    "CarroisGothicSC-Regular.ttf",
+    "Clockopia.ttf",
+    "ComingSoon.ttf",
+    "CutiveMono.ttf",
+    "DancingScript-Bold.ttf",
+    "DancingScript-Regular.ttf",
+    "DroidSansFallback.ttf",
+    "DroidSansFallbackFull.ttf",
+    "DroidSansMono.ttf",
+    "LICENSE",
+    "LICENSE.Apache",
+    "LICENSE.OFL",
+    "MTLc3m.ttf",
+    "MTLmr3m.ttf",
+    "NanumGothic.ttf",
+    "NanumGothicBold.ttf",
+    "NotoColorEmoji.ttf",
+    "NotoKufiArabic-Bold.ttf",
+    "NotoKufiArabic-Regular.ttf",
+    "NotoNaskhArabic-Bold.ttf",
+    "NotoNaskhArabic-Regular.ttf",
+    "NotoNaskhArabicUI-Bold.ttf",
+    "NotoNaskhArabicUI-Regular.ttf",
+    "NotoSans-Bold.ttf",
+    "NotoSans-BoldItalic.ttf",
+    "NotoSans-Italic.ttf",
+    "NotoSans-Regular.ttf",
+    "NotoSansArmenian-Bold.ttf",
+    "NotoSansArmenian-Regular.ttf",
+    "NotoSansAvestan-Regular.ttf",
+    "NotoSansBalinese-Regular.ttf",
+    "NotoSansBamum-Regular.ttf",
+    "NotoSansBatak-Regular.ttf",
+    "NotoSansBengali-Bold.ttf",
+    "NotoSansBengali-Regular.ttf",
+    "NotoSansBengaliUI-Bold.ttf",
+    "NotoSansBengaliUI-Regular.ttf",
+    "NotoSansBrahmi-Regular.ttf",
+    "NotoSansBuginese-Regular.ttf",
+    "NotoSansBuhid-Regular.ttf",
+    "NotoSansCanadianAboriginal-Regular.ttf",
+    "NotoSansCarian-Regular.ttf",
+    "NotoSansCham-Bold.ttf",
+    "NotoSansCham-Regular.ttf",
+    "NotoSansCherokee-Regular.ttf",
+    "NotoSansCoptic-Regular.ttf",
+    "NotoSansCuneiform-Regular.ttf",
+    "NotoSansCypriot-Regular.ttf",
+    "NotoSansDeseret-Regular.ttf",
+    "NotoSansDevanagari-Bold.ttf",
+    "NotoSansDevanagari-Regular.ttf",
+    "NotoSansDevanagariUI-Bold.ttf",
+    "NotoSansDevanagariUI-Regular.ttf",
+    "NotoSansEgyptianHieroglyphs-Regular.ttf",
+    "NotoSansEthiopic-Bold.ttf",
+    "NotoSansEthiopic-Regular.ttf",
+    "NotoSansGeorgian-Bold.ttf",
+    "NotoSansGeorgian-Regular.ttf",
+    "NotoSansGlagolitic-Regular.ttf",
+    "NotoSansGothic-Regular.ttf",
+    "NotoSansGujarati-Bold.ttf",
+    "NotoSansGujarati-Regular.ttf",
+    "NotoSansGujaratiUI-Bold.ttf",
+    "NotoSansGujaratiUI-Regular.ttf",
+    "NotoSansGurmukhi-Bold.ttf",
+    "NotoSansGurmukhi-Regular.ttf",
+    "NotoSansGurmukhiUI-Bold.ttf",
+    "NotoSansGurmukhiUI-Regular.ttf",
+    "NotoSansHanunoo-Regular.ttf",
+    "NotoSansHebrew-Bold.ttf",
+    "NotoSansHebrew-Regular.ttf",
+    "NotoSansImperialAramaic-Regular.ttf",
+    "NotoSansInscriptionalPahlavi-Regular.ttf",
+    "NotoSansInscriptionalParthian-Regular.ttf",
+    "NotoSansJP-Regular-Subsetted.otf",
+    "NotoSansJP-Regular.otf",
+    "NotoSansJavanese-Regular.ttf",
+    "NotoSansKR-Regular.otf",
+    "NotoSansKaithi-Regular.ttf",
+    "NotoSansKannada-Bold.ttf",
+    "NotoSansKannada-Regular.ttf",
+    "NotoSansKannadaUI-Bold.ttf",
+    "NotoSansKannadaUI-Regular.ttf",
+    "NotoSansKayahLi-Regular.ttf",
+    "NotoSansKharoshthi-Regular.ttf",
+    "NotoSansKhmer-Bold.ttf",
+    "NotoSansKhmer-Regular.ttf",
+    "NotoSansKhmerUI-Bold.ttf",
+    "NotoSansKhmerUI-Regular.ttf",
+    "NotoSansLao-Bold.ttf",
+    "NotoSansLao-Regular.ttf",
+    "NotoSansLaoUI-Bold.ttf",
+    "NotoSansLaoUI-Regular.ttf",
+    "NotoSansLepcha-Regular.ttf",
+    "NotoSansLimbu-Regular.ttf",
+    "NotoSansLinearB-Regular.ttf",
+    "NotoSansLisu-Regular.ttf",
+    "NotoSansLycian-Regular.ttf",
+    "NotoSansLydian-Regular.ttf",
+    "NotoSansMalayalam-Bold.ttf",
+    "NotoSansMalayalam-Regular.ttf",
+    "NotoSansMalayalamUI-Bold.ttf",
+    "NotoSansMalayalamUI-Regular.ttf",
+    "NotoSansMandaic-Regular.ttf",
+    "NotoSansMeeteiMayek-Regular.ttf",
+    "NotoSansMongolian-Regular.ttf",
+    "NotoSansMyanmar-Bold.ttf",
+    "NotoSansMyanmar-Regular.ttf",
+    "NotoSansMyanmarUI-Bold.ttf",
+    "NotoSansMyanmarUI-Regular.ttf",
+    "NotoSansNKo-Regular.ttf",
+    "NotoSansNewTaiLue-Regular.ttf",
+    "NotoSansOgham-Regular.ttf",
+    "NotoSansOlChiki-Regular.ttf",
+    "NotoSansOldItalic-Regular.ttf",
+    "NotoSansOldPersian-Regular.ttf",
+    "NotoSansOldSouthArabian-Regular.ttf",
+    "NotoSansOldTurkic-Regular.ttf",
+    "NotoSansOriya-Bold.ttf",
+    "NotoSansOriya-Regular.ttf",
+    "NotoSansOriyaUI-Bold.ttf",
+    "NotoSansOriyaUI-Regular.ttf",
+    "NotoSansOsmanya-Regular.ttf",
+    "NotoSansPhagsPa-Regular.ttf",
+    "NotoSansPhoenician-Regular.ttf",
+    "NotoSansRejang-Regular.ttf",
+    "NotoSansRunic-Regular.ttf",
+    "NotoSansSC-Regular.otf",
+    "NotoSansSamaritan-Regular.ttf",
+    "NotoSansSaurashtra-Regular.ttf",
+    "NotoSansShavian-Regular.ttf",
+    "NotoSansSinhala-Bold.ttf",
+    "NotoSansSinhala-Regular.ttf",
+    "NotoSansSundanese-Regular.ttf",
+    "NotoSansSylotiNagri-Regular.ttf",
+    "NotoSansSymbols-Regular-Subsetted.ttf",
+    "NotoSansSymbols-Regular.ttf",
+    "NotoSansSyriacEastern-Regular.ttf",
+    "NotoSansSyriacEstrangela-Regular.ttf",
+    "NotoSansSyriacWestern-Regular.ttf",
+    "NotoSansTC-Regular.otf",
+    "NotoSansTagalog-Regular.ttf",
+    "NotoSansTagbanwa-Regular.ttf",
+    "NotoSansTaiLe-Regular.ttf",
+    "NotoSansTaiTham-Regular.ttf",
+    "NotoSansTaiViet-Regular.ttf",
+    "NotoSansTamil-Bold.ttf",
+    "NotoSansTamil-Regular.ttf",
+    "NotoSansTamilUI-Bold.ttf",
+    "NotoSansTamilUI-Regular.ttf",
+    "NotoSansTelugu-Bold.ttf",
+    "NotoSansTelugu-Regular.ttf",
+    "NotoSansTeluguUI-Bold.ttf",
+    "NotoSansTeluguUI-Regular.ttf",
+    "NotoSansThaana-Bold.ttf",
+    "NotoSansThaana-Regular.ttf",
+    "NotoSansThai-Bold.ttf",
+    "NotoSansThai-Regular.ttf",
+    "NotoSansThaiUI-Bold.ttf",
+    "NotoSansThaiUI-Regular.ttf",
+    "NotoSansTibetan-Regular.ttf",
+    "NotoSansTifinagh-Regular.ttf",
+    "NotoSansUI-Bold.ttf",
+    "NotoSansUI-BoldItalic.ttf",
+    "NotoSansUI-Italic.ttf",
+    "NotoSansUI-Regular.ttf",
+    "NotoSansUgaritic-Regular.ttf",
+    "NotoSansVai-Regular.ttf",
+    "NotoSansYi-Regular.ttf",
+    "NotoSerif-Bold.ttf",
+    "NotoSerif-BoldItalic.ttf",
+    "NotoSerif-Italic.ttf",
+    "NotoSerif-Regular.ttf",
+    "NotoSerifArmenian-Bold.ttf",
+    "NotoSerifArmenian-Regular.ttf",
+    "NotoSerifGeorgian-Bold.ttf",
+    "NotoSerifGeorgian-Regular.ttf",
+    "NotoSerifKhmer-Bold.ttf",
+    "NotoSerifKhmer-Regular.ttf",
+    "NotoSerifLao-Bold.ttf",
+    "NotoSerifLao-Regular.ttf",
+    "NotoSerifThai-Bold.ttf",
+    "NotoSerifThai-Regular.ttf",
+    "Roboto-Black.ttf",
+    "Roboto-BlackItalic.ttf",
+    "Roboto-Bold.ttf",
+    "Roboto-BoldItalic.ttf",
+    "Roboto-Italic.ttf",
+    "Roboto-Light.ttf",
+    "Roboto-LightItalic.ttf",
+    "Roboto-Medium.ttf",
+    "Roboto-MediumItalic.ttf",
+    "Roboto-Regular.ttf",
+    "Roboto-Thin.ttf",
+    "Roboto-ThinItalic.ttf",
+    "RobotoCondensed-Bold.ttf",
+    "RobotoCondensed-BoldItalic.ttf",
+    "RobotoCondensed-Italic.ttf",
+    "RobotoCondensed-Light.ttf",
+    "RobotoCondensed-LightItalic.ttf",
+    "RobotoCondensed-Regular.ttf",
+    "fonts.xml",
+  ]
+
+  outputs = [
+    "$target_gen_dir/{{source_file_part}}",
+  ]
+}
diff --git a/third_party/blimp_fonts/CarroisGothicSC-Regular.ttf.sha1 b/third_party/blimp_fonts/CarroisGothicSC-Regular.ttf.sha1
new file mode 100644
index 0000000..f9120e0
--- /dev/null
+++ b/third_party/blimp_fonts/CarroisGothicSC-Regular.ttf.sha1
@@ -0,0 +1 @@
+009d2696ba2ceb4d58dca2a6535b7c74f252caf2
\ No newline at end of file
diff --git a/third_party/blimp_fonts/Clockopia.ttf.sha1 b/third_party/blimp_fonts/Clockopia.ttf.sha1
new file mode 100644
index 0000000..ca93d0fd
--- /dev/null
+++ b/third_party/blimp_fonts/Clockopia.ttf.sha1
@@ -0,0 +1 @@
+8175e3bc43ae590f513e5bf38baa5860c81458a1
\ No newline at end of file
diff --git a/third_party/blimp_fonts/ComingSoon.ttf.sha1 b/third_party/blimp_fonts/ComingSoon.ttf.sha1
new file mode 100644
index 0000000..f93b6c9
--- /dev/null
+++ b/third_party/blimp_fonts/ComingSoon.ttf.sha1
@@ -0,0 +1 @@
+a6fc4d9e7339c7d9c6dd9b994a00e4a965c91df4
\ No newline at end of file
diff --git a/third_party/blimp_fonts/CutiveMono.ttf.sha1 b/third_party/blimp_fonts/CutiveMono.ttf.sha1
new file mode 100644
index 0000000..428ebc7
--- /dev/null
+++ b/third_party/blimp_fonts/CutiveMono.ttf.sha1
@@ -0,0 +1 @@
+e4837f21d7581c3f0418a02b2bedf15909df7569
\ No newline at end of file
diff --git a/third_party/blimp_fonts/DancingScript-Bold.ttf.sha1 b/third_party/blimp_fonts/DancingScript-Bold.ttf.sha1
new file mode 100644
index 0000000..9f007c3
--- /dev/null
+++ b/third_party/blimp_fonts/DancingScript-Bold.ttf.sha1
@@ -0,0 +1 @@
+489aa561aca5ef5a8e9884b183cad31a2e52bd9f
\ No newline at end of file
diff --git a/third_party/blimp_fonts/DancingScript-Regular.ttf.sha1 b/third_party/blimp_fonts/DancingScript-Regular.ttf.sha1
new file mode 100644
index 0000000..5a0a8f6
--- /dev/null
+++ b/third_party/blimp_fonts/DancingScript-Regular.ttf.sha1
@@ -0,0 +1 @@
+1298686a3510db5dc99a1a73872e0454112a626e
\ No newline at end of file
diff --git a/third_party/blimp_fonts/DroidSansFallback.ttf.sha1 b/third_party/blimp_fonts/DroidSansFallback.ttf.sha1
new file mode 100644
index 0000000..7cbbc30
--- /dev/null
+++ b/third_party/blimp_fonts/DroidSansFallback.ttf.sha1
@@ -0,0 +1 @@
+408db827c9555c10618707d47314083ebf496f59
\ No newline at end of file
diff --git a/third_party/blimp_fonts/DroidSansFallbackFull.ttf.sha1 b/third_party/blimp_fonts/DroidSansFallbackFull.ttf.sha1
new file mode 100644
index 0000000..9b18446
--- /dev/null
+++ b/third_party/blimp_fonts/DroidSansFallbackFull.ttf.sha1
@@ -0,0 +1 @@
+53c637979f023ea3933cd09befb6518aef5baa92
\ No newline at end of file
diff --git a/third_party/blimp_fonts/DroidSansMono.ttf.sha1 b/third_party/blimp_fonts/DroidSansMono.ttf.sha1
new file mode 100644
index 0000000..536bde4
--- /dev/null
+++ b/third_party/blimp_fonts/DroidSansMono.ttf.sha1
@@ -0,0 +1 @@
+0b75601f8ef8e111babb6ed11de6573f7178ce44
\ No newline at end of file
diff --git a/third_party/blimp_fonts/LICENSE b/third_party/blimp_fonts/LICENSE
new file mode 100644
index 0000000..78d4582
--- /dev/null
+++ b/third_party/blimp_fonts/LICENSE
@@ -0,0 +1,230 @@
+Fonts under Apache License Version 2.0 license:
+
+AndroidClock.ttf
+AndroidClock_Highlight.ttf
+AndroidClock_Solid.ttf
+Clockopia.ttf
+ComingSoon.ttf
+DroidSansFallback.ttf
+DroidSansFallbackFull.ttf
+DroidSansMono.ttf
+MTLc3m.ttf
+MTLmr3m.ttf
+NotoColorEmoji.ttf
+NotoKufiArabic-Bold.ttf
+NotoKufiArabic-Regular.ttf
+NotoNaskhArabic-Bold.ttf
+NotoNaskhArabic-Regular.ttf
+NotoNaskhArabicUI-Bold.ttf
+NotoNaskhArabicUI-Regular.ttf
+NotoSansArmenian-Bold.ttf
+NotoSansArmenian-Regular.ttf
+NotoSansAvestan-Regular.ttf
+NotoSansBalinese-Regular.ttf
+NotoSansBamum-Regular.ttf
+NotoSansBatak-Regular.ttf
+NotoSansBengali-Bold.ttf
+NotoSansBengali-Regular.ttf
+NotoSansBengaliUI-Bold.ttf
+NotoSansBengaliUI-Regular.ttf
+NotoSans-BoldItalic.ttf
+NotoSans-Bold.ttf
+NotoSansBrahmi-Regular.ttf
+NotoSansBuginese-Regular.ttf
+NotoSansBuhid-Regular.ttf
+NotoSansCanadianAboriginal-Regular.ttf
+NotoSansCarian-Regular.ttf
+NotoSansCham-Bold.ttf
+NotoSansCham-Regular.ttf
+NotoSansCherokee-Regular.ttf
+NotoSansCoptic-Regular.ttf
+NotoSansCuneiform-Regular.ttf
+NotoSansCypriot-Regular.ttf
+NotoSansDeseret-Regular.ttf
+NotoSansDevanagari-Bold.ttf
+NotoSansDevanagari-Regular.ttf
+NotoSansDevanagariUI-Bold.ttf
+NotoSansDevanagariUI-Regular.ttf
+NotoSansEgyptianHieroglyphs-Regular.ttf
+NotoSansEthiopic-Bold.ttf
+NotoSansEthiopic-Regular.ttf
+NotoSansGeorgian-Bold.ttf
+NotoSansGeorgian-Regular.ttf
+NotoSansGlagolitic-Regular.ttf
+NotoSansGothic-Regular.ttf
+NotoSansGujarati-Bold.ttf
+NotoSansGujarati-Regular.ttf
+NotoSansGujaratiUI-Bold.ttf
+NotoSansGujaratiUI-Regular.ttf
+NotoSansGurmukhi-Bold.ttf
+NotoSansGurmukhi-Regular.ttf
+NotoSansGurmukhiUI-Bold.ttf
+NotoSansGurmukhiUI-Regular.ttf
+NotoSansHanunoo-Regular.ttf
+NotoSansHebrew-Bold.ttf
+NotoSansHebrew-Regular.ttf
+NotoSansImperialAramaic-Regular.ttf
+NotoSansInscriptionalPahlavi-Regular.ttf
+NotoSansInscriptionalParthian-Regular.ttf
+NotoSans-Italic.ttf
+NotoSansJavanese-Regular.ttf
+NotoSansKaithi-Regular.ttf
+NotoSansKannada-Bold.ttf
+NotoSansKannada-Regular.ttf
+NotoSansKannadaUI-Bold.ttf
+NotoSansKannadaUI-Regular.ttf
+NotoSansKayahLi-Regular.ttf
+NotoSansKharoshthi-Regular.ttf
+NotoSansKhmer-Bold.ttf
+NotoSansKhmer-Regular.ttf
+NotoSansKhmerUI-Bold.ttf
+NotoSansKhmerUI-Regular.ttf
+NotoSansLao-Bold.ttf
+NotoSansLao-Regular.ttf
+NotoSansLaoUI-Bold.ttf
+NotoSansLaoUI-Regular.ttf
+NotoSansLepcha-Regular.ttf
+NotoSansLimbu-Regular.ttf
+NotoSansLinearB-Regular.ttf
+NotoSansLisu-Regular.ttf
+NotoSansLycian-Regular.ttf
+NotoSansLydian-Regular.ttf
+NotoSansMalayalam-Bold.ttf
+NotoSansMalayalam-Regular.ttf
+NotoSansMalayalamUI-Bold.ttf
+NotoSansMalayalamUI-Regular.ttf
+NotoSansMandaic-Regular.ttf
+NotoSansMeeteiMayek-Regular.ttf
+NotoSansMongolian-Regular.ttf
+NotoSansMyanmar-Bold.ttf
+NotoSansMyanmar-Regular.ttf
+NotoSansMyanmarUI-Bold.ttf
+NotoSansMyanmarUI-Regular.ttf
+NotoSansNewTaiLue-Regular.ttf
+NotoSansNKo-Regular.ttf
+NotoSansOgham-Regular.ttf
+NotoSansOlChiki-Regular.ttf
+NotoSansOldItalic-Regular.ttf
+NotoSansOldPersian-Regular.ttf
+NotoSansOldSouthArabian-Regular.ttf
+NotoSansOldTurkic-Regular.ttf
+NotoSansOriya-Bold.ttf
+NotoSansOriya-Regular.ttf
+NotoSansOriyaUI-Bold.ttf
+NotoSansOriyaUI-Regular.ttf
+NotoSansOsmanya-Regular.ttf
+NotoSansPhagsPa-Regular.ttf
+NotoSansPhoenician-Regular.ttf
+NotoSans-Regular.ttf
+NotoSansRejang-Regular.ttf
+NotoSansRunic-Regular.ttf
+NotoSansSamaritan-Regular.ttf
+NotoSansSaurashtra-Regular.ttf
+NotoSansShavian-Regular.ttf
+NotoSansSinhala-Bold.ttf
+NotoSansSinhala-Regular.ttf
+NotoSansSundanese-Regular.ttf
+NotoSansSylotiNagri-Regular.ttf
+NotoSansSymbols-Regular-Subsetted.ttf
+NotoSansSymbols-Regular.ttf
+NotoSansSyriacEastern-Regular.ttf
+NotoSansSyriacEstrangela-Regular.ttf
+NotoSansSyriacWestern-Regular.ttf
+NotoSansTagalog-Regular.ttf
+NotoSansTagbanwa-Regular.ttf
+NotoSansTaiLe-Regular.ttf
+NotoSansTaiTham-Regular.ttf
+NotoSansTaiViet-Regular.ttf
+NotoSansTamil-Bold.ttf
+NotoSansTamil-Regular.ttf
+NotoSansTamilUI-Bold.ttf
+NotoSansTamilUI-Regular.ttf
+NotoSansTelugu-Bold.ttf
+NotoSansTelugu-Regular.ttf
+NotoSansTeluguUI-Bold.ttf
+NotoSansTeluguUI-Regular.ttf
+NotoSansThaana-Bold.ttf
+NotoSansThaana-Regular.ttf
+NotoSansThai-Bold.ttf
+NotoSansThai-Regular.ttf
+NotoSansThaiUI-Bold.ttf
+NotoSansThaiUI-Regular.ttf
+NotoSansTibetan-Regular.ttf
+NotoSansTifinagh-Regular.ttf
+NotoSansUgaritic-Regular.ttf
+NotoSansUI-BoldItalic.ttf
+NotoSansUI-Bold.ttf
+NotoSansUI-Italic.ttf
+NotoSansUI-Regular.ttf
+NotoSansVai-Regular.ttf
+NotoSansYi-Regular.ttf
+NotoSerifArmenian-Bold.ttf
+NotoSerifArmenian-Regular.ttf
+NotoSerif-BoldItalic.ttf
+NotoSerif-Bold.ttf
+NotoSerifGeorgian-Bold.ttf
+NotoSerifGeorgian-Regular.ttf
+NotoSerif-Italic.ttf
+NotoSerifKhmer-Bold.ttf
+NotoSerifKhmer-Regular.ttf
+NotoSerifLao-Bold.ttf
+NotoSerifLao-Regular.ttf
+NotoSerif-Regular.ttf
+NotoSerifThai-Bold.ttf
+NotoSerifThai-Regular.ttf
+Roboto-BlackItalic.ttf
+Roboto-Black.ttf
+Roboto-BoldItalic.ttf
+Roboto-Bold.ttf
+RobotoCondensed-BoldItalic.ttf
+RobotoCondensed-Bold.ttf
+RobotoCondensed-Italic.ttf
+RobotoCondensed-LightItalic.ttf
+RobotoCondensed-Light.ttf
+RobotoCondensed-Regular.ttf
+Roboto-Italic.ttf
+Roboto-LightItalic.ttf
+Roboto-Light.ttf
+Roboto-MediumItalic.ttf
+Roboto-Medium.ttf
+Roboto-Regular.ttf
+Roboto-ThinItalic.ttf
+Roboto-Thin.ttf
+
+
+Fonts under SIL Open Font License, Version 1.1:
+(Full license in LICENSE.OFL)
+
+NotoSansJP-Regular.otf
+NotoSansJP-Regular-Subsetted.otf
+NotoSansKR-Regular.otf
+NotoSansSC-Regular.otf
+NotoSansTC-Regular.otf
+
+
+Copyright (c) 2011 by Ralph du Carrois, with Reserved Font Name 'Carrois'
+This Font Software is licensed under the SIL Open Font License, Version 1.1
+(Full license in LICENSE.OFL)
+CarroisGothicSC-Regular.ttf
+
+
+Copyright (c) 2010, Pablo Impallari (www.impallari.com|impallari@gmail.com),
+Copyright (c) 2010, Igino Marini. (www.ikern.com|mail@iginomarini.com),
+with Reserved Font Name Dancing Script.
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+(Full license in LICENSE.OFL)
+
+DancingScript-Bold.ttf
+DancingScript-Regular.ttf
+CutiveMono.ttf
+
+
+Copyright (c) 2010, NHN Corporation (http://www.nhncorp.com),
+  (http://hangeul.naver.com/font)
+with Reserved Font Name Nanum, Naver Nanum, NanumGothic, Naver NanumGothic, NanumMyeongjo, Naver NanumMyeongjo, NanumBrush, Naver NanumBrush, NanumPen, Naver NanumPen, Naver NanumGothicEco, NanumGothicEco, Naver NanumMyeongjoEco, NanumMyeongjoEco, Naver NanumGothicLight, NanumGothicLight
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+(Full license in LICENSE.OFL)
+
+NanumGothicBold.ttf
+NanumGothic.ttf
diff --git a/third_party/blimp_fonts/LICENSE.Apache b/third_party/blimp_fonts/LICENSE.Apache
new file mode 100644
index 0000000..a3711ba6
--- /dev/null
+++ b/third_party/blimp_fonts/LICENSE.Apache
@@ -0,0 +1,201 @@
+                             Apache License
+                       Version 2.0, January 2004
+                    http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+  "License" shall mean the terms and conditions for use, reproduction,
+  and distribution as defined by Sections 1 through 9 of this document.
+
+  "Licensor" shall mean the copyright owner or entity authorized by
+  the copyright owner that is granting the License.
+
+  "Legal Entity" shall mean the union of the acting entity and all
+  other entities that control, are controlled by, or are under common
+  control with that entity. For the purposes of this definition,
+  "control" means (i) the power, direct or indirect, to cause the
+  direction or management of such entity, whether by contract or
+  otherwise, or (ii) ownership of fifty percent (50%) or more of the
+  outstanding shares, or (iii) beneficial ownership of such entity.
+
+  "You" (or "Your") shall mean an individual or Legal Entity
+  exercising permissions granted by this License.
+
+  "Source" form shall mean the preferred form for making modifications,
+  including but not limited to software source code, documentation
+  source, and configuration files.
+
+  "Object" form shall mean any form resulting from mechanical
+  transformation or translation of a Source form, including but
+  not limited to compiled object code, generated documentation,
+  and conversions to other media types.
+
+  "Work" shall mean the work of authorship, whether in Source or
+  Object form, made available under the License, as indicated by a
+  copyright notice that is included in or attached to the work
+  (an example is provided in the Appendix below).
+
+  "Derivative Works" shall mean any work, whether in Source or Object
+  form, that is based on (or derived from) the Work and for which the
+  editorial revisions, annotations, elaborations, or other modifications
+  represent, as a whole, an original work of authorship. For the purposes
+  of this License, Derivative Works shall not include works that remain
+  separable from, or merely link (or bind by name) to the interfaces of,
+  the Work and Derivative Works thereof.
+
+  "Contribution" shall mean any work of authorship, including
+  the original version of the Work and any modifications or additions
+  to that Work or Derivative Works thereof, that is intentionally
+  submitted to Licensor for inclusion in the Work by the copyright owner
+  or by an individual or Legal Entity authorized to submit on behalf of
+  the copyright owner. For the purposes of this definition, "submitted"
+  means any form of electronic, verbal, or written communication sent
+  to the Licensor or its representatives, including but not limited to
+  communication on electronic mailing lists, source code control systems,
+  and issue tracking systems that are managed by, or on behalf of, the
+  Licensor for the purpose of discussing and improving the Work, but
+  excluding communication that is conspicuously marked or otherwise
+  designated in writing by the copyright owner as "Not a Contribution."
+
+  "Contributor" shall mean Licensor and any individual or Legal Entity
+  on behalf of whom a Contribution has been received by Licensor and
+  subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+  this License, each Contributor hereby grants to You a perpetual,
+  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+  copyright license to reproduce, prepare Derivative Works of,
+  publicly display, publicly perform, sublicense, and distribute the
+  Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+  this License, each Contributor hereby grants to You a perpetual,
+  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+  (except as stated in this section) patent license to make, have made,
+  use, offer to sell, sell, import, and otherwise transfer the Work,
+  where such license applies only to those patent claims licensable
+  by such Contributor that are necessarily infringed by their
+  Contribution(s) alone or by combination of their Contribution(s)
+  with the Work to which such Contribution(s) was submitted. If You
+  institute patent litigation against any entity (including a
+  cross-claim or counterclaim in a lawsuit) alleging that the Work
+  or a Contribution incorporated within the Work constitutes direct
+  or contributory patent infringement, then any patent licenses
+  granted to You under this License for that Work shall terminate
+  as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+  Work or Derivative Works thereof in any medium, with or without
+  modifications, and in Source or Object form, provided that You
+  meet the following conditions:
+
+  (a) You must give any other recipients of the Work or
+      Derivative Works a copy of this License; and
+
+  (b) You must cause any modified files to carry prominent notices
+      stating that You changed the files; and
+
+  (c) You must retain, in the Source form of any Derivative Works
+      that You distribute, all copyright, patent, trademark, and
+      attribution notices from the Source form of the Work,
+      excluding those notices that do not pertain to any part of
+      the Derivative Works; and
+
+  (d) If the Work includes a "NOTICE" text file as part of its
+      distribution, then any Derivative Works that You distribute must
+      include a readable copy of the attribution notices contained
+      within such NOTICE file, excluding those notices that do not
+      pertain to any part of the Derivative Works, in at least one
+      of the following places: within a NOTICE text file distributed
+      as part of the Derivative Works; within the Source form or
+      documentation, if provided along with the Derivative Works; or,
+      within a display generated by the Derivative Works, if and
+      wherever such third-party notices normally appear. The contents
+      of the NOTICE file are for informational purposes only and
+      do not modify the License. You may add Your own attribution
+      notices within Derivative Works that You distribute, alongside
+      or as an addendum to the NOTICE text from the Work, provided
+      that such additional attribution notices cannot be construed
+      as modifying the License.
+
+  You may add Your own copyright statement to Your modifications and
+  may provide additional or different license terms and conditions
+  for use, reproduction, or distribution of Your modifications, or
+  for any such Derivative Works as a whole, provided Your use,
+  reproduction, and distribution of the Work otherwise complies with
+  the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+  any Contribution intentionally submitted for inclusion in the Work
+  by You to the Licensor shall be under the terms and conditions of
+  this License, without any additional terms or conditions.
+  Notwithstanding the above, nothing herein shall supersede or modify
+  the terms of any separate license agreement you may have executed
+  with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+  names, trademarks, service marks, or product names of the Licensor,
+  except as required for reasonable and customary use in describing the
+  origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+  agreed to in writing, Licensor provides the Work (and each
+  Contributor provides its Contributions) on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+  implied, including, without limitation, any warranties or conditions
+  of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+  PARTICULAR PURPOSE. You are solely responsible for determining the
+  appropriateness of using or redistributing the Work and assume any
+  risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+  whether in tort (including negligence), contract, or otherwise,
+  unless required by applicable law (such as deliberate and grossly
+  negligent acts) or agreed to in writing, shall any Contributor be
+  liable to You for damages, including any direct, indirect, special,
+  incidental, or consequential damages of any character arising as a
+  result of this License or out of the use or inability to use the
+  Work (including but not limited to damages for loss of goodwill,
+  work stoppage, computer failure or malfunction, or any and all
+  other commercial damages or losses), even if such Contributor
+  has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+  the Work or Derivative Works thereof, You may choose to offer,
+  and charge a fee for, acceptance of support, warranty, indemnity,
+  or other liability obligations and/or rights consistent with this
+  License. However, in accepting such obligations, You may act only
+  on Your own behalf and on Your sole responsibility, not on behalf
+  of any other Contributor, and only if You agree to indemnify,
+  defend, and hold each Contributor harmless for any liability
+  incurred by, or claims asserted against, such Contributor by reason
+  of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+  To apply the Apache License to your work, attach the following
+  boilerplate notice, with the fields enclosed by brackets "[]"
+  replaced with your own identifying information. (Don't include
+  the brackets!)  The text should be enclosed in the appropriate
+  comment syntax for the file format. We also recommend that a
+  file or class name and description of purpose be included on the
+  same "printed page" as the copyright notice for easier
+  identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/third_party/blimp_fonts/LICENSE.OFL b/third_party/blimp_fonts/LICENSE.OFL
new file mode 100644
index 0000000..d952d62
--- /dev/null
+++ b/third_party/blimp_fonts/LICENSE.OFL
@@ -0,0 +1,92 @@
+This Font Software is licensed under the SIL Open Font License,
+Version 1.1.
+
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font
+creation efforts of academic and linguistic communities, and to
+provide a free and open framework in which fonts may be shared and
+improved in partnership with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply to
+any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software
+components as distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to,
+deleting, or substituting -- in part or in whole -- any of the
+components of the Original Version, by changing formats or by porting
+the Font Software to a new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed,
+modify, redistribute, and sell modified and unmodified copies of the
+Font Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components, in
+Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the
+corresponding Copyright Holder. This restriction only applies to the
+primary font name as presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created using
+the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/third_party/blimp_fonts/MTLc3m.ttf.sha1 b/third_party/blimp_fonts/MTLc3m.ttf.sha1
new file mode 100644
index 0000000..fe44a8d
--- /dev/null
+++ b/third_party/blimp_fonts/MTLc3m.ttf.sha1
@@ -0,0 +1 @@
+3c204b67777ea8d9a5b68b1c10eb606bb72cb5ab
\ No newline at end of file
diff --git a/third_party/blimp_fonts/MTLmr3m.ttf.sha1 b/third_party/blimp_fonts/MTLmr3m.ttf.sha1
new file mode 100644
index 0000000..fe932746
--- /dev/null
+++ b/third_party/blimp_fonts/MTLmr3m.ttf.sha1
@@ -0,0 +1 @@
+6084cd39578214d7a4dec3fe46b10fdb7d335e50
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NanumGothic.ttf.sha1 b/third_party/blimp_fonts/NanumGothic.ttf.sha1
new file mode 100644
index 0000000..f523180
--- /dev/null
+++ b/third_party/blimp_fonts/NanumGothic.ttf.sha1
@@ -0,0 +1 @@
+f6844b0169c0a453778980b65b28fa4b15014246
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NanumGothicBold.ttf.sha1 b/third_party/blimp_fonts/NanumGothicBold.ttf.sha1
new file mode 100644
index 0000000..c453c733d
--- /dev/null
+++ b/third_party/blimp_fonts/NanumGothicBold.ttf.sha1
@@ -0,0 +1 @@
+da02b0bb41d80957c8ffdde238b2c85c21f02361
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoColorEmoji.ttf.sha1 b/third_party/blimp_fonts/NotoColorEmoji.ttf.sha1
new file mode 100644
index 0000000..f9073838
--- /dev/null
+++ b/third_party/blimp_fonts/NotoColorEmoji.ttf.sha1
@@ -0,0 +1 @@
+d4af84777101e3083886decc94a87b7ab8c370e5
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoKufiArabic-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoKufiArabic-Bold.ttf.sha1
new file mode 100644
index 0000000..7d430f8
--- /dev/null
+++ b/third_party/blimp_fonts/NotoKufiArabic-Bold.ttf.sha1
@@ -0,0 +1 @@
+1e586ea25cf9ab4fd959280e1248f8a44c4a59d9
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoKufiArabic-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoKufiArabic-Regular.ttf.sha1
new file mode 100644
index 0000000..b1753b7
--- /dev/null
+++ b/third_party/blimp_fonts/NotoKufiArabic-Regular.ttf.sha1
@@ -0,0 +1 @@
+3a3f060aaf35f60e543d5e762a33c6ea66d80c9c
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoNaskhArabic-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoNaskhArabic-Bold.ttf.sha1
new file mode 100644
index 0000000..87386afb
--- /dev/null
+++ b/third_party/blimp_fonts/NotoNaskhArabic-Bold.ttf.sha1
@@ -0,0 +1 @@
+b81530fa957843ba04e9c91dd1ee5cba8e737345
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoNaskhArabic-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoNaskhArabic-Regular.ttf.sha1
new file mode 100644
index 0000000..cffe28e
--- /dev/null
+++ b/third_party/blimp_fonts/NotoNaskhArabic-Regular.ttf.sha1
@@ -0,0 +1 @@
+651752e1b267194a463b4fb211ee8579576e9c0f
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoNaskhArabicUI-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoNaskhArabicUI-Bold.ttf.sha1
new file mode 100644
index 0000000..fdaa035
--- /dev/null
+++ b/third_party/blimp_fonts/NotoNaskhArabicUI-Bold.ttf.sha1
@@ -0,0 +1 @@
+43c827c0770e68d211b2f64f7796e4773665439f
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoNaskhArabicUI-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoNaskhArabicUI-Regular.ttf.sha1
new file mode 100644
index 0000000..909aa1f
--- /dev/null
+++ b/third_party/blimp_fonts/NotoNaskhArabicUI-Regular.ttf.sha1
@@ -0,0 +1 @@
+4dfe8336947e6e52502f2f8156371e85553ab600
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSans-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSans-Bold.ttf.sha1
new file mode 100644
index 0000000..bfeded8
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSans-Bold.ttf.sha1
@@ -0,0 +1 @@
+64b897dfb0a6cc8fd573e0793b85028b73dfb4a0
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSans-BoldItalic.ttf.sha1 b/third_party/blimp_fonts/NotoSans-BoldItalic.ttf.sha1
new file mode 100644
index 0000000..f6f4b8b
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSans-BoldItalic.ttf.sha1
@@ -0,0 +1 @@
+0ef56b3baa79415191519532e1c4a9325bb4f5ea
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSans-Italic.ttf.sha1 b/third_party/blimp_fonts/NotoSans-Italic.ttf.sha1
new file mode 100644
index 0000000..bc30332
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSans-Italic.ttf.sha1
@@ -0,0 +1 @@
+0d572e04d5d48ce3819ac78e0e2dbe1a6bcb1d47
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSans-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSans-Regular.ttf.sha1
new file mode 100644
index 0000000..9b89352
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSans-Regular.ttf.sha1
@@ -0,0 +1 @@
+b0c0c510fbf942d63745dc5248d23f1fe1859c1f
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansArmenian-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansArmenian-Bold.ttf.sha1
new file mode 100644
index 0000000..4a057fe6
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansArmenian-Bold.ttf.sha1
@@ -0,0 +1 @@
+eaecc6acfe8e40321429b503e1f4aa55e67b15e7
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansArmenian-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansArmenian-Regular.ttf.sha1
new file mode 100644
index 0000000..2450a07
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansArmenian-Regular.ttf.sha1
@@ -0,0 +1 @@
+bb1d0b181ee7a3dfd2570be4e29052e2eeb4c4a8
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansAvestan-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansAvestan-Regular.ttf.sha1
new file mode 100644
index 0000000..9dee971e
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansAvestan-Regular.ttf.sha1
@@ -0,0 +1 @@
+97993a74daa52ff59031f5c5541dc37459563f77
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansBalinese-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansBalinese-Regular.ttf.sha1
new file mode 100644
index 0000000..528d2d45
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansBalinese-Regular.ttf.sha1
@@ -0,0 +1 @@
+48a782222ccbc6e67036a83dd8ccfef75b766b8c
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansBamum-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansBamum-Regular.ttf.sha1
new file mode 100644
index 0000000..0849897
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansBamum-Regular.ttf.sha1
@@ -0,0 +1 @@
+7d3d14ac5ae5df87d7dc9243df011a6220023d30
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansBatak-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansBatak-Regular.ttf.sha1
new file mode 100644
index 0000000..68996230
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansBatak-Regular.ttf.sha1
@@ -0,0 +1 @@
+113c277988592dcd935fad584164814a0c39987c
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansBengali-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansBengali-Bold.ttf.sha1
new file mode 100644
index 0000000..db8c39a4
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansBengali-Bold.ttf.sha1
@@ -0,0 +1 @@
+3ba5b31be8e6715cabe7eb3f6948dad3936a54f6
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansBengali-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansBengali-Regular.ttf.sha1
new file mode 100644
index 0000000..8a26e7e
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansBengali-Regular.ttf.sha1
@@ -0,0 +1 @@
+28e762ed4a3b29dddb1cbd591f264f6e6471f0f2
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansBengaliUI-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansBengaliUI-Bold.ttf.sha1
new file mode 100644
index 0000000..45745ab
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansBengaliUI-Bold.ttf.sha1
@@ -0,0 +1 @@
+1ca4e43f7a865f21890f5a6f2258bbad758ba021
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansBengaliUI-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansBengaliUI-Regular.ttf.sha1
new file mode 100644
index 0000000..9b91c21d
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansBengaliUI-Regular.ttf.sha1
@@ -0,0 +1 @@
+efb13bb61802b122deb2e9445c855a008dd7d6fa
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansBrahmi-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansBrahmi-Regular.ttf.sha1
new file mode 100644
index 0000000..97086ff
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansBrahmi-Regular.ttf.sha1
@@ -0,0 +1 @@
+4cedf2d8ca231b81a44d984d04dd920360da4509
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansBuginese-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansBuginese-Regular.ttf.sha1
new file mode 100644
index 0000000..56cd4fe
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansBuginese-Regular.ttf.sha1
@@ -0,0 +1 @@
+bc56fb49234be9e7eddbaa35fc3e8965cde61155
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansBuhid-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansBuhid-Regular.ttf.sha1
new file mode 100644
index 0000000..0909c2f
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansBuhid-Regular.ttf.sha1
@@ -0,0 +1 @@
+7b6bc1c7b6444090b45ba5400bd16fedd3f1f310
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansCanadianAboriginal-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansCanadianAboriginal-Regular.ttf.sha1
new file mode 100644
index 0000000..4f2b208
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansCanadianAboriginal-Regular.ttf.sha1
@@ -0,0 +1 @@
+d3977d0e5345ccb2cc7ca1d93d2420f31b4eb558
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansCarian-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansCarian-Regular.ttf.sha1
new file mode 100644
index 0000000..3ae06b4
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansCarian-Regular.ttf.sha1
@@ -0,0 +1 @@
+0b51a8b392db852e640393ec34e7c07c10587fa5
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansCham-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansCham-Bold.ttf.sha1
new file mode 100644
index 0000000..2d123d0
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansCham-Bold.ttf.sha1
@@ -0,0 +1 @@
+4ad98c588ef2214aca74f6634278e58aec681fcd
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansCham-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansCham-Regular.ttf.sha1
new file mode 100644
index 0000000..bef04f6
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansCham-Regular.ttf.sha1
@@ -0,0 +1 @@
+18cd6f3b26410a70c1a00bf52ef26d6376874ab0
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansCherokee-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansCherokee-Regular.ttf.sha1
new file mode 100644
index 0000000..9d98d2a1
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansCherokee-Regular.ttf.sha1
@@ -0,0 +1 @@
+5be65ab8dc89fcdca48018ba3c863620ce95ac37
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansCoptic-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansCoptic-Regular.ttf.sha1
new file mode 100644
index 0000000..64df8346
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansCoptic-Regular.ttf.sha1
@@ -0,0 +1 @@
+08f262f76db5a9a53ac48c62b03d0dcefef0f5a7
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansCuneiform-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansCuneiform-Regular.ttf.sha1
new file mode 100644
index 0000000..c6535d2
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansCuneiform-Regular.ttf.sha1
@@ -0,0 +1 @@
+1731ae2d4b5b363efe9e86f9b6d4e77d590ceac2
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansCypriot-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansCypriot-Regular.ttf.sha1
new file mode 100644
index 0000000..f9d715e5
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansCypriot-Regular.ttf.sha1
@@ -0,0 +1 @@
+1e61adaf72b89c8b2c640c5deb3166048b9935ab
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansDeseret-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansDeseret-Regular.ttf.sha1
new file mode 100644
index 0000000..feb1fb6d
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansDeseret-Regular.ttf.sha1
@@ -0,0 +1 @@
+12610cd362930ce2bf2464d71391df11fa05e041
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansDevanagari-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansDevanagari-Bold.ttf.sha1
new file mode 100644
index 0000000..1db540a5
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansDevanagari-Bold.ttf.sha1
@@ -0,0 +1 @@
+7d2e8e7960e6e74507e974c1abb60c7118c5ec70
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansDevanagari-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansDevanagari-Regular.ttf.sha1
new file mode 100644
index 0000000..6f19fe39
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansDevanagari-Regular.ttf.sha1
@@ -0,0 +1 @@
+e043644bd7ca723c03a6482a472b8da6e7a6d87b
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansDevanagariUI-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansDevanagariUI-Bold.ttf.sha1
new file mode 100644
index 0000000..0201754
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansDevanagariUI-Bold.ttf.sha1
@@ -0,0 +1 @@
+d2cb268c25df9f8f6f834aeb5cd823603be1d202
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansDevanagariUI-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansDevanagariUI-Regular.ttf.sha1
new file mode 100644
index 0000000..794a5d7
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansDevanagariUI-Regular.ttf.sha1
@@ -0,0 +1 @@
+167c6949556960b8dd779baf68a9a6be51e788de
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansEgyptianHieroglyphs-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansEgyptianHieroglyphs-Regular.ttf.sha1
new file mode 100644
index 0000000..d75145b
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansEgyptianHieroglyphs-Regular.ttf.sha1
@@ -0,0 +1 @@
+f751cc4b4b0cf4c97f608ae4f7741a36fe9ff66c
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansEthiopic-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansEthiopic-Bold.ttf.sha1
new file mode 100644
index 0000000..62e8a19
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansEthiopic-Bold.ttf.sha1
@@ -0,0 +1 @@
+514908c4ec5afc786ebf6979b654a48649cd0eca
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansEthiopic-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansEthiopic-Regular.ttf.sha1
new file mode 100644
index 0000000..d64850d
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansEthiopic-Regular.ttf.sha1
@@ -0,0 +1 @@
+b4e7246f78ff5d94de75c9fd5c6aec7c0540ee34
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansGeorgian-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansGeorgian-Bold.ttf.sha1
new file mode 100644
index 0000000..590f36a
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansGeorgian-Bold.ttf.sha1
@@ -0,0 +1 @@
+f5ef0c389a715449de4cfc75d188cee902ceab54
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansGeorgian-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansGeorgian-Regular.ttf.sha1
new file mode 100644
index 0000000..c862c47
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansGeorgian-Regular.ttf.sha1
@@ -0,0 +1 @@
+0bc21a4a8df1a38699ca008b0771da770bbe4fd2
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansGlagolitic-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansGlagolitic-Regular.ttf.sha1
new file mode 100644
index 0000000..5e29582
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansGlagolitic-Regular.ttf.sha1
@@ -0,0 +1 @@
+254597fab20087221158855f58d1ce97653f746f
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansGothic-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansGothic-Regular.ttf.sha1
new file mode 100644
index 0000000..eb4f3996
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansGothic-Regular.ttf.sha1
@@ -0,0 +1 @@
+3e4ca5caf1c40d5b7509269b57319f5542338d46
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansGujarati-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansGujarati-Bold.ttf.sha1
new file mode 100644
index 0000000..70f57bbe
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansGujarati-Bold.ttf.sha1
@@ -0,0 +1 @@
+8c8fb46985f818e921ffedb9a9bde0fcf7828911
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansGujarati-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansGujarati-Regular.ttf.sha1
new file mode 100644
index 0000000..8f4ac71
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansGujarati-Regular.ttf.sha1
@@ -0,0 +1 @@
+24c133d6352b25c120bcf33d989bf26723e24279
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansGujaratiUI-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansGujaratiUI-Bold.ttf.sha1
new file mode 100644
index 0000000..8d4f7d5
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansGujaratiUI-Bold.ttf.sha1
@@ -0,0 +1 @@
+fbe9d746123474703345067ad016aa1f14cf6dc9
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansGujaratiUI-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansGujaratiUI-Regular.ttf.sha1
new file mode 100644
index 0000000..2002b08
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansGujaratiUI-Regular.ttf.sha1
@@ -0,0 +1 @@
+a1ba64256d731eb3bdbf31446bbeedaa6c6d905e
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansGurmukhi-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansGurmukhi-Bold.ttf.sha1
new file mode 100644
index 0000000..eb08537
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansGurmukhi-Bold.ttf.sha1
@@ -0,0 +1 @@
+66b46c24dd6ece64d41283f0734ec23380bb6417
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansGurmukhi-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansGurmukhi-Regular.ttf.sha1
new file mode 100644
index 0000000..42f69e9
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansGurmukhi-Regular.ttf.sha1
@@ -0,0 +1 @@
+329adf9d083e73e6e0393dae62e281a991c8b103
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansGurmukhiUI-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansGurmukhiUI-Bold.ttf.sha1
new file mode 100644
index 0000000..3eaf4b4
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansGurmukhiUI-Bold.ttf.sha1
@@ -0,0 +1 @@
+2410178072dcc690b52acc6897e778a0bffff452
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansGurmukhiUI-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansGurmukhiUI-Regular.ttf.sha1
new file mode 100644
index 0000000..e0ea527
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansGurmukhiUI-Regular.ttf.sha1
@@ -0,0 +1 @@
+0eae03dbbad4d205e039651899ea9a5310736c6e
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansHanunoo-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansHanunoo-Regular.ttf.sha1
new file mode 100644
index 0000000..799bed7
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansHanunoo-Regular.ttf.sha1
@@ -0,0 +1 @@
+fe0cca164f425b39f8540da5b6463ce77bee640c
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansHebrew-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansHebrew-Bold.ttf.sha1
new file mode 100644
index 0000000..87e69d1
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansHebrew-Bold.ttf.sha1
@@ -0,0 +1 @@
+d981044b3ff2607b13ad0051d3b3db7f88007748
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansHebrew-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansHebrew-Regular.ttf.sha1
new file mode 100644
index 0000000..ae16cc0
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansHebrew-Regular.ttf.sha1
@@ -0,0 +1 @@
+083d168f4d033ce85bdc3919081e3880a6136578
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansImperialAramaic-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansImperialAramaic-Regular.ttf.sha1
new file mode 100644
index 0000000..240ff2f
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansImperialAramaic-Regular.ttf.sha1
@@ -0,0 +1 @@
+660288815e06bf6fb63f746012ca739958135bab
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansInscriptionalPahlavi-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansInscriptionalPahlavi-Regular.ttf.sha1
new file mode 100644
index 0000000..e43ac54
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansInscriptionalPahlavi-Regular.ttf.sha1
@@ -0,0 +1 @@
+296c6ba342b1937b6c98ef7428a3bfbd9fed2df3
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansInscriptionalParthian-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansInscriptionalParthian-Regular.ttf.sha1
new file mode 100644
index 0000000..e1e8f95
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansInscriptionalParthian-Regular.ttf.sha1
@@ -0,0 +1 @@
+097d726c7477b9261fb5bf01dc4686610a3fbc97
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansJP-Regular-Subsetted.otf.sha1 b/third_party/blimp_fonts/NotoSansJP-Regular-Subsetted.otf.sha1
new file mode 100644
index 0000000..7d4fce5
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansJP-Regular-Subsetted.otf.sha1
@@ -0,0 +1 @@
+8afcd909334ce92647a82c2e4aaac408a93bf8ef
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansJP-Regular.otf.sha1 b/third_party/blimp_fonts/NotoSansJP-Regular.otf.sha1
new file mode 100644
index 0000000..2ad4564
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansJP-Regular.otf.sha1
@@ -0,0 +1 @@
+685c52a8ad0b41098e85c099a6e5be0d09ef2f02
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansJavanese-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansJavanese-Regular.ttf.sha1
new file mode 100644
index 0000000..6eee177
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansJavanese-Regular.ttf.sha1
@@ -0,0 +1 @@
+2542883c305f0121e332c658aa8ee22813952fd2
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansKR-Regular.otf.sha1 b/third_party/blimp_fonts/NotoSansKR-Regular.otf.sha1
new file mode 100644
index 0000000..b5396b3
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansKR-Regular.otf.sha1
@@ -0,0 +1 @@
+82e49c4d7e4eced8a0bce49ef901a86459547d8c
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansKaithi-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansKaithi-Regular.ttf.sha1
new file mode 100644
index 0000000..277134f
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansKaithi-Regular.ttf.sha1
@@ -0,0 +1 @@
+7b6c562b4b0ed7891791a39e1a115eb363ac133f
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansKannada-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansKannada-Bold.ttf.sha1
new file mode 100644
index 0000000..2d30174
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansKannada-Bold.ttf.sha1
@@ -0,0 +1 @@
+709a295c58dee0715dbb3c5d797006281afa6f87
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansKannada-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansKannada-Regular.ttf.sha1
new file mode 100644
index 0000000..c000026
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansKannada-Regular.ttf.sha1
@@ -0,0 +1 @@
+d9293ef195260469a8b3e284e9e6c6e919381c19
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansKannadaUI-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansKannadaUI-Bold.ttf.sha1
new file mode 100644
index 0000000..20a8884
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansKannadaUI-Bold.ttf.sha1
@@ -0,0 +1 @@
+0803c674ee4f28199fca9c9624886f3c899a6d1c
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansKannadaUI-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansKannadaUI-Regular.ttf.sha1
new file mode 100644
index 0000000..9e6e64f6
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansKannadaUI-Regular.ttf.sha1
@@ -0,0 +1 @@
+d053741efb996673ba31f1322734148fc95ee13c
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansKayahLi-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansKayahLi-Regular.ttf.sha1
new file mode 100644
index 0000000..ba70921
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansKayahLi-Regular.ttf.sha1
@@ -0,0 +1 @@
+870b4a50663afb8af3f661ebc3e18ca7a6dda8d3
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansKharoshthi-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansKharoshthi-Regular.ttf.sha1
new file mode 100644
index 0000000..4587667
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansKharoshthi-Regular.ttf.sha1
@@ -0,0 +1 @@
+4e09bd089479532dd29d222ad958e58497038b86
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansKhmer-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansKhmer-Bold.ttf.sha1
new file mode 100644
index 0000000..9876e5b
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansKhmer-Bold.ttf.sha1
@@ -0,0 +1 @@
+680eddbf617b19705a0e067e582da240281b599e
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansKhmer-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansKhmer-Regular.ttf.sha1
new file mode 100644
index 0000000..d77a6ac
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansKhmer-Regular.ttf.sha1
@@ -0,0 +1 @@
+0b7a86319c4f2e19b861d0a9acc92b7670245da2
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansKhmerUI-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansKhmerUI-Bold.ttf.sha1
new file mode 100644
index 0000000..036cb9d
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansKhmerUI-Bold.ttf.sha1
@@ -0,0 +1 @@
+377f97bb928e4634e779d30c2791dec8416ea49f
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansKhmerUI-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansKhmerUI-Regular.ttf.sha1
new file mode 100644
index 0000000..626c7f0
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansKhmerUI-Regular.ttf.sha1
@@ -0,0 +1 @@
+cea1075973e5f15a4a5073ef2f46679e62e6e6a1
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansLao-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansLao-Bold.ttf.sha1
new file mode 100644
index 0000000..ff05d6e
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansLao-Bold.ttf.sha1
@@ -0,0 +1 @@
+4fc0c98ee2c4942f44ce6b48b58a49c5cb0c8be0
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansLao-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansLao-Regular.ttf.sha1
new file mode 100644
index 0000000..6c3c40e
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansLao-Regular.ttf.sha1
@@ -0,0 +1 @@
+ad401524474b290c3ae2703e5310e37ef604b58b
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansLaoUI-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansLaoUI-Bold.ttf.sha1
new file mode 100644
index 0000000..60d9cd5
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansLaoUI-Bold.ttf.sha1
@@ -0,0 +1 @@
+c8e61bb2c6484c32f3a6f7a9dc5af6b550f78baf
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansLaoUI-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansLaoUI-Regular.ttf.sha1
new file mode 100644
index 0000000..46d37b2
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansLaoUI-Regular.ttf.sha1
@@ -0,0 +1 @@
+d417ad2d7239079958c786123b885e483d771b26
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansLepcha-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansLepcha-Regular.ttf.sha1
new file mode 100644
index 0000000..a6b40a7
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansLepcha-Regular.ttf.sha1
@@ -0,0 +1 @@
+fdb5fad01f714ad8f84637a2a31db004e6e670c8
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansLimbu-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansLimbu-Regular.ttf.sha1
new file mode 100644
index 0000000..54accd2c
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansLimbu-Regular.ttf.sha1
@@ -0,0 +1 @@
+5a13f322a26cd1247dc8b88056952faad256b6c9
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansLinearB-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansLinearB-Regular.ttf.sha1
new file mode 100644
index 0000000..f73226f
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansLinearB-Regular.ttf.sha1
@@ -0,0 +1 @@
+df9cba01d31a0309b9c2a0e9f01f2aec5ffe70da
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansLisu-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansLisu-Regular.ttf.sha1
new file mode 100644
index 0000000..bb0e9b4
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansLisu-Regular.ttf.sha1
@@ -0,0 +1 @@
+bf95b975fb4f961167c71c5836ea7a4660931b03
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansLycian-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansLycian-Regular.ttf.sha1
new file mode 100644
index 0000000..e069c167
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansLycian-Regular.ttf.sha1
@@ -0,0 +1 @@
+da92da0f24ad080c36190c2f18f942daaad2868e
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansLydian-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansLydian-Regular.ttf.sha1
new file mode 100644
index 0000000..ee5710b
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansLydian-Regular.ttf.sha1
@@ -0,0 +1 @@
+a2f852b9b962d07e72af6304299ef0d435f05bd1
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansMalayalam-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansMalayalam-Bold.ttf.sha1
new file mode 100644
index 0000000..6d6fb1d
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansMalayalam-Bold.ttf.sha1
@@ -0,0 +1 @@
+e020a0103265f2c1dd71261bb6dfdd0ad18bbeab
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansMalayalam-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansMalayalam-Regular.ttf.sha1
new file mode 100644
index 0000000..3c93dd9
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansMalayalam-Regular.ttf.sha1
@@ -0,0 +1 @@
+0e3b4ad160c5e8ffdbe262492b33d2f425e836dc
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansMalayalamUI-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansMalayalamUI-Bold.ttf.sha1
new file mode 100644
index 0000000..8108cdb
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansMalayalamUI-Bold.ttf.sha1
@@ -0,0 +1 @@
+00d98bf5b71b2c2715f9fb04168129b7b19d9385
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansMalayalamUI-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansMalayalamUI-Regular.ttf.sha1
new file mode 100644
index 0000000..713700a
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansMalayalamUI-Regular.ttf.sha1
@@ -0,0 +1 @@
+67d3ad87a313ae88628c67c89b03624aa9b6649f
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansMandaic-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansMandaic-Regular.ttf.sha1
new file mode 100644
index 0000000..6a8c1984
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansMandaic-Regular.ttf.sha1
@@ -0,0 +1 @@
+370382717a5a166f90343f68f365d5c932f768f5
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansMeeteiMayek-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansMeeteiMayek-Regular.ttf.sha1
new file mode 100644
index 0000000..9fd6166
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansMeeteiMayek-Regular.ttf.sha1
@@ -0,0 +1 @@
+0e3e035dcb6244602125b17e3f374e79583088b7
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansMongolian-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansMongolian-Regular.ttf.sha1
new file mode 100644
index 0000000..8c3bea8
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansMongolian-Regular.ttf.sha1
@@ -0,0 +1 @@
+514c23daa829d986fb83ce1db7e0db97b6983a72
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansMyanmar-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansMyanmar-Bold.ttf.sha1
new file mode 100644
index 0000000..a77727e
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansMyanmar-Bold.ttf.sha1
@@ -0,0 +1 @@
+eb1bc4722a6e4c62b2d746a6d6a2f90de480821f
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansMyanmar-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansMyanmar-Regular.ttf.sha1
new file mode 100644
index 0000000..b3056c0
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansMyanmar-Regular.ttf.sha1
@@ -0,0 +1 @@
+0469de145d807dc3a7565f2d7da1867042ec8e7a
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansMyanmarUI-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansMyanmarUI-Bold.ttf.sha1
new file mode 100644
index 0000000..c9f06d0
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansMyanmarUI-Bold.ttf.sha1
@@ -0,0 +1 @@
+594b7d3d54bfe2edbf073f044bcba39b9a75a8bf
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansMyanmarUI-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansMyanmarUI-Regular.ttf.sha1
new file mode 100644
index 0000000..a48da98
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansMyanmarUI-Regular.ttf.sha1
@@ -0,0 +1 @@
+42a45af174c35216b596085e646425a768717952
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansNKo-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansNKo-Regular.ttf.sha1
new file mode 100644
index 0000000..29bbdf5
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansNKo-Regular.ttf.sha1
@@ -0,0 +1 @@
+335ea7c2d3be7d88a1ebfaa0de41336037ec2595
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansNewTaiLue-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansNewTaiLue-Regular.ttf.sha1
new file mode 100644
index 0000000..3c52e91
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansNewTaiLue-Regular.ttf.sha1
@@ -0,0 +1 @@
+81a9a9c1d9a4c29b41bca01418108d52216b5559
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansOgham-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansOgham-Regular.ttf.sha1
new file mode 100644
index 0000000..abec25e
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansOgham-Regular.ttf.sha1
@@ -0,0 +1 @@
+18f2332625c8aadb2e0359164a23ea60bf3bb306
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansOlChiki-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansOlChiki-Regular.ttf.sha1
new file mode 100644
index 0000000..6cdd6d60
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansOlChiki-Regular.ttf.sha1
@@ -0,0 +1 @@
+0ece2465241ff335139f95589d55f0e42274f81b
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansOldItalic-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansOldItalic-Regular.ttf.sha1
new file mode 100644
index 0000000..f53ed579
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansOldItalic-Regular.ttf.sha1
@@ -0,0 +1 @@
+e92907af55b187bb9ebb1e2fbbb1341c07d9f01f
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansOldPersian-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansOldPersian-Regular.ttf.sha1
new file mode 100644
index 0000000..c24c8e3b
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansOldPersian-Regular.ttf.sha1
@@ -0,0 +1 @@
+f3169cd736266f67a6909d588de7dc77389cb219
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansOldSouthArabian-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansOldSouthArabian-Regular.ttf.sha1
new file mode 100644
index 0000000..ff115366
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansOldSouthArabian-Regular.ttf.sha1
@@ -0,0 +1 @@
+a858eff985bb1b94112bc38ce783594c4f2678a7
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansOldTurkic-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansOldTurkic-Regular.ttf.sha1
new file mode 100644
index 0000000..149144a1
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansOldTurkic-Regular.ttf.sha1
@@ -0,0 +1 @@
+65662c0178078729fec1dd0e74549e687ea09ed7
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansOriya-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansOriya-Bold.ttf.sha1
new file mode 100644
index 0000000..7e7e7c7
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansOriya-Bold.ttf.sha1
@@ -0,0 +1 @@
+05f5bae5d05f853a6cc4b3a24849aec652c90718
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansOriya-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansOriya-Regular.ttf.sha1
new file mode 100644
index 0000000..712235d
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansOriya-Regular.ttf.sha1
@@ -0,0 +1 @@
+b0635a39a23b71f88085c403b3aef269bf7b58c4
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansOriyaUI-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansOriyaUI-Bold.ttf.sha1
new file mode 100644
index 0000000..98c0488
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansOriyaUI-Bold.ttf.sha1
@@ -0,0 +1 @@
+541170c878075daadfcf1d2a792b6a7312fd4096
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansOriyaUI-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansOriyaUI-Regular.ttf.sha1
new file mode 100644
index 0000000..c0e2598a
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansOriyaUI-Regular.ttf.sha1
@@ -0,0 +1 @@
+931f507e2ed32d87284c8109ffe027f1e795aaed
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansOsmanya-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansOsmanya-Regular.ttf.sha1
new file mode 100644
index 0000000..0c6e3681
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansOsmanya-Regular.ttf.sha1
@@ -0,0 +1 @@
+ec7b494463ee46dffae8e7d4e234c43dc004ec60
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansPhagsPa-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansPhagsPa-Regular.ttf.sha1
new file mode 100644
index 0000000..6fba4c3
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansPhagsPa-Regular.ttf.sha1
@@ -0,0 +1 @@
+feead638b84c697d770d49c18e6e0a8fdfa62ce9
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansPhoenician-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansPhoenician-Regular.ttf.sha1
new file mode 100644
index 0000000..3dead6e
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansPhoenician-Regular.ttf.sha1
@@ -0,0 +1 @@
+59f539be1b6bc8b4e86be3437e1693cc896948c0
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansRejang-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansRejang-Regular.ttf.sha1
new file mode 100644
index 0000000..f917711
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansRejang-Regular.ttf.sha1
@@ -0,0 +1 @@
+34c7b71548c9b532167b08facb1c871bb4196056
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansRunic-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansRunic-Regular.ttf.sha1
new file mode 100644
index 0000000..ca2daa76
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansRunic-Regular.ttf.sha1
@@ -0,0 +1 @@
+78e7364b4d720528c62ef2038154c78e92c17444
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansSC-Regular.otf.sha1 b/third_party/blimp_fonts/NotoSansSC-Regular.otf.sha1
new file mode 100644
index 0000000..e74636c
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansSC-Regular.otf.sha1
@@ -0,0 +1 @@
+fd0e99f14fe21661a0d528fb9882c833979f3386
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansSamaritan-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansSamaritan-Regular.ttf.sha1
new file mode 100644
index 0000000..5172b5d
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansSamaritan-Regular.ttf.sha1
@@ -0,0 +1 @@
+91bbc172f85eb4f3ae37a8b98128d3ea5dc0e7cf
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansSaurashtra-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansSaurashtra-Regular.ttf.sha1
new file mode 100644
index 0000000..b677b37
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansSaurashtra-Regular.ttf.sha1
@@ -0,0 +1 @@
+6e338de732880469c09e61f5de509189f05225f3
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansShavian-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansShavian-Regular.ttf.sha1
new file mode 100644
index 0000000..bdaf32b
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansShavian-Regular.ttf.sha1
@@ -0,0 +1 @@
+eb7afe2ae1fd731c6d7e061403589a48df76da0d
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansSinhala-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansSinhala-Bold.ttf.sha1
new file mode 100644
index 0000000..0be0a3d
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansSinhala-Bold.ttf.sha1
@@ -0,0 +1 @@
+ff78425befdaf0bdd24b97a075e66819665ab257
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansSinhala-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansSinhala-Regular.ttf.sha1
new file mode 100644
index 0000000..08a75bb2
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansSinhala-Regular.ttf.sha1
@@ -0,0 +1 @@
+c3dcca37adf3b98add716876f93e30e7d28d5730
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansSundanese-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansSundanese-Regular.ttf.sha1
new file mode 100644
index 0000000..74936e46
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansSundanese-Regular.ttf.sha1
@@ -0,0 +1 @@
+b8990d9647be086ff2ef3c2eeae53536ec3cd98f
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansSylotiNagri-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansSylotiNagri-Regular.ttf.sha1
new file mode 100644
index 0000000..133b5f5
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansSylotiNagri-Regular.ttf.sha1
@@ -0,0 +1 @@
+a862f457f067fde48161f6865d9418643b37c029
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansSymbols-Regular-Subsetted.ttf.sha1 b/third_party/blimp_fonts/NotoSansSymbols-Regular-Subsetted.ttf.sha1
new file mode 100644
index 0000000..1f18c96
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansSymbols-Regular-Subsetted.ttf.sha1
@@ -0,0 +1 @@
+e5e8d7c88162df4cfe8cd6405bafa3d3b1cc3166
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansSymbols-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansSymbols-Regular.ttf.sha1
new file mode 100644
index 0000000..7cd8f19
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansSymbols-Regular.ttf.sha1
@@ -0,0 +1 @@
+8b4ac8bf6c801dd39ccadde9f12bade82615f35a
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansSyriacEastern-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansSyriacEastern-Regular.ttf.sha1
new file mode 100644
index 0000000..35096cb
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansSyriacEastern-Regular.ttf.sha1
@@ -0,0 +1 @@
+fdba9e07d99e4a95d248fa7ef9eb96e969859e62
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansSyriacEstrangela-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansSyriacEstrangela-Regular.ttf.sha1
new file mode 100644
index 0000000..e54fa50
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansSyriacEstrangela-Regular.ttf.sha1
@@ -0,0 +1 @@
+7834dfb6bfd02a0b35bcbc23b6ab1d0caa681af6
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansSyriacWestern-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansSyriacWestern-Regular.ttf.sha1
new file mode 100644
index 0000000..511afba4
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansSyriacWestern-Regular.ttf.sha1
@@ -0,0 +1 @@
+15443875b09c934e251da0c8653a12a44264278a
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansTC-Regular.otf.sha1 b/third_party/blimp_fonts/NotoSansTC-Regular.otf.sha1
new file mode 100644
index 0000000..4cb9f878
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansTC-Regular.otf.sha1
@@ -0,0 +1 @@
+2c4bf5559ca000201c572fc05d46d7b9b4ac9de4
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansTagalog-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansTagalog-Regular.ttf.sha1
new file mode 100644
index 0000000..1b6b6db
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansTagalog-Regular.ttf.sha1
@@ -0,0 +1 @@
+c11711b924f9c0b20716cb82625e4fada3d0c33b
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansTagbanwa-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansTagbanwa-Regular.ttf.sha1
new file mode 100644
index 0000000..082e917
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansTagbanwa-Regular.ttf.sha1
@@ -0,0 +1 @@
+e933217646423187bac1196bd2c1ab3ba48adf4d
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansTaiLe-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansTaiLe-Regular.ttf.sha1
new file mode 100644
index 0000000..ea0a2fe
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansTaiLe-Regular.ttf.sha1
@@ -0,0 +1 @@
+155df213be34c45269925ea1581354ec02179c03
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansTaiTham-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansTaiTham-Regular.ttf.sha1
new file mode 100644
index 0000000..fd3c0a0
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansTaiTham-Regular.ttf.sha1
@@ -0,0 +1 @@
+0d1bf0f83c66ea3b92deaaeafa3bd5466a54ee7f
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansTaiViet-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansTaiViet-Regular.ttf.sha1
new file mode 100644
index 0000000..b79c3d4
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansTaiViet-Regular.ttf.sha1
@@ -0,0 +1 @@
+508064c86453713ed578ab1428b2686a813501f7
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansTamil-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansTamil-Bold.ttf.sha1
new file mode 100644
index 0000000..ef28710
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansTamil-Bold.ttf.sha1
@@ -0,0 +1 @@
+8f3644c86def39f6bb79631b28ef1174108a63fa
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansTamil-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansTamil-Regular.ttf.sha1
new file mode 100644
index 0000000..feb6fc8
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansTamil-Regular.ttf.sha1
@@ -0,0 +1 @@
+49635e1da5596cd05c764398dfb347dc6ae81ea0
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansTamilUI-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansTamilUI-Bold.ttf.sha1
new file mode 100644
index 0000000..f334b54c
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansTamilUI-Bold.ttf.sha1
@@ -0,0 +1 @@
+89142481ceb5891f31f5e56420299e32ffd466a2
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansTamilUI-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansTamilUI-Regular.ttf.sha1
new file mode 100644
index 0000000..44a87b7
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansTamilUI-Regular.ttf.sha1
@@ -0,0 +1 @@
+7a05209d7198ca0b0a324770f74998e312e5a57f
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansTelugu-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansTelugu-Bold.ttf.sha1
new file mode 100644
index 0000000..70cf710
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansTelugu-Bold.ttf.sha1
@@ -0,0 +1 @@
+14a8d5b42b1670b0b1673ef92e562f16b6b4d5f5
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansTelugu-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansTelugu-Regular.ttf.sha1
new file mode 100644
index 0000000..d45d2091
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansTelugu-Regular.ttf.sha1
@@ -0,0 +1 @@
+439d61e6aacbf4ce5826b863d5075ce9bbbdae34
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansTeluguUI-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansTeluguUI-Bold.ttf.sha1
new file mode 100644
index 0000000..c2187e21
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansTeluguUI-Bold.ttf.sha1
@@ -0,0 +1 @@
+5af88b54631e6b70162ae063903955bbe3cd2f8b
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansTeluguUI-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansTeluguUI-Regular.ttf.sha1
new file mode 100644
index 0000000..5d7b35b5
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansTeluguUI-Regular.ttf.sha1
@@ -0,0 +1 @@
+923e09cbca1ad94f2c0ac9932d9b5db784fcfa25
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansThaana-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansThaana-Bold.ttf.sha1
new file mode 100644
index 0000000..103cea2
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansThaana-Bold.ttf.sha1
@@ -0,0 +1 @@
+9585cb2672e485f86216870a450e22ef9125fd33
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansThaana-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansThaana-Regular.ttf.sha1
new file mode 100644
index 0000000..e475a9d
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansThaana-Regular.ttf.sha1
@@ -0,0 +1 @@
+bc685050058ca472fdd67f8a7a43699252bbf3ef
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansThai-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansThai-Bold.ttf.sha1
new file mode 100644
index 0000000..f97107a
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansThai-Bold.ttf.sha1
@@ -0,0 +1 @@
+f9332a74751a1c9a8ae5915a094279e8a716387f
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansThai-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansThai-Regular.ttf.sha1
new file mode 100644
index 0000000..c91bff1e
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansThai-Regular.ttf.sha1
@@ -0,0 +1 @@
+c4fa534578248260321cc8da6a090dc021c47126
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansThaiUI-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansThaiUI-Bold.ttf.sha1
new file mode 100644
index 0000000..b6962b8
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansThaiUI-Bold.ttf.sha1
@@ -0,0 +1 @@
+a3d4349b3cf5e8b737ebad1eea37f86f3274749d
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansThaiUI-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansThaiUI-Regular.ttf.sha1
new file mode 100644
index 0000000..7b7a483
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansThaiUI-Regular.ttf.sha1
@@ -0,0 +1 @@
+947be6d319b4a67796fe3410d64d365ff1bc5d7c
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansTibetan-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansTibetan-Regular.ttf.sha1
new file mode 100644
index 0000000..dc5c23c
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansTibetan-Regular.ttf.sha1
@@ -0,0 +1 @@
+4b769855dc15edebf6d6e13afdc044c96c98c680
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansTifinagh-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansTifinagh-Regular.ttf.sha1
new file mode 100644
index 0000000..42d4b27bb
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansTifinagh-Regular.ttf.sha1
@@ -0,0 +1 @@
+e8600002e8d4e60a43c9c4084b527aa25d8ed1c4
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansUI-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSansUI-Bold.ttf.sha1
new file mode 100644
index 0000000..488e798
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansUI-Bold.ttf.sha1
@@ -0,0 +1 @@
+f8c365a95bdd3a4d60bdb6c43995660223afaee0
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansUI-BoldItalic.ttf.sha1 b/third_party/blimp_fonts/NotoSansUI-BoldItalic.ttf.sha1
new file mode 100644
index 0000000..0601892
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansUI-BoldItalic.ttf.sha1
@@ -0,0 +1 @@
+efe7c88a6fb0c7711cc29ec4206c93dba319150b
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansUI-Italic.ttf.sha1 b/third_party/blimp_fonts/NotoSansUI-Italic.ttf.sha1
new file mode 100644
index 0000000..84f7ac5
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansUI-Italic.ttf.sha1
@@ -0,0 +1 @@
+9cf96f38e211a21d71a2c21f2c5e6e2ee34024eb
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansUI-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansUI-Regular.ttf.sha1
new file mode 100644
index 0000000..ef4bb52
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansUI-Regular.ttf.sha1
@@ -0,0 +1 @@
+6930143f0077b8e43b0677df8739e7a3c30caa69
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansUgaritic-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansUgaritic-Regular.ttf.sha1
new file mode 100644
index 0000000..6cf0e7d
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansUgaritic-Regular.ttf.sha1
@@ -0,0 +1 @@
+8f8ebc30c66a06dbe2997b1a07e0668e105ed067
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansVai-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansVai-Regular.ttf.sha1
new file mode 100644
index 0000000..1502e6a
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansVai-Regular.ttf.sha1
@@ -0,0 +1 @@
+4ce9208384bfb5a21767ab85311837277d8b9978
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSansYi-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSansYi-Regular.ttf.sha1
new file mode 100644
index 0000000..66d1962
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSansYi-Regular.ttf.sha1
@@ -0,0 +1 @@
+ea20e1e87a943b37262ab10e3003525861d95d60
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSerif-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSerif-Bold.ttf.sha1
new file mode 100644
index 0000000..f9bf271
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSerif-Bold.ttf.sha1
@@ -0,0 +1 @@
+82b243fd7bdba883b5a6a73ac6d68b3da1b3b97b
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSerif-BoldItalic.ttf.sha1 b/third_party/blimp_fonts/NotoSerif-BoldItalic.ttf.sha1
new file mode 100644
index 0000000..6800f8f9
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSerif-BoldItalic.ttf.sha1
@@ -0,0 +1 @@
+39141b42604ed41d8a6d85366c775cded1d6752c
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSerif-Italic.ttf.sha1 b/third_party/blimp_fonts/NotoSerif-Italic.ttf.sha1
new file mode 100644
index 0000000..fccb33ec
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSerif-Italic.ttf.sha1
@@ -0,0 +1 @@
+2e2e8b537d7d86e1f5c2e0d3338720d0d853c09f
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSerif-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSerif-Regular.ttf.sha1
new file mode 100644
index 0000000..d77fdd1
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSerif-Regular.ttf.sha1
@@ -0,0 +1 @@
+8608d1f96bb9482ea8942ebd6545cdb9e2921ed9
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSerifArmenian-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSerifArmenian-Bold.ttf.sha1
new file mode 100644
index 0000000..12b87be
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSerifArmenian-Bold.ttf.sha1
@@ -0,0 +1 @@
+d9952506333e6076a6ad1fe237b590d3a124e3da
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSerifArmenian-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSerifArmenian-Regular.ttf.sha1
new file mode 100644
index 0000000..e511251
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSerifArmenian-Regular.ttf.sha1
@@ -0,0 +1 @@
+54fffecfd5fb8f33fa0b88d752a532dd767b8d90
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSerifGeorgian-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSerifGeorgian-Bold.ttf.sha1
new file mode 100644
index 0000000..7a018ab
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSerifGeorgian-Bold.ttf.sha1
@@ -0,0 +1 @@
+fd2cc6de838f77ac7692725d249e29443560a8bc
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSerifGeorgian-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSerifGeorgian-Regular.ttf.sha1
new file mode 100644
index 0000000..f7247c43
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSerifGeorgian-Regular.ttf.sha1
@@ -0,0 +1 @@
+16c1f30c13622a6a080d910ea5db3fa7815c11e8
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSerifKhmer-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSerifKhmer-Bold.ttf.sha1
new file mode 100644
index 0000000..31bc23f
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSerifKhmer-Bold.ttf.sha1
@@ -0,0 +1 @@
+fcb63dfd57dc35d81eef4d9b91598f6e7e93000c
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSerifKhmer-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSerifKhmer-Regular.ttf.sha1
new file mode 100644
index 0000000..e778e05
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSerifKhmer-Regular.ttf.sha1
@@ -0,0 +1 @@
+a4000457e9f5db03fd4161ed420b9e426bdb0d87
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSerifLao-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSerifLao-Bold.ttf.sha1
new file mode 100644
index 0000000..911d2960
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSerifLao-Bold.ttf.sha1
@@ -0,0 +1 @@
+ab67b00c5092b0094af2ad54cfdb9018b8299ab4
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSerifLao-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSerifLao-Regular.ttf.sha1
new file mode 100644
index 0000000..a809edda
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSerifLao-Regular.ttf.sha1
@@ -0,0 +1 @@
+cca411f1874c4a03386078b0712ca849e8a7f9bf
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSerifThai-Bold.ttf.sha1 b/third_party/blimp_fonts/NotoSerifThai-Bold.ttf.sha1
new file mode 100644
index 0000000..668c5a31
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSerifThai-Bold.ttf.sha1
@@ -0,0 +1 @@
+ced1a6c362d127948b5a4d36548732f9de033c1d
\ No newline at end of file
diff --git a/third_party/blimp_fonts/NotoSerifThai-Regular.ttf.sha1 b/third_party/blimp_fonts/NotoSerifThai-Regular.ttf.sha1
new file mode 100644
index 0000000..c5831fcc
--- /dev/null
+++ b/third_party/blimp_fonts/NotoSerifThai-Regular.ttf.sha1
@@ -0,0 +1 @@
+8db9bbb5f1d3f71829a4130d953b676c8bdf0625
\ No newline at end of file
diff --git a/third_party/blimp_fonts/OWNERS b/third_party/blimp_fonts/OWNERS
new file mode 100644
index 0000000..d7dfb92
--- /dev/null
+++ b/third_party/blimp_fonts/OWNERS
@@ -0,0 +1,5 @@
+dtrainor@chromium.org
+haibinlu@chromium.org
+kmarshall@chromium.org
+nyquist@chromium.org
+wez@chromium.org
diff --git a/third_party/blimp_fonts/README.chromium b/third_party/blimp_fonts/README.chromium
new file mode 100644
index 0000000..380be7c8
--- /dev/null
+++ b/third_party/blimp_fonts/README.chromium
@@ -0,0 +1,49 @@
+Name: blimp_fonts
+URL: See below
+Version: unknown
+License: Apache Version 2.0 and SIL Open Font License, Version 1.1
+Security Critical: yes
+
+Description:
+A collection of fonts that are necessary to bundle with the blimp engine to be
+able to render the correct fonts for different clients.
+
+How to update:
+See //blimp/docs/fonts.md.
+
+Local Modifications:
+Not all files from the external repositories are used.
+- *.otf, *.ttf: From the various repositories.
+- .gitignore:   Added.
+- BUILD.gn:     Added.
+- LICENSE:      Added.
+- LICENSE.*:    Extracted from license files in the various repositories.
+- README.md:    Added.
+- fonts.xml:    From this repository:
+                https://android.googlesource.com/platform/frameworks/base.git
+
+Fonts are pulled from the following repositories:
+- Git repo: https://android.googlesource.com/platform/frameworks/base.git
+  Commit: 6a278db4c4a144829353e81420f28dcf2105f767
+  Directory: data/fonts/
+- Git repo: https://android.googlesource.com/platform/external/noto-fonts.git
+  Commit: eb0883544dd538edbfb52cce9a2481509ca5ee9f
+  Directory: cjk/, other/
+- Git repo: https://android.googlesource.com/platform/external/roboto-fonts.git
+  Commit: f5cf79102af594c746627b392b4f98eedd254571
+  Directory: .
+- Git repo: https://android.googlesource.com/platform/external/google-fonts/dancing-script.git
+  Commit: 7b6623bd54cee3e48ae8a4f477f616366643cc78
+  Directory: .
+- Git repo: https://android.googlesource.com/platform/external/google-fonts/cutive-mono.git
+  Commit: bce2136662854076023066602526ba299e6556b2
+  Directory: .
+- Git repo: https://android.googlesource.com/platform/external/google-fonts/coming-soon.git
+  Commit: 2c5cb418c690815545bbb0316eae5fd33b9fc859
+  Directory: .
+- Git repo: https://android.googlesource.com/platform/external/google-fonts/carrois-gothic-sc.git
+  Commit: 0062a10458d4c357f3082d66bcb129d11913aaae
+  Directory: .
+- Git repo: https://android.googlesource.com/platform/external/naver-fonts.git
+  Commit: 91e6e9f94d1d769a8f742649674149ba98ce7d45
+  Directory: .
diff --git a/third_party/blimp_fonts/Roboto-Black.ttf.sha1 b/third_party/blimp_fonts/Roboto-Black.ttf.sha1
new file mode 100644
index 0000000..6ee8a62
--- /dev/null
+++ b/third_party/blimp_fonts/Roboto-Black.ttf.sha1
@@ -0,0 +1 @@
+d3ecadec65a1ed2765a0f6b47b6bf2000e8491d5
\ No newline at end of file
diff --git a/third_party/blimp_fonts/Roboto-BlackItalic.ttf.sha1 b/third_party/blimp_fonts/Roboto-BlackItalic.ttf.sha1
new file mode 100644
index 0000000..9b159021
--- /dev/null
+++ b/third_party/blimp_fonts/Roboto-BlackItalic.ttf.sha1
@@ -0,0 +1 @@
+82960419d7bdadc88fa3a94a016bd93538666769
\ No newline at end of file
diff --git a/third_party/blimp_fonts/Roboto-Bold.ttf.sha1 b/third_party/blimp_fonts/Roboto-Bold.ttf.sha1
new file mode 100644
index 0000000..59a0f18a
--- /dev/null
+++ b/third_party/blimp_fonts/Roboto-Bold.ttf.sha1
@@ -0,0 +1 @@
+ce209e7a825828599429bf4d0d134272d20adf3d
\ No newline at end of file
diff --git a/third_party/blimp_fonts/Roboto-BoldItalic.ttf.sha1 b/third_party/blimp_fonts/Roboto-BoldItalic.ttf.sha1
new file mode 100644
index 0000000..20dad84
--- /dev/null
+++ b/third_party/blimp_fonts/Roboto-BoldItalic.ttf.sha1
@@ -0,0 +1 @@
+0982eed1d138c584407ac6dd04448eb643bef2b0
\ No newline at end of file
diff --git a/third_party/blimp_fonts/Roboto-Italic.ttf.sha1 b/third_party/blimp_fonts/Roboto-Italic.ttf.sha1
new file mode 100644
index 0000000..c875f750
--- /dev/null
+++ b/third_party/blimp_fonts/Roboto-Italic.ttf.sha1
@@ -0,0 +1 @@
+d701e916ba7ef08efef9b924b0e220ac0623a75a
\ No newline at end of file
diff --git a/third_party/blimp_fonts/Roboto-Light.ttf.sha1 b/third_party/blimp_fonts/Roboto-Light.ttf.sha1
new file mode 100644
index 0000000..c62d9d0
--- /dev/null
+++ b/third_party/blimp_fonts/Roboto-Light.ttf.sha1
@@ -0,0 +1 @@
+1ce31afef046a5f38dbcb6e212d827eb69d56569
\ No newline at end of file
diff --git a/third_party/blimp_fonts/Roboto-LightItalic.ttf.sha1 b/third_party/blimp_fonts/Roboto-LightItalic.ttf.sha1
new file mode 100644
index 0000000..5aac8f52
--- /dev/null
+++ b/third_party/blimp_fonts/Roboto-LightItalic.ttf.sha1
@@ -0,0 +1 @@
+a2ec190ac6d148c53128eb1ed61c638b3006ed5d
\ No newline at end of file
diff --git a/third_party/blimp_fonts/Roboto-Medium.ttf.sha1 b/third_party/blimp_fonts/Roboto-Medium.ttf.sha1
new file mode 100644
index 0000000..ebce56d
--- /dev/null
+++ b/third_party/blimp_fonts/Roboto-Medium.ttf.sha1
@@ -0,0 +1 @@
+92d678bb9f3c07deabfaa4e62b9de0aeab45888a
\ No newline at end of file
diff --git a/third_party/blimp_fonts/Roboto-MediumItalic.ttf.sha1 b/third_party/blimp_fonts/Roboto-MediumItalic.ttf.sha1
new file mode 100644
index 0000000..943de92
--- /dev/null
+++ b/third_party/blimp_fonts/Roboto-MediumItalic.ttf.sha1
@@ -0,0 +1 @@
+4bc89e68bb659347904cae4543e9e22eb06e43dc
\ No newline at end of file
diff --git a/third_party/blimp_fonts/Roboto-Regular.ttf.sha1 b/third_party/blimp_fonts/Roboto-Regular.ttf.sha1
new file mode 100644
index 0000000..ce967ad
--- /dev/null
+++ b/third_party/blimp_fonts/Roboto-Regular.ttf.sha1
@@ -0,0 +1 @@
+9475dcae6d4d43961baecbe3049d70eaef1ba2e2
\ No newline at end of file
diff --git a/third_party/blimp_fonts/Roboto-Thin.ttf.sha1 b/third_party/blimp_fonts/Roboto-Thin.ttf.sha1
new file mode 100644
index 0000000..2c13ddc
--- /dev/null
+++ b/third_party/blimp_fonts/Roboto-Thin.ttf.sha1
@@ -0,0 +1 @@
+a1d984651a0481e5232ee925e2c37895a375d11c
\ No newline at end of file
diff --git a/third_party/blimp_fonts/Roboto-ThinItalic.ttf.sha1 b/third_party/blimp_fonts/Roboto-ThinItalic.ttf.sha1
new file mode 100644
index 0000000..dfdff321
--- /dev/null
+++ b/third_party/blimp_fonts/Roboto-ThinItalic.ttf.sha1
@@ -0,0 +1 @@
+e828ca5fede8ae7dc78a09a718506412fe8851a7
\ No newline at end of file
diff --git a/third_party/blimp_fonts/RobotoCondensed-Bold.ttf.sha1 b/third_party/blimp_fonts/RobotoCondensed-Bold.ttf.sha1
new file mode 100644
index 0000000..a28bd78
--- /dev/null
+++ b/third_party/blimp_fonts/RobotoCondensed-Bold.ttf.sha1
@@ -0,0 +1 @@
+ddd594ab7c3b7e2a0a36fd812afe2ec40c509fce
\ No newline at end of file
diff --git a/third_party/blimp_fonts/RobotoCondensed-BoldItalic.ttf.sha1 b/third_party/blimp_fonts/RobotoCondensed-BoldItalic.ttf.sha1
new file mode 100644
index 0000000..7987f563
--- /dev/null
+++ b/third_party/blimp_fonts/RobotoCondensed-BoldItalic.ttf.sha1
@@ -0,0 +1 @@
+ca1359cb1d5d82a8d7956e4b469bd031e63b5ab3
\ No newline at end of file
diff --git a/third_party/blimp_fonts/RobotoCondensed-Italic.ttf.sha1 b/third_party/blimp_fonts/RobotoCondensed-Italic.ttf.sha1
new file mode 100644
index 0000000..00db36f
--- /dev/null
+++ b/third_party/blimp_fonts/RobotoCondensed-Italic.ttf.sha1
@@ -0,0 +1 @@
+fd09eff1019edb33d3d3a4af9c9e8efd109eff06
\ No newline at end of file
diff --git a/third_party/blimp_fonts/RobotoCondensed-Light.ttf.sha1 b/third_party/blimp_fonts/RobotoCondensed-Light.ttf.sha1
new file mode 100644
index 0000000..6038de8
--- /dev/null
+++ b/third_party/blimp_fonts/RobotoCondensed-Light.ttf.sha1
@@ -0,0 +1 @@
+810a20524f675f6633de3a6ee0a5cdd5741c5139
\ No newline at end of file
diff --git a/third_party/blimp_fonts/RobotoCondensed-LightItalic.ttf.sha1 b/third_party/blimp_fonts/RobotoCondensed-LightItalic.ttf.sha1
new file mode 100644
index 0000000..af7a5747
--- /dev/null
+++ b/third_party/blimp_fonts/RobotoCondensed-LightItalic.ttf.sha1
@@ -0,0 +1 @@
+66891ba5c00b998aa4796f95191b2d3864e7d07a
\ No newline at end of file
diff --git a/third_party/blimp_fonts/RobotoCondensed-Regular.ttf.sha1 b/third_party/blimp_fonts/RobotoCondensed-Regular.ttf.sha1
new file mode 100644
index 0000000..4cb0246
--- /dev/null
+++ b/third_party/blimp_fonts/RobotoCondensed-Regular.ttf.sha1
@@ -0,0 +1 @@
+fb9c9c896f5cc2b6b90a8359ce213144bb0716f1
\ No newline at end of file
diff --git a/third_party/blimp_fonts/fonts.xml b/third_party/blimp_fonts/fonts.xml
new file mode 100644
index 0000000..dbe81fa
--- /dev/null
+++ b/third_party/blimp_fonts/fonts.xml
@@ -0,0 +1,371 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    NOTE: this is the newer (L) version of the system font configuration,
+    supporting richer weight selection. Some apps will expect the older
+    version, so please keep system_fonts.xml and fallback_fonts.xml in sync
+    with any changes, even though framework will only read this file.
+
+    All fonts withohut names are added to the default list. Fonts are chosen
+    based on a match: full BCP-47 language tag including script, then just
+    language, and finally order (the first font containing the glyph).
+
+    Order of appearance is also the tiebreaker for weight matching. This is
+    the reason why the 900 weights of Roboto precede the 700 weights - we
+    prefer the former when an 800 weight is requested. Since bold spans
+    effectively add 300 to the weight, this ensures that 900 is the bold
+    paired with the 500 weight, ensuring adequate contrast.
+-->
+<familyset version="22">
+    <!-- first font is default -->
+    <family name="sans-serif">
+        <font weight="100" style="normal">Roboto-Thin.ttf</font>
+        <font weight="100" style="italic">Roboto-ThinItalic.ttf</font>
+        <font weight="300" style="normal">Roboto-Light.ttf</font>
+        <font weight="300" style="italic">Roboto-LightItalic.ttf</font>
+        <font weight="400" style="normal">Roboto-Regular.ttf</font>
+        <font weight="400" style="italic">Roboto-Italic.ttf</font>
+        <font weight="500" style="normal">Roboto-Medium.ttf</font>
+        <font weight="500" style="italic">Roboto-MediumItalic.ttf</font>
+        <font weight="900" style="normal">Roboto-Black.ttf</font>
+        <font weight="900" style="italic">Roboto-BlackItalic.ttf</font>
+        <font weight="700" style="normal">Roboto-Bold.ttf</font>
+        <font weight="700" style="italic">Roboto-BoldItalic.ttf</font>
+    </family>
+
+    <!-- Note that aliases must come after the fonts they reference. -->
+    <alias name="sans-serif-thin" to="sans-serif" weight="100" />
+    <alias name="sans-serif-light" to="sans-serif" weight="300" />
+    <alias name="sans-serif-medium" to="sans-serif" weight="500" />
+    <alias name="sans-serif-black" to="sans-serif" weight="900" />
+    <alias name="arial" to="sans-serif" />
+    <alias name="helvetica" to="sans-serif" />
+    <alias name="tahoma" to="sans-serif" />
+    <alias name="verdana" to="sans-serif" />
+
+    <family name="sans-serif-condensed">
+        <font weight="300" style="normal">RobotoCondensed-Light.ttf</font>
+        <font weight="300" style="italic">RobotoCondensed-LightItalic.ttf</font>
+        <font weight="400" style="normal">RobotoCondensed-Regular.ttf</font>
+        <font weight="400" style="italic">RobotoCondensed-Italic.ttf</font>
+        <font weight="700" style="normal">RobotoCondensed-Bold.ttf</font>
+        <font weight="700" style="italic">RobotoCondensed-BoldItalic.ttf</font>
+    </family>
+    <alias name="sans-serif-condensed-light" to="sans-serif-condensed" weight="300" />
+
+    <family name="serif">
+        <font weight="400" style="normal">NotoSerif-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSerif-Bold.ttf</font>
+        <font weight="400" style="italic">NotoSerif-Italic.ttf</font>
+        <font weight="700" style="italic">NotoSerif-BoldItalic.ttf</font>
+    </family>
+    <alias name="times" to="serif" />
+    <alias name="times new roman" to="serif" />
+    <alias name="palatino" to="serif" />
+    <alias name="georgia" to="serif" />
+    <alias name="baskerville" to="serif" />
+    <alias name="goudy" to="serif" />
+    <alias name="fantasy" to="serif" />
+    <alias name="ITC Stone Serif" to="serif" />
+
+    <family name="monospace">
+        <font weight="400" style="normal">DroidSansMono.ttf</font>
+    </family>
+    <alias name="sans-serif-monospace" to="monospace" />
+    <alias name="monaco" to="monospace" />
+
+    <family name="serif-monospace">
+        <font weight="400" style="normal">CutiveMono.ttf</font>
+    </family>
+    <alias name="courier" to="serif-monospace" />
+    <alias name="courier new" to="serif-monospace" />
+
+    <family name="casual">
+        <font weight="400" style="normal">ComingSoon.ttf</font>
+    </family>
+
+    <family name="cursive">
+        <font weight="400" style="normal">DancingScript-Regular.ttf</font>
+        <font weight="700" style="normal">DancingScript-Bold.ttf</font>
+    </family>
+
+    <family name="sans-serif-smallcaps">
+        <font weight="400" style="normal">CarroisGothicSC-Regular.ttf</font>
+    </family>
+
+    <!-- fallback fonts -->
+    <family variant="elegant">
+        <font weight="400" style="normal">NotoNaskhArabic-Regular.ttf</font>
+        <font weight="700" style="normal">NotoNaskhArabic-Bold.ttf</font>
+    </family>
+    <family variant="compact">
+        <font weight="400" style="normal">NotoNaskhArabicUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoNaskhArabicUI-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansEthiopic-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansEthiopic-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansHebrew-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansHebrew-Bold.ttf</font>
+    </family>
+    <family variant="elegant">
+        <font weight="400" style="normal">NotoSansThai-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansThai-Bold.ttf</font>
+    </family>
+    <family variant="compact">
+        <font weight="400" style="normal">NotoSansThaiUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansThaiUI-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansArmenian-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansArmenian-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansGeorgian-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansGeorgian-Bold.ttf</font>
+    </family>
+    <family variant="elegant">
+        <font weight="400" style="normal">NotoSansDevanagari-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansDevanagari-Bold.ttf</font>
+    </family>
+    <family variant="compact">
+        <font weight="400" style="normal">NotoSansDevanagariUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansDevanagariUI-Bold.ttf</font>
+    </family>
+    <!-- Gujarati should come after Devanagari -->
+    <family variant="elegant">
+        <font weight="400" style="normal">NotoSansGujarati-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansGujarati-Bold.ttf</font>
+    </family>
+    <family variant="compact">
+        <font weight="400" style="normal">NotoSansGujaratiUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansGujaratiUI-Bold.ttf</font>
+    </family>
+    <!-- Gurmukhi should come after Devanagari -->
+    <family variant="elegant">
+        <font weight="400" style="normal">NotoSansGurmukhi-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansGurmukhi-Bold.ttf</font>
+    </family>
+    <family variant="compact">
+        <font weight="400" style="normal">NotoSansGurmukhiUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansGurmukhiUI-Bold.ttf</font>
+    </family>
+    <family variant="elegant">
+        <font weight="400" style="normal">NotoSansTamil-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansTamil-Bold.ttf</font>
+    </family>
+    <family variant="compact">
+        <font weight="400" style="normal">NotoSansTamilUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansTamilUI-Bold.ttf</font>
+    </family>
+    <family variant="elegant">
+        <font weight="400" style="normal">NotoSansMalayalam-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansMalayalam-Bold.ttf</font>
+    </family>
+    <family variant="compact">
+        <font weight="400" style="normal">NotoSansMalayalamUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansMalayalamUI-Bold.ttf</font>
+    </family>
+    <family variant="elegant">
+        <font weight="400" style="normal">NotoSansBengali-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansBengali-Bold.ttf</font>
+    </family>
+    <family variant="compact">
+        <font weight="400" style="normal">NotoSansBengaliUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansBengaliUI-Bold.ttf</font>
+    </family>
+    <family variant="elegant">
+        <font weight="400" style="normal">NotoSansTelugu-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansTelugu-Bold.ttf</font>
+    </family>
+    <family variant="compact">
+        <font weight="400" style="normal">NotoSansTeluguUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansTeluguUI-Bold.ttf</font>
+    </family>
+    <family variant="elegant">
+        <font weight="400" style="normal">NotoSansKannada-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansKannada-Bold.ttf</font>
+    </family>
+    <family variant="compact">
+        <font weight="400" style="normal">NotoSansKannadaUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansKannadaUI-Bold.ttf</font>
+    </family>
+    <family variant="elegant">
+        <font weight="400" style="normal">NotoSansOriya-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansOriya-Bold.ttf</font>
+    </family>
+    <family variant="compact">
+        <font weight="400" style="normal">NotoSansOriyaUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansOriyaUI-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansSinhala-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansSinhala-Bold.ttf</font>
+    </family>
+    <family variant="elegant">
+        <font weight="400" style="normal">NotoSansKhmer-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansKhmer-Bold.ttf</font>
+    </family>
+    <family variant="compact">
+        <font weight="400" style="normal">NotoSansKhmerUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansKhmerUI-Bold.ttf</font>
+    </family>
+    <family variant="elegant">
+        <font weight="400" style="normal">NotoSansLao-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansLao-Bold.ttf</font>
+    </family>
+    <family variant="compact">
+        <font weight="400" style="normal">NotoSansLaoUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansLaoUI-Bold.ttf</font>
+    </family>
+    <family variant="elegant">
+        <font weight="400" style="normal">NotoSansMyanmar-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansMyanmar-Bold.ttf</font>
+    </family>
+    <family variant="compact">
+        <font weight="400" style="normal">NotoSansMyanmarUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansMyanmarUI-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansThaana-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansThaana-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansCham-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansCham-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansBalinese-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansBamum-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansBatak-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansBuginese-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansBuhid-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansCanadianAboriginal-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansCherokee-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansCoptic-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansGlagolitic-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansHanunoo-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansJavanese-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansKayahLi-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansLepcha-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansLimbu-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansLisu-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansMandaic-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansMeeteiMayek-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansNewTaiLue-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansNKo-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansOlChiki-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansRejang-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansSaurashtra-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansSundanese-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansSylotiNagri-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansSyriacEstrangela-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansTagbanwa-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansTaiTham-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansTaiViet-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansTibetan-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansTifinagh-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansVai-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansYi-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted.ttf</font>
+    </family>
+    <family lang="zh-Hans">
+        <font weight="400" style="normal">NotoSansSC-Regular.otf</font>
+    </family>
+    <family lang="zh-Hant">
+        <font weight="400" style="normal">NotoSansTC-Regular.otf</font>
+    </family>
+    <family lang="ja">
+        <font weight="400" style="normal">NotoSansJP-Regular.otf</font>
+    </family>
+    <family lang="ko">
+        <font weight="400" style="normal">NotoSansKR-Regular.otf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NanumGothic.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoColorEmoji.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">DroidSansFallback.ttf</font>
+    </family>
+    <family lang="ja">
+        <font weight="400" style="normal">MTLmr3m.ttf</font>
+    </family>
+    <!--
+        Tai Le and Mongolian are intentionally kept last, to make sure they don't override
+        the East Asian punctuation for Chinese.
+    -->
+    <family>
+        <font weight="400" style="normal">NotoSansTaiLe-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansMongolian-Regular.ttf</font>
+    </family>
+</familyset>
diff --git a/third_party/closure_compiler/compiled_resources.gyp b/third_party/closure_compiler/compiled_resources.gyp
index e7a8aeb..eddacdd 100644
--- a/third_party/closure_compiler/compiled_resources.gyp
+++ b/third_party/closure_compiler/compiled_resources.gyp
@@ -27,7 +27,6 @@
         '../../chrome/browser/resources/options/compiled_resources.gyp:*',
         '../../chrome/browser/resources/media_router/compiled_resources.gyp:*',
         '../../chrome/browser/resources/md_extensions/compiled_resources.gyp:*',
-        '../../chrome/browser/resources/md_history/compiled_resources.gyp:*',
         '../../chrome/browser/resources/ntp4/compiled_resources.gyp:*',
         '../../remoting/app_remoting_webapp_compile.gypi:*',
         '../../remoting/remoting_webapp_compile.gypi:*',
diff --git a/third_party/closure_compiler/compiled_resources2.gyp b/third_party/closure_compiler/compiled_resources2.gyp
index f04e090..817f782 100644
--- a/third_party/closure_compiler/compiled_resources2.gyp
+++ b/third_party/closure_compiler/compiled_resources2.gyp
@@ -18,6 +18,7 @@
         '<(DEPTH)/chrome/browser/resources/chromeos/network_ui/compiled_resources2.gyp:*',
         '<(DEPTH)/chrome/browser/resources/history/compiled_resources2.gyp:*',
         '<(DEPTH)/chrome/browser/resources/md_downloads/compiled_resources2.gyp:*',
+        '<(DEPTH)/chrome/browser/resources/md_history/compiled_resources2.gyp:*',
         '<(DEPTH)/chrome/browser/resources/settings/compiled_resources2.gyp:*',
         '<(DEPTH)/chrome/browser/resources/uber/compiled_resources2.gyp:*',
         '<(DEPTH)/ui/webui/resources/cr_elements/compiled_resources2.gyp:*',
diff --git a/third_party/libjingle/BUILD.gn b/third_party/libjingle/BUILD.gn
index 1c3e5f9..962ec91 100644
--- a/third_party/libjingle/BUILD.gn
+++ b/third_party/libjingle/BUILD.gn
@@ -324,6 +324,8 @@
       "../webrtc/api/statstypes.h",
       "../webrtc/api/streamcollection.h",
       "../webrtc/api/umametrics.h",
+      "../webrtc/api/videocapturertracksource.cc",
+      "../webrtc/api/videocapturertracksource.h",
       "../webrtc/api/videosource.cc",
       "../webrtc/api/videosource.h",
       "../webrtc/api/videosourceinterface.h",
@@ -332,6 +334,8 @@
       "../webrtc/api/videotrack.h",
       "../webrtc/api/videotrackrenderers.cc",
       "../webrtc/api/videotrackrenderers.h",
+      "../webrtc/api/videotracksource.cc",
+      "../webrtc/api/videotracksource.h",
       "../webrtc/api/webrtcsdp.cc",
       "../webrtc/api/webrtcsdp.h",
       "../webrtc/api/webrtcsession.cc",
diff --git a/third_party/libjingle/README.chromium b/third_party/libjingle/README.chromium
index 4abaaf03..a1fcda4 100644
--- a/third_party/libjingle/README.chromium
+++ b/third_party/libjingle/README.chromium
@@ -1,7 +1,7 @@
 Name: libjingle
 URL: http://www.webrtc.org
 Version: unknown
-Revision: 11754
+Revision: 11893
 License: BSD
 License File: source/talk/COPYING
 Security Critical: yes
diff --git a/third_party/libjingle/libjingle.gyp b/third_party/libjingle/libjingle.gyp
index 6edf17f9..586368c 100644
--- a/third_party/libjingle/libjingle.gyp
+++ b/third_party/libjingle/libjingle.gyp
@@ -289,6 +289,8 @@
             '<(DEPTH)/third_party/webrtc/api/statstypes.h',
             '<(DEPTH)/third_party/webrtc/api/streamcollection.h',
             '<(DEPTH)/third_party/webrtc/api/umametrics.h',
+            '<(DEPTH)/third_party/webrtc/api/videocapturertracksource.cc',
+            '<(DEPTH)/third_party/webrtc/api/videocapturertracksource.h',
             '<(DEPTH)/third_party/webrtc/api/videosource.cc',
             '<(DEPTH)/third_party/webrtc/api/videosource.h',
             '<(DEPTH)/third_party/webrtc/api/videosourceinterface.h',
@@ -297,6 +299,8 @@
             '<(DEPTH)/third_party/webrtc/api/videotrack.h',
             '<(DEPTH)/third_party/webrtc/api/videotrackrenderers.cc',
             '<(DEPTH)/third_party/webrtc/api/videotrackrenderers.h',
+            '<(DEPTH)/third_party/webrtc/api/videotracksource.cc',
+            '<(DEPTH)/third_party/webrtc/api/videotracksource.h',
             '<(DEPTH)/third_party/webrtc/api/webrtcsdp.cc',
             '<(DEPTH)/third_party/webrtc/api/webrtcsdp.h',
             '<(DEPTH)/third_party/webrtc/api/webrtcsession.cc',
diff --git a/third_party/libxml/README.chromium b/third_party/libxml/README.chromium
index c3536ee2..33d9f98 100644
--- a/third_party/libxml/README.chromium
+++ b/third_party/libxml/README.chromium
@@ -36,6 +36,9 @@
 cd libxml2-2.9.2\win32
 cscript //E:jscript configure.js compiler=msvc iconv=no icu=yes ftp=no http=no
 Then copy VC10/config.h and include/libxml/xmlversion.h to win32/ on Linux.
+Patch win32/config.h to wrap the #define snprintf with:
+  #if _MSC_VER < 1900
+  #endif
 
 Remove:
   src/doc/
diff --git a/third_party/libxml/win32/config.h b/third_party/libxml/win32/config.h
index 8629944e..b9e0e5c0 100644
--- a/third_party/libxml/win32/config.h
+++ b/third_party/libxml/win32/config.h
@@ -96,7 +96,9 @@
 
 #if defined(_MSC_VER)
 #define mkdir(p,m) _mkdir(p)
+#if _MSC_VER < 1900
 #define snprintf _snprintf
+#endif
 #if _MSC_VER < 1500
 #define vsnprintf(b,c,f,a) _vsnprintf(b,c,f,a)
 #endif
diff --git a/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp b/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp
index 2806dab..1f1928e 100644
--- a/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp
+++ b/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp
@@ -88,15 +88,36 @@
 // A method is from Blink if it is from the Blink namespace or overrides a
 // method from the Blink namespace.
 bool IsBlinkOrWTFMethod(const clang::CXXMethodDecl& decl) {
-  if (IsDeclContextInBlinkOrWTF(decl.getDeclContext(), true, true))
-    return true;
+  bool overrides_blink = false;
+  bool overrides_non_blink = false;
 
   for (auto it = decl.begin_overridden_methods();
        it != decl.end_overridden_methods(); ++it) {
     if (IsBlinkOrWTFMethod(**it))
-      return true;
+      overrides_blink = true;
+    else
+      overrides_non_blink = true;
   }
-  return false;
+
+  // If this fires we have a class overriding a method from a class in blink,
+  // and also overriding a method of the same name from a class not in blink,
+  // without a common base class. The blink method will be renamed but the
+  // non-blink method will not, meaning no matter what we do here we stop
+  // overriding one of the two which creates a behaviour change. So assert and
+  // demand the user to fix the code first. T_T
+  if (overrides_blink || overrides_non_blink)
+    assert(overrides_blink != overrides_non_blink);
+
+  // If the method overrides something from outside blink then it's not a blink
+  // method.
+  if (overrides_non_blink)
+    return false;
+  // If the method overrides something from inside blink, then it is also a
+  // blink method.
+  if (overrides_blink)
+    return true;
+  // Otherwise decide for itself.
+  return IsDeclContextInBlinkOrWTF(decl.getDeclContext(), true, true);
 }
 
 AST_MATCHER(clang::CXXMethodDecl, isBlinkOrWTFMethod) {
diff --git a/tools/clang/rewrite_to_chrome_style/tests/methods-expected.cc b/tools/clang/rewrite_to_chrome_style/tests/methods-expected.cc
index c45df99..343e4e1 100644
--- a/tools/clang/rewrite_to_chrome_style/tests/methods-expected.cc
+++ b/tools/clang/rewrite_to_chrome_style/tests/methods-expected.cc
@@ -2,8 +2,25 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+namespace v8 {
+
+class InterfaceOutsideOfBlink {
+ public:
+  virtual void nonBlinkVirtual() = 0;
+};
+
+}  // namespace v8
+
 namespace blink {
 
+class InsideOfBlink : public v8::InterfaceOutsideOfBlink {
+ public:
+  // This function overrides something outside of blink so don't rename it.
+  void nonBlinkVirtual() override {}
+  // This function is in blink so rename it.
+  virtual void BlinkVirtual() {}
+};
+
 class MyIterator {};
 using my_iterator = char*;
 
@@ -110,6 +127,23 @@
   return tt;
 }
 
+class SubclassOfInsideOfBlink : public blink::InsideOfBlink {
+ public:
+  // This function overrides something outside of blink so don't rename it.
+  void nonBlinkVirtual() override {}
+  // This function overrides something in blink so rename it.
+  void BlinkVirtual() override {}
+};
+
+class TestSubclassInsideOfBlink : public SubclassOfInsideOfBlink {
+ public:
+ public:
+  // This function overrides something outside of blink so don't rename it.
+  void nonBlinkVirtual() override {}
+  // This function overrides something in blink so rename it.
+  void BlinkVirtual() override {}
+};
+
 namespace blink {
 
 struct StructInBlink {
diff --git a/tools/clang/rewrite_to_chrome_style/tests/methods-original.cc b/tools/clang/rewrite_to_chrome_style/tests/methods-original.cc
index 1bd97fa..040582dd 100644
--- a/tools/clang/rewrite_to_chrome_style/tests/methods-original.cc
+++ b/tools/clang/rewrite_to_chrome_style/tests/methods-original.cc
@@ -2,8 +2,25 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+namespace v8 {
+
+class InterfaceOutsideOfBlink {
+ public:
+  virtual void nonBlinkVirtual() = 0;
+};
+
+}  // namespace v8
+
 namespace blink {
 
+class InsideOfBlink : public v8::InterfaceOutsideOfBlink {
+ public:
+  // This function overrides something outside of blink so don't rename it.
+  void nonBlinkVirtual() override {}
+  // This function is in blink so rename it.
+  virtual void blinkVirtual() {}
+};
+
 class MyIterator {};
 using my_iterator = char*;
 
@@ -114,6 +131,23 @@
   return tt;
 }
 
+class SubclassOfInsideOfBlink : public blink::InsideOfBlink {
+ public:
+  // This function overrides something outside of blink so don't rename it.
+  void nonBlinkVirtual() override {}
+  // This function overrides something in blink so rename it.
+  void blinkVirtual() override {}
+};
+
+class TestSubclassInsideOfBlink : public SubclassOfInsideOfBlink {
+ public:
+ public:
+  // This function overrides something outside of blink so don't rename it.
+  void nonBlinkVirtual() override {}
+  // This function overrides something in blink so rename it.
+  void blinkVirtual() override {}
+};
+
 namespace blink {
 
 struct StructInBlink {
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 3365cb0..09ebfbb 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -18757,6 +18757,14 @@
   </summary>
 </histogram>
 
+<histogram name="Login.PasswordChangeFlow" enum="LoginPasswordChangeFlow">
+  <owner>xiyuan@chromium.org</owner>
+  <owner>omrilio@chromium.org</owner>
+  <summary>
+    Records the UI flow after a possible password change is detected.
+  </summary>
+</histogram>
+
 <histogram name="Login.PolicyFilesStatePerBoot" enum="LoginPolicyFilesState">
   <owner>cmasone@chromium.org</owner>
   <summary>The state of Chrome OS owner key and device policy files.</summary>
@@ -66221,6 +66229,8 @@
   <int value="1108" label="ENTERPRISE_PLATFORMKEYS_CHALLENGEMACHINEKEY"/>
   <int value="1109" label="ENTERPRISE_PLATFORMKEYS_CHALLENGEUSERKEY"/>
   <int value="1110" label="INPUTMETHODPRIVATE_NOTIFYIMEMENUITEMACTIVATED"/>
+  <int value="1111" label="INPUT_IME_SHOWWINDOW"/>
+  <int value="1112" label="INPUT_IME_HIDEWINDOW"/>
 </enum>
 
 <enum name="ExtensionInstallCause" type="int">
@@ -69431,6 +69441,8 @@
   <int value="1" label="Precise GC"/>
   <int value="2" label="Conservative GC"/>
   <int value="3" label="Forced GC for testing"/>
+  <int value="4" label="Memory pressure GC"/>
+  <int value="5" label="Page navigation GC"/>
 </enum>
 
 <enum name="GDataAuthResult" type="int">
@@ -72770,6 +72782,11 @@
   <int value="1" label="Known user"/>
 </enum>
 
+<enum name="LoginPasswordChangeFlow" type="int">
+  <int value="0" label="Password change"/>
+  <int value="1" label="Cryptohome failure"/>
+</enum>
+
 <enum name="LoginPolicyFilesState" type="int">
   <summary>Policy/owner key file state.</summary>
   <int value="0" label="HEALTHY_R11">Healthy, pre-R11</int>
@@ -84283,6 +84300,16 @@
   <affected-histogram name="WebRTC.Stun.BatchSuccessPercent.UnknownNAT"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="BlinkGCReason">
+  <suffix name="IdleGC" label="Idle GC"/>
+  <suffix name="PreciseGC" label="Precise GC"/>
+  <suffix name="ConservativeGC" label="Conservative GC"/>
+  <suffix name="ForcedGC" label="Forced GC for testing"/>
+  <suffix name="MemoryPressureGC" label="Memory pressure GC"/>
+  <suffix name="PageNavigationGC" label="Page navigation GC"/>
+  <affected-histogram name="BlinkGC.CollectionRate"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="CacheInstance" separator="." ordering="prefix">
   <suffix name="App"
       label="Collected from the HTML5 Application Cache instance."/>
diff --git a/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory.txt b/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory.txt
index fffe2ea..f7377a7 100644
--- a/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory.txt
+++ b/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory.txt
@@ -125,3 +125,40 @@
 
 # https://crbug.com/1310994
 MetricsServiceBrowserTest.CrashRenderers
+
+# https://crbug.com/592900
+AppViewTest.TestAppViewWithUndefinedDataShouldSucceed
+BasicExtensionSettingsWebUITest.testNonEmptyExtensionList
+BookmarkBubbleSignInDelegateTest.OnSignInLinkClickedReusesBlank
+BrowserOptionsOverlayWebUITest.testNavigationInBackground
+CrashRecoveryBrowserTest.DoubleReloadWithError
+CrashRecoveryBrowserTest.ReloadCacheRevalidate
+CrExtensionsBrowserTest.ExtensionItemDeveloperStateTest
+CrExtensionsBrowserTest.ExtensionItemList
+CrExtensionsBrowserTest.ExtensionItemWarningsTest
+CrExtensionsBrowserTestWithInstalledExtension.ExtensionServiceProfileSettingsTest
+CrExtensionsBrowserTestWithInstalledExtension.ExtensionServiceToggleIncognitoTest
+CrExtensionsBrowserTestWithInstalledExtension.ExtensionServiceUninstallTest
+CrSettingsRtlTest.DrawerPanelFlips
+DownloadTestWithShelf.IncognitoDownload
+DurableStorageBrowserTest.Incognito
+HostedAppTest.ShouldShowLocationBarForHTTPBookmarkApp
+HostedAppTest.ShouldShowLocationBarForHTTPSBookmarkApp
+ImageWriterPrivateApiTest.TestWriteFromFile
+InlineInstallPrivateApiTestApp.BackgroundInstall
+InlineInstallPrivateApiTestApp.SuccessfulInstall
+InstallGoodExtensionSettingsWebUITest.showOptions
+MaterialHistoryBrowserTest.HistoryItemTest
+MimeHandlerViewTest.Abort
+MimeHandlerViewTest.EmbeddedDataUrlObject
+MultilanguageOptionsWebUIBrowserTest.NotAcceptLanguage
+PasswordsPrivateApiTest.RequestPlaintextPassword
+PDFExtensionTest.BasicPlugin
+PDFExtensionTest.ParamsParser
+PDFExtensionTest.TabTitleWithEmbeddedPdf
+PDFExtensionTest.TabTitleWithTitle
+PushMessagingBrowserTest.SubscribeWithoutKeySuccessNotificationsGranted
+SubframeTaskBrowserTest.TaskManagerShowsSubframeTasks
+SyncSetupWebUITestAsync.RestoreSyncDataTypes
+WebUIWebViewBrowserTest.ExecuteScriptCode
+ZoomControllerBrowserTest.NavigationResetsManualMode
diff --git a/ui/accessibility/platform/ax_platform_node.cc b/ui/accessibility/platform/ax_platform_node.cc
index 8f889458..adfcc1e 100644
--- a/ui/accessibility/platform/ax_platform_node.cc
+++ b/ui/accessibility/platform/ax_platform_node.cc
@@ -4,12 +4,23 @@
 
 #include "ui/accessibility/platform/ax_platform_node.h"
 
+#include "base/containers/hash_tables.h"
+#include "base/lazy_instance.h"
 #include "build/build_config.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/accessibility/platform/ax_platform_node_delegate.h"
 
 namespace ui {
 
+namespace {
+
+using UniqueIdMap = base::hash_map<int32_t, AXPlatformNode*>;
+// Map from each AXPlatformNode's unique id to its instance.
+base::LazyInstance<UniqueIdMap> g_unique_id_map =
+    LAZY_INSTANCE_INITIALIZER;
+
+}
+
 #if !defined(PLATFORM_HAS_AX_PLATFORM_NODE_IMPL)
 // static
 AXPlatformNode* AXPlatformNode::Create(AXPlatformNodeDelegate* delegate) {
@@ -28,10 +39,39 @@
 }
 #endif
 
-AXPlatformNode::AXPlatformNode() {
+// static
+int32_t AXPlatformNode::GetNextUniqueId() {
+  static int32_t next_unique_id = 1;
+  int32_t unique_id = next_unique_id;
+  if (next_unique_id == INT32_MAX)
+    next_unique_id = 1;
+  else
+    next_unique_id++;
+
+  return unique_id;
+}
+
+AXPlatformNode::AXPlatformNode() : unique_id_(GetNextUniqueId()) {
+  g_unique_id_map.Get()[unique_id_] = this;
 }
 
 AXPlatformNode::~AXPlatformNode() {
+  if (unique_id_)
+    g_unique_id_map.Get().erase(unique_id_);
+}
+
+void AXPlatformNode::Destroy() {
+  g_unique_id_map.Get().erase(unique_id_);
+  unique_id_ = 0;
+}
+
+AXPlatformNode* AXPlatformNode::GetFromUniqueId(int32_t unique_id) {
+  UniqueIdMap* unique_ids = g_unique_id_map.Pointer();
+  auto iter = unique_ids->find(unique_id);
+  if (iter != unique_ids->end())
+    return iter->second;
+
+  return nullptr;
 }
 
 }  // namespace ui
diff --git a/ui/accessibility/platform/ax_platform_node.h b/ui/accessibility/platform/ax_platform_node.h
index 1d0ed51..c9df259 100644
--- a/ui/accessibility/platform/ax_platform_node.h
+++ b/ui/accessibility/platform/ax_platform_node.h
@@ -46,9 +46,17 @@
   static AXPlatformNode* FromNativeViewAccessible(
       gfx::NativeViewAccessible accessible);
 
+  // Each platform accessibility object has a unique id that's guaranteed
+  // to be a positive number. (It's stored in an int32_t as opposed to
+  // uint32_t because some platforms want to negate it, so we want to ensure
+  // the range is below the signed int max.) This can be used when the
+  // id has to be unique across multiple frames, since node ids are
+  // only unique within one tree.
+  static int32_t GetNextUniqueId();
+
   // Call Destroy rather than deleting this, because the subclass may
   // use reference counting.
-  virtual void Destroy() = 0;
+  virtual void Destroy();
 
   // Get the platform-specific accessible object type for this instance.
   // On some platforms this is just a type cast, on others it may be a
@@ -65,6 +73,10 @@
  protected:
   AXPlatformNode();
   virtual ~AXPlatformNode();
+
+  AXPlatformNode* GetFromUniqueId(int32_t unique_id);
+
+  int32_t unique_id_;
 };
 
 }  // namespace ui
diff --git a/ui/accessibility/platform/ax_platform_node_base.cc b/ui/accessibility/platform/ax_platform_node_base.cc
index 2c1bf90..a9d4c1f 100644
--- a/ui/accessibility/platform/ax_platform_node_base.cc
+++ b/ui/accessibility/platform/ax_platform_node_base.cc
@@ -44,6 +44,7 @@
 // AXPlatformNode overrides.
 
 void AXPlatformNodeBase::Destroy() {
+  AXPlatformNode::Destroy();
   delegate_ = nullptr;
   delete this;
 }
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index 168f2fe..95632d8 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -78,34 +78,12 @@
 
 namespace {
 
-typedef base::hash_map<LONG, AXPlatformNodeWin*> UniqueIdWinMap;
-// Map from each AXPlatformNodeWin's unique id to its instance.
-base::LazyInstance<UniqueIdWinMap> g_unique_id_win_map =
-    LAZY_INSTANCE_INITIALIZER;
-
 typedef base::hash_set<AXPlatformNodeWin*> AXPlatformNodeWinSet;
 // Set of all AXPlatformNodeWin objects that were the target of an
 // alert event.
 base::LazyInstance<AXPlatformNodeWinSet> g_alert_targets =
     LAZY_INSTANCE_INITIALIZER;
 
-LONG GetNextNegativeUniqueIdForWinAccessibility(AXPlatformNodeWin* obj) {
-  static LONG next_unique_id = -1;
-  LONG unique_id = next_unique_id;
-  if (next_unique_id == LONG_MIN)
-    next_unique_id = -1;
-  else
-    next_unique_id--;
-
-  g_unique_id_win_map.Get().insert(std::make_pair(unique_id, obj));
-
-  return unique_id;
-}
-
-void UnregisterNegativeUniqueId(LONG unique_id) {
-  g_unique_id_win_map.Get().erase(unique_id);
-}
-
 base::LazyInstance<base::ObserverList<IAccessible2UsageObserver>>
     g_iaccessible2_usage_observer_list = LAZY_INSTANCE_INITIALIZER;
 
@@ -156,8 +134,7 @@
 // AXPlatformNodeWin
 //
 
-AXPlatformNodeWin::AXPlatformNodeWin()
-    : unique_id_win_(GetNextNegativeUniqueIdForWinAccessibility(this)) {
+AXPlatformNodeWin::AXPlatformNodeWin() {
 }
 
 AXPlatformNodeWin::~AXPlatformNodeWin() {
@@ -170,7 +147,6 @@
 
 void AXPlatformNodeWin::Destroy() {
   delegate_ = nullptr;
-  UnregisterNegativeUniqueId(unique_id_win_);
   RemoveAlertTarget();
   Release();
 }
@@ -194,7 +170,7 @@
   if (native_event < EVENT_MIN)
     return;
 
-  ::NotifyWinEvent(native_event, hwnd, OBJID_CLIENT, unique_id_win_);
+  ::NotifyWinEvent(native_event, hwnd, OBJID_CLIENT, -unique_id_);
 
   // Keep track of objects that are a target of an alert event.
   if (event_type == ui::AX_EVENT_ALERT)
@@ -366,10 +342,10 @@
     return E_FAIL;
 
   // Negative child ids can be used to map to any descendant.
-  UniqueIdWinMap* unique_ids = g_unique_id_win_map.Pointer();
-  auto iter = unique_ids->find(child_id);
-  if (iter != unique_ids->end()) {
-    *disp_child = iter->second;
+  AXPlatformNodeWin* child = static_cast<AXPlatformNodeWin*>(
+      GetFromUniqueId(-child_id));
+  if (child) {
+    *disp_child = child;
     (*disp_child)->AddRef();
     return S_OK;
   }
@@ -531,7 +507,7 @@
 
 STDMETHODIMP AXPlatformNodeWin::get_uniqueID(LONG* unique_id) {
   COM_OBJECT_VALIDATE_1_ARG(unique_id);
-  *unique_id = unique_id_win_;
+  *unique_id = -unique_id_;
   return S_OK;
 }
 
diff --git a/ui/accessibility/platform/ax_platform_node_win.h b/ui/accessibility/platform/ax_platform_node_win.h
index 3979272..eb747ed4d 100644
--- a/ui/accessibility/platform/ax_platform_node_win.h
+++ b/ui/accessibility/platform/ax_platform_node_win.h
@@ -297,16 +297,6 @@
                     IA2TextBoundaryType ia2_boundary,
                     LONG start_offset,
                     ui::TextBoundaryDirection direction);
-
-  // A windows-specific unique ID for this object. It's returned in
-  // IAccessible2::get_uniqueID, but more importantly it's used for
-  // firing events. On Windows, we fire events on the nearest parent HWND
-  // and pass the unique ID as the child id parameter. When the client
-  // wants to retrieve the object the event was fired on, it calls
-  // get_accChild and passes the child ID. We use negative IDs for the unique
-  // ID so we can distinguish a request for an arbitrary child from a request
-  // for an immediate child of an object by its 0-based index.
-  LONG unique_id_win_;
 };
 
 }  // namespace ui
diff --git a/ui/android/java/src/org/chromium/ui/widget/TextViewWithClickableSpans.java b/ui/android/java/src/org/chromium/ui/widget/TextViewWithClickableSpans.java
index 184172a..e7587e9d 100644
--- a/ui/android/java/src/org/chromium/ui/widget/TextViewWithClickableSpans.java
+++ b/ui/android/java/src/org/chromium/ui/widget/TextViewWithClickableSpans.java
@@ -19,6 +19,8 @@
 import android.widget.PopupMenu;
 import android.widget.TextView;
 
+import org.chromium.base.VisibleForTesting;
+
 /**
  * ClickableSpan isn't accessible by default, so we create a subclass
  * of TextView that tries to handle the case where a user clicks on a view
@@ -118,7 +120,11 @@
         return clickableSpans.length > 0;
     }
 
-    private ClickableSpan[] getClickableSpans() {
+    /**
+     * Returns the ClickableSpans in this TextView's text.
+     */
+    @VisibleForTesting
+    public ClickableSpan[] getClickableSpans() {
         CharSequence text = getText();
         if (!(text instanceof SpannableString)) return null;
 
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager.css b/ui/file_manager/file_manager/foreground/css/file_manager.css
index 45f806f..f83f14f 100644
--- a/ui/file_manager/file_manager/foreground/css/file_manager.css
+++ b/ui/file_manager/file_manager/foreground/css/file_manager.css
@@ -124,6 +124,24 @@
   flex-direction: column;
 }
 
+/* Details pane */
+.details-container {
+  background-color: rgb(250, 250, 250);
+  flex: none;
+  max-width: 30%;
+  min-width: 100px;
+  overflow: hidden;
+  position: relative;
+}
+
+#list-details-splitter:not([activated]) {
+  display: none;
+}
+
+.details-container:not([activated]) {
+  display: none;
+}
+
 /* Directory tree at the left. */
 .dialog-navigation-list {
   -webkit-border-end: 1px solid rgba(0, 0, 0, 0.15);
@@ -449,6 +467,24 @@
   display: none;
 }
 
+#details-button {
+  /**
+   * TODO(ryoh): This should be removed after we finally implement details
+   *     panel.
+   */
+  display: none;
+}
+
+#details-button > .icon {
+  background-image: -webkit-image-set(
+      url(../images/files/ui/details_white.png) 1x,
+      url(../images/files/ui/2x/details_white.png) 2x);
+}
+
+body.check-select #details-button {
+  display: none;
+}
+
 #gear-button > .icon {
   background-image: -webkit-image-set(
       url(../images/files/ui/menu_white.png) 1x,
diff --git a/ui/file_manager/file_manager/foreground/images/files/ui/2x/details_white.png b/ui/file_manager/file_manager/foreground/images/files/ui/2x/details_white.png
new file mode 100644
index 0000000..e5b87280
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/files/ui/2x/details_white.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/files/ui/details_white.png b/ui/file_manager/file_manager/foreground/images/files/ui/details_white.png
new file mode 100644
index 0000000..7618185
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/files/ui/details_white.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/js/app_state_controller.js b/ui/file_manager/file_manager/foreground/js/app_state_controller.js
index bfaa930..7df9810 100644
--- a/ui/file_manager/file_manager/foreground/js/app_state_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/app_state_controller.js
@@ -79,6 +79,7 @@
   // Restore preferences.
   this.ui_.setCurrentListType(
       this.viewOptions_.listType || ListContainer.ListType.DETAIL);
+  this.ui_.setDetailsVisibility(!!this.viewOptions_.detailsVisibility);
   this.directoryModel_.getFileList().sort(
       this.viewOptions_.sortField || 'modificationTime',
       this.viewOptions_.sortDirection || 'desc');
@@ -97,7 +98,12 @@
     sortField: sortStatus.field,
     sortDirection: sortStatus.direction,
     columnConfig: {},
-    listType: this.ui_.listContainer.currentListType
+    listType: this.ui_.listContainer.currentListType,
+    /**
+     * TODO(ryoh): Simplify this line after we finally implement details panel.
+     */
+    detailsVisibility: this.ui_.detailsContainer &&
+        this.ui_.detailsContainer.visible || false
   };
   var cm = this.ui_.listContainer.table.columnModel;
   prefs.columnConfig = cm.exportColumnConfig();
diff --git a/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp b/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp
index 5031555f..9b9a5da 100644
--- a/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp
+++ b/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp
@@ -124,6 +124,7 @@
           './ui/actions_submenu.js',
           './ui/banners.js',
           './ui/default_task_dialog.js',
+          './ui/details_container.js',
           './ui/dialog_footer.js',
           './ui/directory_tree.js',
           './ui/drag_selector.js',
diff --git a/ui/file_manager/file_manager/foreground/js/main_scripts.js b/ui/file_manager/file_manager/foreground/js/main_scripts.js
index e826ffd..c7c905ac 100644
--- a/ui/file_manager/file_manager/foreground/js/main_scripts.js
+++ b/ui/file_manager/file_manager/foreground/js/main_scripts.js
@@ -140,6 +140,7 @@
 //<include src="ui/actions_submenu.js">
 //<include src="ui/banners.js" >
 //<include src="ui/default_task_dialog.js">
+//<include src="ui/details_container.js">
 //<include src="ui/dialog_footer.js">
 //<include src="ui/directory_tree.js">
 //<include src="ui/drag_selector.js">
diff --git a/ui/file_manager/file_manager/foreground/js/main_window_component.js b/ui/file_manager/file_manager/foreground/js/main_window_component.js
index 0a1419e..12c83ca 100644
--- a/ui/file_manager/file_manager/foreground/js/main_window_component.js
+++ b/ui/file_manager/file_manager/foreground/js/main_window_component.js
@@ -124,6 +124,8 @@
       'pathclick', this.onBreadcrumbClick_.bind(this));
   ui.toggleViewButton.addEventListener(
       'click', this.onToggleViewButtonClick_.bind(this));
+  ui.detailsButton.addEventListener(
+      'click', this.onDetailsButtonClick_.bind(this));
   directoryModel.addEventListener(
       'directory-changed', this.onDirectoryChanged_.bind(this));
   volumeManager.addEventListener(
@@ -132,6 +134,8 @@
   this.onDriveConnectionChanged_();
   document.addEventListener('keydown', this.onKeyDown_.bind(this));
   document.addEventListener('keyup', this.onKeyUp_.bind(this));
+  selectionHandler.addEventListener('change',
+      this.onFileSelectionChanged_.bind(this));
 }
 
 /**
@@ -159,6 +163,17 @@
 };
 
 /**
+ * Handles file selection event.
+ *
+ * @private
+ */
+MainWindowComponent.prototype.onFileSelectionChanged_ = function(event) {
+  if (this.ui_.detailsContainer) {
+    this.ui_.detailsContainer.onFileSelectionChanged(event);
+  }
+};
+
+/**
  * Handles mouse click or tap.
  *
  * @param {Event} event The click event.
@@ -236,6 +251,18 @@
 };
 
 /**
+ * Handles click event on the toggle-view button.
+ * @param {Event} event Click event.
+ * @private
+ */
+MainWindowComponent.prototype.onDetailsButtonClick_ = function(event) {
+  var visible = this.ui_.detailsContainer.visible;
+  this.ui_.setDetailsVisibility(!visible);
+  this.appStateController_.saveViewOptions();
+  this.ui_.listContainer.focus();
+};
+
+/**
  * KeyDown event handler for the document.
  * @param {Event} event Key event.
  * @private
diff --git a/ui/file_manager/file_manager/foreground/js/ui/details_container.js b/ui/file_manager/file_manager/foreground/js/ui/details_container.js
new file mode 100644
index 0000000..1d54bad
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/js/ui/details_container.js
@@ -0,0 +1,63 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @param {!HTMLElement} element
+ * @param {!Element} splitter
+ * @param {!Element} button
+ * @param {!FilesToggleRipple} toggleRipple
+ * @constructor
+ * @struct
+ */
+function DetailsContainer(element, splitter, button, toggleRipple) {
+  /**
+   * Container element.
+   * @private {!HTMLElement}
+   * @const
+   */
+  this.element_ = element;
+  /**
+   * Splitter element between the file list and the details panel.
+   * @private {!Element}
+   * @const
+   */
+  this.splitter_ = splitter;
+  /**
+   * "View details" button element.
+   * @private {!Element}
+   * @const
+   */
+  this.button_ = button;
+  /**
+   * Ripple element of "View details" button.
+   * @private {!Element}
+   * @const
+   */
+  this.toggleRipple_ = toggleRipple;
+  /**
+   * @type {boolean}
+   */
+  this.visible = false;
+  this.setVisibility(false);
+}
+
+DetailsContainer.prototype.onFileSelectionChanged = function(event) {
+  var selection = event.target.selection;
+};
+
+/**
+ * Sets the details panel visibility
+ * @param {boolean} visibility True if the details panel is visible.
+ */
+DetailsContainer.prototype.setVisibility = function(visibility) {
+  if (visibility) {
+    this.splitter_.setAttribute('activated', '');
+    this.element_.setAttribute('activated', '');
+  } else {
+    this.splitter_.removeAttribute('activated');
+    this.element_.removeAttribute('activated');
+  }
+  this.visible = visibility;
+  this.toggleRipple_.activated = visibility;
+};
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
index 8f4db8a..4c04632 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
@@ -163,6 +163,23 @@
       '#sort-button', cr.ui.MenuButton);
 
   /**
+   * The button to open the details panel.
+   * @type {!Element}
+   * @const
+   */
+  this.detailsButton = queryRequiredElement(
+      '#details-button', this.element);
+
+  /**
+   * Ripple effect of details button.
+   * @private {!FilesToggleRipple}
+   * @const
+   */
+  this.detailsButtonToggleRipple_ =
+      /** @type {!FilesToggleRipple} */ (queryRequiredElement(
+          'files-toggle-ripple', this.detailsButton));
+
+  /**
    * Ripple effect of sort button.
    * @private {!FilesToggleRipple}
    * @const
@@ -215,6 +232,12 @@
   this.listContainer = null;
 
   /**
+   * Details container.
+   * @type {DetailsContainer}
+   */
+  this.detailsContainer = null;
+
+  /**
    * @type {!HTMLElement}
    */
   this.formatPanelError =
@@ -327,6 +350,22 @@
   this.decorateSplitter_(
       queryRequiredElement('#navigation-list-splitter', this.element));
 
+  // Details container.
+  chrome.commandLinePrivate.hasSwitch('enable-files-details-panel',
+      function(enabled) {
+    if (enabled) {
+      this.detailsButton.style.display = 'block';
+      var listDetailsSplitter =
+          queryRequiredElement('#list-details-splitter', this.element);
+      this.decorateSplitter_(listDetailsSplitter);
+      this.detailsContainer = new DetailsContainer(
+          queryRequiredElement('#details-container', this.element),
+          listDetailsSplitter,
+          this.detailsButton,
+          this.detailsButtonToggleRipple_);
+    }
+  }.bind(this));
+
   // Location line.
   this.locationLine = locationLine;
 
@@ -447,6 +486,17 @@
 };
 
 /**
+ * Sets the details panel visibility
+ * @param {boolean} visibility True if the details panel is visible.
+ */
+FileManagerUI.prototype.setDetailsVisibility = function(visibility) {
+  if (this.detailsContainer) {
+    this.detailsContainer.setVisibility(visibility);
+    this.relayout();
+  }
+};
+
+/**
  * Overrides default handling for clicks on hyperlinks.
  * In a packaged apps links with targer='_blank' open in a new tab by
  * default, other links do not open at all.
diff --git a/ui/file_manager/file_manager/main.html b/ui/file_manager/file_manager/main.html
index ca17199..3639d5a 100644
--- a/ui/file_manager/file_manager/main.html
+++ b/ui/file_manager/file_manager/main.html
@@ -309,7 +309,13 @@
         <files-toggle-ripple></files-toggle-ripple>
         <div class="icon"></div>
       </button>
-      <button id="gear-button" class="icon-button" tabindex="18"
+      <button id="details-button" class="icon-button" tabindex="18"
+              i18n-values="aria-label:DETAIL_BUTTON_TOOLTIP"
+              has-tooltip>
+        <files-toggle-ripple></files-toggle-ripple>
+        <div class="icon"></div>
+      </button>
+      <button id="gear-button" class="icon-button" tabindex="19"
               menu="#gear-menu"
               i18n-values="aria-label:GEAR_BUTTON_TOOLTIP"
               aria-activedescendant="gear-menu"
@@ -342,7 +348,7 @@
     <div class="dialog-container">
       <div class="dialog-navigation-list">
         <div class="dialog-navigation-list-contents">
-          <tree id="directory-tree" tabindex="19"></tree>
+          <tree id="directory-tree" tabindex="20"></tree>
         </div>
         <div class="dialog-navigation-list-footer">
           <div id="progress-center" hidden>
@@ -403,6 +409,9 @@
           </div>
         </div>
       </div>
+      <div class="splitter" id="list-details-splitter"></div>
+      <div id="details-container" class="details-container">
+      </div>
     </div>
     <div class="dialog-footer progressable" tabindex="-1"
          visibleif="saveas-file open-file open-multi-file folder upload-folder">
diff --git a/ui/file_manager/gallery/js/slide_mode.js b/ui/file_manager/gallery/js/slide_mode.js
index dcad955..1968409 100644
--- a/ui/file_manager/gallery/js/slide_mode.js
+++ b/ui/file_manager/gallery/js/slide_mode.js
@@ -1870,6 +1870,12 @@
    */
   this.lastZoom_ = 1.0;
 
+  /**
+   * @type {number}
+   * @private
+   */
+  this.mouseWheelZoomOperationId_ = 0;
+
   targetElement.addEventListener('touchstart', this.onTouchStart_.bind(this));
   var onTouchEventBound = this.onTouchEvent_.bind(this);
   targetElement.ownerDocument.addEventListener('touchmove', onTouchEventBound);
@@ -2068,20 +2074,28 @@
  */
 TouchHandler.prototype.onMouseWheel_ = function(event) {
   var event = assertInstanceof(event, MouseEvent);
-  var viewport = this.slideMode_.getViewport();
   if (!this.enabled_)
     return;
 
   this.stopOperation();
-  this.lastZoom_ = viewport.getZoom();
-  var zoom = this.lastZoom_;
+
+  var viewport = this.slideMode_.getViewport();
+  var zoom = viewport.getZoom();
   if (event.wheelDeltaY > 0) {
     zoom *= TouchHandler.WHEEL_ZOOM_FACTOR;
   } else {
     zoom /= TouchHandler.WHEEL_ZOOM_FACTOR;
   }
-  viewport.setZoom(zoom);
-  this.slideMode_.imageView_.applyViewportChange();
+
+  // Request animation frame not to set zoom more than once in a frame. This is
+  // a fix for https://crbug.com/591033
+  requestAnimationFrame(function(operationId) {
+    if (this.mouseWheelZoomOperationId_ !== operationId)
+      return;
+
+    viewport.setZoom(zoom);
+    this.slideMode_.applyViewportChange();
+  }.bind(this, ++this.mouseWheelZoomOperationId_));
 };
 
 /**
diff --git a/ui/gfx/geometry/insets.cc b/ui/gfx/geometry/insets.cc
index 46fb84c..08ee8f4 100644
--- a/ui/gfx/geometry/insets.cc
+++ b/ui/gfx/geometry/insets.cc
@@ -10,6 +10,11 @@
 
 Insets::Insets() : Insets(0, 0, 0, 0) {}
 
+Insets::Insets(int all) : Insets(all, all, all, all) {}
+
+Insets::Insets(int vertical, int horizontal)
+    : Insets(vertical, horizontal, vertical, horizontal) {}
+
 Insets::Insets(int top, int left, int bottom, int right)
     : top_(top), left_(left), bottom_(bottom), right_(right) {}
 
diff --git a/ui/gfx/geometry/insets.h b/ui/gfx/geometry/insets.h
index 0466d94..2fc0d62 100644
--- a/ui/gfx/geometry/insets.h
+++ b/ui/gfx/geometry/insets.h
@@ -12,10 +12,11 @@
 
 namespace gfx {
 
-// An integer version of gfx::Insets.
 class GFX_EXPORT Insets {
  public:
   Insets();
+  explicit Insets(int all);
+  Insets(int vertical, int horizontal);
   Insets(int top, int left, int bottom, int right);
 
   ~Insets();
diff --git a/ui/gfx/geometry/insets_f.h b/ui/gfx/geometry/insets_f.h
index 90592d77..f159a74 100644
--- a/ui/gfx/geometry/insets_f.h
+++ b/ui/gfx/geometry/insets_f.h
@@ -11,7 +11,7 @@
 
 namespace gfx {
 
-// A floating versin of gfx::Insets.
+// A floating point version of gfx::Insets.
 class GFX_EXPORT InsetsF {
  public:
   InsetsF();
diff --git a/ui/gfx/harfbuzz_font_skia.cc b/ui/gfx/harfbuzz_font_skia.cc
index 723b68ae..e2adeaf 100644
--- a/ui/gfx/harfbuzz_font_skia.cc
+++ b/ui/gfx/harfbuzz_font_skia.cc
@@ -16,6 +16,7 @@
 #include "third_party/skia/include/core/SkPaint.h"
 #include "third_party/skia/include/core/SkTypeface.h"
 #include "ui/gfx/render_text.h"
+#include "ui/gfx/skia_util.h"
 
 namespace gfx {
 
@@ -65,14 +66,14 @@
 
   paint->getTextWidths(&glyph, sizeof(glyph), &sk_width, &sk_bounds);
   if (width)
-    *width = SkScalarToFixed(sk_width);
+    *width = SkiaScalarToHarfBuzzUnits(sk_width);
   if (extents) {
     // Invert y-axis because Skia is y-grows-down but we set up HarfBuzz to be
     // y-grows-up.
-    extents->x_bearing = SkScalarToFixed(sk_bounds.fLeft);
-    extents->y_bearing = SkScalarToFixed(-sk_bounds.fTop);
-    extents->width = SkScalarToFixed(sk_bounds.width());
-    extents->height = SkScalarToFixed(-sk_bounds.height());
+    extents->x_bearing = SkiaScalarToHarfBuzzUnits(sk_bounds.fLeft);
+    extents->y_bearing = SkiaScalarToHarfBuzzUnits(-sk_bounds.fTop);
+    extents->width = SkiaScalarToHarfBuzzUnits(sk_bounds.width());
+    extents->height = SkiaScalarToHarfBuzzUnits(-sk_bounds.height());
   }
 }
 
@@ -132,7 +133,7 @@
 
   SkScalar upm = SkIntToScalar(typeface->getUnitsPerEm());
   SkScalar size = font_data->paint_.getTextSize();
-  return SkScalarToFixed(
+  return SkiaScalarToHarfBuzzUnits(
       SkScalarMulDiv(SkIntToScalar(kerning_adjustments[0]), size, upm));
 }
 
@@ -271,7 +272,7 @@
     face_cache->first.Init(skia_face);
 
   hb_font_t* harfbuzz_font = hb_font_create(face_cache->first.get());
-  const int scale = SkScalarToFixed(text_size);
+  const int scale = SkiaScalarToHarfBuzzUnits(text_size);
   hb_font_set_scale(harfbuzz_font, scale, scale);
   FontData* hb_font_data = new FontData(&face_cache->second);
   hb_font_data->paint_.setTypeface(skia_face);
diff --git a/ui/gfx/render_text_harfbuzz.cc b/ui/gfx/render_text_harfbuzz.cc
index a9a05ef..590537e 100644
--- a/ui/gfx/render_text_harfbuzz.cc
+++ b/ui/gfx/render_text_harfbuzz.cc
@@ -28,6 +28,7 @@
 #include "ui/gfx/geometry/safe_integer_conversions.h"
 #include "ui/gfx/harfbuzz_font_skia.h"
 #include "ui/gfx/range/range_f.h"
+#include "ui/gfx/skia_util.h"
 #include "ui/gfx/text_utils.h"
 #include "ui/gfx/utf16_indexing.h"
 
@@ -1503,12 +1504,14 @@
     DCHECK_LE(infos[i].codepoint, std::numeric_limits<uint16_t>::max());
     run->glyphs[i] = static_cast<uint16_t>(infos[i].codepoint);
     run->glyph_to_char[i] = infos[i].cluster;
-    const SkScalar x_offset = SkFixedToScalar(hb_positions[i].x_offset);
-    const SkScalar y_offset = SkFixedToScalar(hb_positions[i].y_offset);
+    const SkScalar x_offset =
+        HarfBuzzUnitsToSkiaScalar(hb_positions[i].x_offset);
+    const SkScalar y_offset =
+        HarfBuzzUnitsToSkiaScalar(hb_positions[i].y_offset);
     run->positions[i].set(run->width + x_offset, -y_offset);
     run->width += (glyph_width_for_test_ > 0)
                       ? glyph_width_for_test_
-                      : SkFixedToFloat(hb_positions[i].x_advance);
+                      : HarfBuzzUnitsToFloat(hb_positions[i].x_advance);
     // Round run widths if subpixel positioning is off to match native behavior.
     if (!run->render_params.subpixel_positioning)
       run->width = std::floor(run->width + 0.5f);
diff --git a/ui/gfx/skia_util.cc b/ui/gfx/skia_util.cc
index c1e6c18..a971c9f 100644
--- a/ui/gfx/skia_util.cc
+++ b/ui/gfx/skia_util.cc
@@ -7,6 +7,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include "base/numerics/safe_conversions.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkColorFilter.h"
 #include "third_party/skia/include/core/SkColorPriv.h"
@@ -226,4 +227,21 @@
   points[3] = PointFToSkPoint(quad.p4());
 }
 
+// We treat HarfBuzz ints as 16.16 fixed-point.
+static const int kHbUnit1 = 1 << 16;
+
+int SkiaScalarToHarfBuzzUnits(SkScalar value) {
+  return base::saturated_cast<int>(value * kHbUnit1);
+}
+
+SkScalar HarfBuzzUnitsToSkiaScalar(int value) {
+  static const SkScalar kSkToHbRatio = SK_Scalar1 / kHbUnit1;
+  return kSkToHbRatio * value;
+}
+
+float HarfBuzzUnitsToFloat(int value) {
+  static const float kFloatToHbRatio = 1.0f / kHbUnit1;
+  return kFloatToHbRatio * value;
+}
+
 }  // namespace gfx
diff --git a/ui/gfx/skia_util.h b/ui/gfx/skia_util.h
index 25c96d03..1953e635 100644
--- a/ui/gfx/skia_util.h
+++ b/ui/gfx/skia_util.h
@@ -88,6 +88,15 @@
                                   int pixel_width,
                                   unsigned char* rgba);
 
+// Converts a Skia floating-point value to an int appropriate for hb_position_t.
+GFX_EXPORT int SkiaScalarToHarfBuzzUnits(SkScalar value);
+
+// Converts an hb_position_t to a Skia floating-point value.
+GFX_EXPORT SkScalar HarfBuzzUnitsToSkiaScalar(int value);
+
+// Converts an hb_position_t to a float.
+GFX_EXPORT float HarfBuzzUnitsToFloat(int value);
+
 }  // namespace gfx
 
 #endif  // UI_GFX_SKIA_UTIL_H_
diff --git a/ui/shell_dialogs/BUILD.gn b/ui/shell_dialogs/BUILD.gn
index 06ca709..ec6b56d 100644
--- a/ui/shell_dialogs/BUILD.gn
+++ b/ui/shell_dialogs/BUILD.gn
@@ -63,13 +63,6 @@
     include_dirs = [ "$root_gen_dir/ui" ]
     libs = [ "jnigraphics" ]
   }
-
-  if (is_android && use_aura) {
-    sources += [
-      "select_file_dialog_auraandroid.cc",
-      "select_file_dialog_auraandroid.h",
-    ]
-  }
 }
 
 test("shell_dialogs_unittests") {
diff --git a/ui/shell_dialogs/select_file_dialog.cc b/ui/shell_dialogs/select_file_dialog.cc
index 2bfacec..fd2a7cf6 100644
--- a/ui/shell_dialogs/select_file_dialog.cc
+++ b/ui/shell_dialogs/select_file_dialog.cc
@@ -14,16 +14,6 @@
 #include "ui/shell_dialogs/select_file_policy.h"
 #include "ui/shell_dialogs/selected_file_info.h"
 
-#if defined(OS_WIN)
-#include "ui/shell_dialogs/select_file_dialog_win.h"
-#elif defined(OS_MACOSX)
-#include "ui/shell_dialogs/select_file_dialog_mac.h"
-#elif defined(OS_ANDROID)
-#include "ui/shell_dialogs/select_file_dialog_android.h"
-#elif defined(USE_AURA) && defined(OS_LINUX) && !defined(OS_CHROMEOS)
-#include "ui/shell_dialogs/shell_dialog_linux.h"
-#endif
-
 namespace {
 
 // Optional dialog factory. Leaked.
@@ -79,22 +69,7 @@
       return dialog;
   }
 
-#if defined(USE_AURA) && defined(OS_LINUX) && !defined(OS_CHROMEOS)
-  const ui::ShellDialogLinux* shell_dialogs = ui::ShellDialogLinux::instance();
-  if (shell_dialogs)
-    return shell_dialogs->CreateSelectFileDialog(listener, policy);
-#endif
-
-#if defined(OS_WIN)
-  return CreateDefaultWinSelectFileDialog(listener, policy);
-#elif defined(OS_MACOSX) && !defined(USE_AURA)
-  return CreateMacSelectFileDialog(listener, policy);
-#elif defined(OS_ANDROID)
-  return CreateAndroidSelectFileDialog(listener, policy);
-#else
-  NOTIMPLEMENTED();
-  return NULL;
-#endif
+  return CreateSelectFileDialog(listener, policy);
 }
 
 void SelectFileDialog::SelectFile(
diff --git a/ui/shell_dialogs/select_file_dialog.h b/ui/shell_dialogs/select_file_dialog.h
index 041fb4a..e89f686 100644
--- a/ui/shell_dialogs/select_file_dialog.h
+++ b/ui/shell_dialogs/select_file_dialog.h
@@ -213,6 +213,8 @@
   DISALLOW_COPY_AND_ASSIGN(SelectFileDialog);
 };
 
+SelectFileDialog* CreateSelectFileDialog(SelectFileDialog::Listener* listener,
+                                         SelectFilePolicy* policy);
 }  // namespace ui
 
 #endif  // UI_SHELL_DIALOGS_SELECT_FILE_DIALOG_H_
diff --git a/ui/shell_dialogs/select_file_dialog_android.cc b/ui/shell_dialogs/select_file_dialog_android.cc
index b0c7532..11b9d4c 100644
--- a/ui/shell_dialogs/select_file_dialog_android.cc
+++ b/ui/shell_dialogs/select_file_dialog_android.cc
@@ -145,9 +145,8 @@
   return false;
 }
 
-SelectFileDialog* CreateAndroidSelectFileDialog(
-    SelectFileDialog::Listener* listener,
-    SelectFilePolicy* policy) {
+SelectFileDialog* CreateSelectFileDialog(SelectFileDialog::Listener* listener,
+                                         SelectFilePolicy* policy) {
   return SelectFileDialogImpl::Create(listener, policy);
 }
 
diff --git a/ui/shell_dialogs/select_file_dialog_android.h b/ui/shell_dialogs/select_file_dialog_android.h
index 0dba18e..5291cd3 100644
--- a/ui/shell_dialogs/select_file_dialog_android.h
+++ b/ui/shell_dialogs/select_file_dialog_android.h
@@ -65,10 +65,6 @@
   DISALLOW_COPY_AND_ASSIGN(SelectFileDialogImpl);
 };
 
-SelectFileDialog* CreateAndroidSelectFileDialog(
-    SelectFileDialog::Listener* listener,
-    SelectFilePolicy* policy);
-
 }  // namespace ui
 
 #endif  // UI_SHELL_DIALOGS_ANDROID_SELECT_FILE_DIALOG_ANDROID_H_
diff --git a/ui/shell_dialogs/select_file_dialog_auraandroid.cc b/ui/shell_dialogs/select_file_dialog_auraandroid.cc
deleted file mode 100644
index 185f47e..0000000
--- a/ui/shell_dialogs/select_file_dialog_auraandroid.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "select_file_dialog_auraandroid.h"
-
-#include "base/logging.h"
-
-namespace ui {
-
-// static
-SelectFileDialogImpl* SelectFileDialogImpl::Create(Listener* listener,
-                                                   SelectFilePolicy* policy) {
-  return new SelectFileDialogImpl(listener, policy);
-}
-
-bool SelectFileDialogImpl::IsRunning(gfx::NativeWindow) const {
-  return listener_;
-}
-
-void SelectFileDialogImpl::ListenerDestroyed() {
-  listener_ = NULL;
-}
-
-void SelectFileDialogImpl::SelectFileImpl(
-    SelectFileDialog::Type type,
-    const base::string16& title,
-    const base::FilePath& default_path,
-    const SelectFileDialog::FileTypeInfo* file_types,
-    int file_type_index,
-    const std::string& default_extension,
-    gfx::NativeWindow owning_window,
-    void* params) {
-  NOTIMPLEMENTED();
-}
-
-SelectFileDialogImpl::~SelectFileDialogImpl() {
-}
-
-SelectFileDialogImpl::SelectFileDialogImpl(Listener* listener,
-                                           SelectFilePolicy* policy)
-    : SelectFileDialog(listener, policy) {
-}
-
-bool SelectFileDialogImpl::HasMultipleFileTypeChoicesImpl() {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-SelectFileDialog* CreateAndroidSelectFileDialog(
-    SelectFileDialog::Listener* listener,
-    SelectFilePolicy* policy) {
-  return SelectFileDialogImpl::Create(listener, policy);
-}
-
-}  // namespace ui
diff --git a/ui/shell_dialogs/select_file_dialog_auraandroid.h b/ui/shell_dialogs/select_file_dialog_auraandroid.h
deleted file mode 100644
index 5b7a163..0000000
--- a/ui/shell_dialogs/select_file_dialog_auraandroid.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_SHELL_DIALOGS_ANDROID_SELECT_FILE_DIALOG_ANDROID_H_
-#define UI_SHELL_DIALOGS_ANDROID_SELECT_FILE_DIALOG_ANDROID_H_
-
-#include "base/macros.h"
-#include "ui/shell_dialogs/select_file_dialog.h"
-
-namespace ui {
-
-class SelectFileDialogImpl : public SelectFileDialog {
- public:
-  static SelectFileDialogImpl* Create(Listener* listener,
-                                      SelectFilePolicy* policy);
-
-  // From SelectFileDialog
-  bool IsRunning(gfx::NativeWindow) const override;
-  void ListenerDestroyed() override;
-  void SelectFileImpl(SelectFileDialog::Type type,
-                      const base::string16& title,
-                      const base::FilePath& default_path,
-                      const SelectFileDialog::FileTypeInfo* file_types,
-                      int file_type_index,
-                      const std::string& default_extension,
-                      gfx::NativeWindow owning_window,
-                      void* params) override;
-
- protected:
-  ~SelectFileDialogImpl() override;
-
- private:
-  SelectFileDialogImpl(Listener* listener,  SelectFilePolicy* policy);
-
-  bool HasMultipleFileTypeChoicesImpl() override;
-
-  DISALLOW_COPY_AND_ASSIGN(SelectFileDialogImpl);
-};
-
-SelectFileDialog* CreateAndroidSelectFileDialog(
-    SelectFileDialog::Listener* listener,
-    SelectFilePolicy* policy);
-
-}  // namespace ui
-
-#endif  // UI_SHELL_DIALOGS_ANDROID_SELECT_FILE_DIALOG_ANDROID_H_
-
diff --git a/ui/shell_dialogs/select_file_dialog_mac.h b/ui/shell_dialogs/select_file_dialog_mac.h
index 8915a08..2527f96 100644
--- a/ui/shell_dialogs/select_file_dialog_mac.h
+++ b/ui/shell_dialogs/select_file_dialog_mac.h
@@ -5,14 +5,91 @@
 #ifndef UI_SHELL_DIALOGS_SELECT_FILE_DIALOG_MAC_H_
 #define UI_SHELL_DIALOGS_SELECT_FILE_DIALOG_MAC_H_
 
+#import <Cocoa/Cocoa.h>
+
+#include <map>
+#include <set>
+
+#import "base/mac/scoped_nsobject.h"
+#include "base/macros.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/shell_dialogs/select_file_dialog.h"
 
+@class ExtensionDropdownHandler;
+@class SelectFileDialogBridge;
+
 namespace ui {
 
-SelectFileDialog* CreateMacSelectFileDialog(
-    SelectFileDialog::Listener* listener,
-    SelectFilePolicy* policy);
+// Implementation of SelectFileDialog that shows Cocoa dialogs for choosing a
+// file or folder.
+class SelectFileDialogImpl : public ui::SelectFileDialog {
+ public:
+  SelectFileDialogImpl(Listener* listener, ui::SelectFilePolicy* policy);
+
+  // BaseShellDialog implementation.
+  bool IsRunning(gfx::NativeWindow parent_window) const override;
+  void ListenerDestroyed() override;
+
+  // Callback from ObjC bridge.
+  void FileWasSelected(NSSavePanel* dialog,
+                       NSWindow* parent_window,
+                       bool was_cancelled,
+                       bool is_multi,
+                       const std::vector<base::FilePath>& files,
+                       int index);
+
+ protected:
+  // SelectFileDialog implementation.
+  // |params| is user data we pass back via the Listener interface.
+  void SelectFileImpl(Type type,
+                      const base::string16& title,
+                      const base::FilePath& default_path,
+                      const FileTypeInfo* file_types,
+                      int file_type_index,
+                      const base::FilePath::StringType& default_extension,
+                      gfx::NativeWindow owning_window,
+                      void* params) override;
+
+ private:
+  // Struct to store data associated with a file dialog while it is showing.
+  struct DialogData {
+    DialogData(void* params_,
+               base::scoped_nsobject<ExtensionDropdownHandler> handler);
+
+    // |params| user data associated with this file dialog.
+    void* params;
+
+    // Extension dropdown handler corresponding to this file dialog.
+    base::scoped_nsobject<ExtensionDropdownHandler> extension_dropdown_handler;
+
+    ~DialogData();
+  };
+
+  ~SelectFileDialogImpl() override;
+
+  // Sets the accessory view for the |dialog| and returns the associated
+  // ExtensionDropdownHandler.
+  static base::scoped_nsobject<ExtensionDropdownHandler> SetAccessoryView(
+      NSSavePanel* dialog,
+      const FileTypeInfo* file_types,
+      int file_type_index,
+      const base::FilePath::StringType& default_extension);
+
+  bool HasMultipleFileTypeChoicesImpl() override;
+
+  // The bridge for results from Cocoa to return to us.
+  base::scoped_nsobject<SelectFileDialogBridge> bridge_;
+
+  // The set of all parent windows for which we are currently running dialogs.
+  std::set<NSWindow*> parents_;
+
+  // A map from file dialogs to the DialogData associated with them.
+  std::map<NSSavePanel*, DialogData> dialog_data_map_;
+
+  bool hasMultipleFileTypeChoices_;
+
+  DISALLOW_COPY_AND_ASSIGN(SelectFileDialogImpl);
+};
 
 }  // namespace ui
 
diff --git a/ui/shell_dialogs/select_file_dialog_mac.mm b/ui/shell_dialogs/select_file_dialog_mac.mm
index e53c389..2a4167c 100644
--- a/ui/shell_dialogs/select_file_dialog_mac.mm
+++ b/ui/shell_dialogs/select_file_dialog_mac.mm
@@ -2,14 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/shell_dialogs/select_file_dialog.h"
+#include "ui/shell_dialogs/select_file_dialog_mac.h"
 
-#import <Cocoa/Cocoa.h>
 #include <CoreServices/CoreServices.h>
 #include <stddef.h>
 
-#include <map>
-#include <set>
 #include <vector>
 
 #include "base/files/file_util.h"
@@ -18,8 +15,6 @@
 #include "base/mac/bundle_locations.h"
 #include "base/mac/foundation_util.h"
 #include "base/mac/scoped_cftyperef.h"
-#import "base/mac/scoped_nsobject.h"
-#include "base/macros.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_restrictions.h"
@@ -55,16 +50,14 @@
 
 }  // namespace
 
-class SelectFileDialogImpl;
-
 // A bridge class to act as the modal delegate to the save/open sheet and send
 // the results to the C++ class.
 @interface SelectFileDialogBridge : NSObject<NSOpenSavePanelDelegate> {
  @private
-  SelectFileDialogImpl* selectFileDialogImpl_;  // WEAK; owns us
+  ui::SelectFileDialogImpl* selectFileDialogImpl_;  // WEAK; owns us
 }
 
-- (id)initWithSelectFileDialogImpl:(SelectFileDialogImpl*)s;
+- (id)initWithSelectFileDialogImpl:(ui::SelectFileDialogImpl*)s;
 - (void)endedPanel:(NSSavePanel*)panel
          didCancel:(bool)did_cancel
               type:(ui::SelectFileDialog::Type)type
@@ -92,76 +85,7 @@
 - (void)popupAction:(id)sender;
 @end
 
-// Implementation of SelectFileDialog that shows Cocoa dialogs for choosing a
-// file or folder.
-class SelectFileDialogImpl : public ui::SelectFileDialog {
- public:
-  explicit SelectFileDialogImpl(Listener* listener,
-                                ui::SelectFilePolicy* policy);
-
-  // BaseShellDialog implementation.
-  bool IsRunning(gfx::NativeWindow parent_window) const override;
-  void ListenerDestroyed() override;
-
-  // Callback from ObjC bridge.
-  void FileWasSelected(NSSavePanel* dialog,
-                       NSWindow* parent_window,
-                       bool was_cancelled,
-                       bool is_multi,
-                       const std::vector<base::FilePath>& files,
-                       int index);
-
- protected:
-  // SelectFileDialog implementation.
-  // |params| is user data we pass back via the Listener interface.
-  void SelectFileImpl(Type type,
-                      const base::string16& title,
-                      const base::FilePath& default_path,
-                      const FileTypeInfo* file_types,
-                      int file_type_index,
-                      const base::FilePath::StringType& default_extension,
-                      gfx::NativeWindow owning_window,
-                      void* params) override;
-
- private:
-  // Struct to store data associated with a file dialog while it is showing.
-  struct DialogData {
-    DialogData(void* params_,
-               base::scoped_nsobject<ExtensionDropdownHandler> handler)
-        : params(params_), extension_dropdown_handler(handler) {}
-
-    // |params| user data associated with this file dialog.
-    void* params;
-
-    // Extension dropdown handler corresponding to this file dialog.
-    base::scoped_nsobject<ExtensionDropdownHandler> extension_dropdown_handler;
-  };
-
-  ~SelectFileDialogImpl() override;
-
-  // Sets the accessory view for the |dialog| and returns the associated
-  // ExtensionDropdownHandler.
-  static base::scoped_nsobject<ExtensionDropdownHandler> SetAccessoryView(
-      NSSavePanel* dialog,
-      const FileTypeInfo* file_types,
-      int file_type_index,
-      const base::FilePath::StringType& default_extension);
-
-  bool HasMultipleFileTypeChoicesImpl() override;
-
-  // The bridge for results from Cocoa to return to us.
-  base::scoped_nsobject<SelectFileDialogBridge> bridge_;
-
-  // The set of all parent windows for which we are currently running dialogs.
-  std::set<NSWindow*> parents_;
-
-  // A map from file dialogs to the DialogData associated with them.
-  std::map<NSSavePanel*, DialogData> dialog_data_map_;
-
-  bool hasMultipleFileTypeChoices_;
-
-  DISALLOW_COPY_AND_ASSIGN(SelectFileDialogImpl);
-};
+namespace ui {
 
 SelectFileDialogImpl::SelectFileDialogImpl(Listener* listener,
                                            ui::SelectFilePolicy* policy)
@@ -319,6 +243,13 @@
   }];
 }
 
+SelectFileDialogImpl::DialogData::DialogData(
+    void* params_,
+    base::scoped_nsobject<ExtensionDropdownHandler> handler)
+    : params(params_), extension_dropdown_handler(handler) {}
+
+SelectFileDialogImpl::DialogData::~DialogData() {}
+
 SelectFileDialogImpl::~SelectFileDialogImpl() {
   // Walk through the open dialogs and close them all.  Use a temporary vector
   // to hold the pointers, since we can't delete from the map as we're iterating
@@ -429,9 +360,16 @@
   return hasMultipleFileTypeChoices_;
 }
 
+SelectFileDialog* CreateSelectFileDialog(SelectFileDialog::Listener* listener,
+                                         SelectFilePolicy* policy) {
+  return new SelectFileDialogImpl(listener, policy);
+}
+
+}  // namespace ui
+
 @implementation SelectFileDialogBridge
 
-- (id)initWithSelectFileDialogImpl:(SelectFileDialogImpl*)s {
+- (id)initWithSelectFileDialogImpl:(ui::SelectFileDialogImpl*)s {
   if ((self = [super init])) {
     selectFileDialogImpl_ = s;
   }
@@ -509,13 +447,3 @@
 }
 
 @end
-
-namespace ui {
-
-SelectFileDialog* CreateMacSelectFileDialog(
-    SelectFileDialog::Listener* listener,
-    SelectFilePolicy* policy) {
-  return new SelectFileDialogImpl(listener, policy);
-}
-
-}  // namespace ui
diff --git a/ui/shell_dialogs/select_file_dialog_win.cc b/ui/shell_dialogs/select_file_dialog_win.cc
index dafe050..d455f59c 100644
--- a/ui/shell_dialogs/select_file_dialog_win.cc
+++ b/ui/shell_dialogs/select_file_dialog_win.cc
@@ -706,9 +706,8 @@
       listener, policy, get_open_file_name_impl, get_save_file_name_impl);
 }
 
-SelectFileDialog* CreateDefaultWinSelectFileDialog(
-    SelectFileDialog::Listener* listener,
-    SelectFilePolicy* policy) {
+SelectFileDialog* CreateSelectFileDialog(SelectFileDialog::Listener* listener,
+                                         SelectFilePolicy* policy) {
   return CreateWinSelectFileDialog(listener,
                                    policy,
                                    base::Bind(&CallBuiltinGetOpenFileName),
diff --git a/ui/shell_dialogs/select_file_dialog_win.h b/ui/shell_dialogs/select_file_dialog_win.h
index 646bdb1..e066c65f 100644
--- a/ui/shell_dialogs/select_file_dialog_win.h
+++ b/ui/shell_dialogs/select_file_dialog_win.h
@@ -28,10 +28,6 @@
     const base::Callback<bool(OPENFILENAME* ofn)>& get_open_file_name_impl,
     const base::Callback<bool(OPENFILENAME* ofn)>& get_save_file_name_impl);
 
-SelectFileDialog* CreateDefaultWinSelectFileDialog(
-    SelectFileDialog::Listener* listener,
-    SelectFilePolicy* policy);
-
 }  // namespace ui
 
 #endif  //  UI_SHELL_DIALOGS_SELECT_FILE_DIALOG_WIN_H_
diff --git a/ui/shell_dialogs/shell_dialog_linux.cc b/ui/shell_dialogs/shell_dialog_linux.cc
index 62bee5b..685369c 100644
--- a/ui/shell_dialogs/shell_dialog_linux.cc
+++ b/ui/shell_dialogs/shell_dialog_linux.cc
@@ -20,4 +20,15 @@
   return g_shell_dialog_linux;
 }
 
+SelectFileDialog* CreateSelectFileDialog(SelectFileDialog::Listener* listener,
+                                         SelectFilePolicy* policy) {
+#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+  const ui::ShellDialogLinux* shell_dialogs = ui::ShellDialogLinux::instance();
+  if (shell_dialogs)
+    return shell_dialogs->CreateSelectFileDialog(listener, policy);
+#endif
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
 }  // namespace ui
diff --git a/ui/views/animation/ink_drop_host_view.cc b/ui/views/animation/ink_drop_host_view.cc
index bd219a0..77e28178 100644
--- a/ui/views/animation/ink_drop_host_view.cc
+++ b/ui/views/animation/ink_drop_host_view.cc
@@ -11,12 +11,12 @@
 namespace views {
 
 // Default sizes for ink drop effects.
-const int kInkDropLargeSize = 32;
+const int kInkDropSize = 24;
 const int kInkDropLargeCornerRadius = 4;
-const int kInkDropSmallSize = 24;
 const int kInkDropSmallCornerRadius = 2;
 
-InkDropHostView::InkDropHostView() {}
+InkDropHostView::InkDropHostView()
+    : ink_drop_size_(kInkDropSize, kInkDropSize) {}
 
 InkDropHostView::~InkDropHostView() {}
 
@@ -33,18 +33,19 @@
 }
 
 scoped_ptr<InkDropAnimation> InkDropHostView::CreateInkDropAnimation() const {
+  gfx::Size large_drop(ink_drop_size_.width() * 4 / 3,
+                       ink_drop_size_.height() * 4 / 3);
+
   scoped_ptr<InkDropAnimation> animation(new SquareInkDropAnimation(
-      gfx::Size(kInkDropLargeSize, kInkDropLargeSize),
-      kInkDropLargeCornerRadius,
-      gfx::Size(kInkDropSmallSize, kInkDropSmallSize),
+      large_drop, kInkDropLargeCornerRadius, ink_drop_size_,
       kInkDropSmallCornerRadius, GetInkDropCenter(), GetInkDropBaseColor()));
   return animation;
 }
 
 scoped_ptr<InkDropHover> InkDropHostView::CreateInkDropHover() const {
-  scoped_ptr<InkDropHover> hover(new InkDropHover(
-      gfx::Size(kInkDropSmallSize, kInkDropSmallSize),
-      kInkDropSmallCornerRadius, GetInkDropCenter(), GetInkDropBaseColor()));
+  scoped_ptr<InkDropHover> hover(
+      new InkDropHover(ink_drop_size_, kInkDropSmallCornerRadius,
+                       GetInkDropCenter(), GetInkDropBaseColor()));
   return hover;
 }
 
diff --git a/ui/views/animation/ink_drop_host_view.h b/ui/views/animation/ink_drop_host_view.h
index 87832b7..9467d1e 100644
--- a/ui/views/animation/ink_drop_host_view.h
+++ b/ui/views/animation/ink_drop_host_view.h
@@ -7,6 +7,7 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/geometry/size.h"
 #include "ui/views/animation/ink_drop_host.h"
 #include "ui/views/view.h"
 
@@ -27,6 +28,8 @@
   scoped_ptr<InkDropAnimation> CreateInkDropAnimation() const override;
   scoped_ptr<InkDropHover> CreateInkDropHover() const override;
 
+  void set_ink_drop_size(const gfx::Size& size) { ink_drop_size_ = size; }
+
  protected:
   // Overrideable methods to allow views to provide minor tweaks to the default
   // ink drop.
@@ -34,6 +37,8 @@
   virtual SkColor GetInkDropBaseColor() const;
 
  private:
+  gfx::Size ink_drop_size_;
+
   DISALLOW_COPY_AND_ASSIGN(InkDropHostView);
 };
 }
diff --git a/ui/views/cocoa/bridged_native_widget_unittest.mm b/ui/views/cocoa/bridged_native_widget_unittest.mm
index 5b39b511..7723f238 100644
--- a/ui/views/cocoa/bridged_native_widget_unittest.mm
+++ b/ui/views/cocoa/bridged_native_widget_unittest.mm
@@ -279,6 +279,8 @@
 }
 
 void BridgedNativeWidgetTest::TearDown() {
+  if (bridge())
+    bridge()->SetRootView(nullptr);
   view_.reset();
   BridgedNativeWidgetTestBase::TearDown();
 }
diff --git a/ui/views/controls/button/custom_button.h b/ui/views/controls/button/custom_button.h
index dfd0384..fa0a215 100644
--- a/ui/views/controls/button/custom_button.h
+++ b/ui/views/controls/button/custom_button.h
@@ -103,6 +103,8 @@
   // Overridden from gfx::AnimationDelegate:
   void AnimationProgressed(const gfx::Animation* animation) override;
 
+  InkDropDelegate* ink_drop_delegate() const { return ink_drop_delegate_; }
+
  protected:
   // Construct the Button with a Listener. See comment for Button's ctor.
   explicit CustomButton(ButtonListener* listener);
@@ -135,7 +137,6 @@
   // state). This does not take into account enabled state.
   bool ShouldEnterHoveredState();
 
-  InkDropDelegate* ink_drop_delegate() const { return ink_drop_delegate_; }
   void set_ink_drop_delegate(InkDropDelegate* ink_drop_delegate) {
     ink_drop_delegate_ = ink_drop_delegate;
   }
diff --git a/ui/views/widget/native_widget_mac_unittest.mm b/ui/views/widget/native_widget_mac_unittest.mm
index 635de89..e62394e 100644
--- a/ui/views/widget/native_widget_mac_unittest.mm
+++ b/ui/views/widget/native_widget_mac_unittest.mm
@@ -555,12 +555,12 @@
   [[native_parent contentView] addSubview:anchor_view];
 
   // Note: Don't use WidgetTest::CreateChildPlatformWidget because that makes
-  // windows of TYPE_CONTROL which are automatically made visible. But still
-  // mark it as a child to test window positioning.
+  // windows of TYPE_CONTROL which need a parent Widget to obtain the focus
+  // manager.
   Widget* child = new Widget;
   Widget::InitParams init_params;
   init_params.parent = anchor_view;
-  init_params.child = true;
+  init_params.type = Widget::InitParams::TYPE_POPUP;
   child->Init(init_params);
 
   TestWidgetObserver child_observer(child);
@@ -577,7 +577,8 @@
       NativeWidgetMac::GetBridgeForNativeWindow(child->GetNativeWindow());
   EXPECT_EQ(native_parent, bridged_native_widget->parent()->GetNSWindow());
 
-  child->SetBounds(gfx::Rect(50, 50, 200, 100));
+  const gfx::Rect child_bounds(50, 50, 200, 100);
+  child->SetBounds(child_bounds);
   EXPECT_FALSE(child->IsVisible());
   EXPECT_EQ(0u, [[native_parent childWindows] count]);
 
@@ -588,11 +589,9 @@
             [[native_parent childWindows] objectAtIndex:0]);
   EXPECT_EQ(native_parent, [child->GetNativeWindow() parentWindow]);
 
-  // Child should be positioned on screen relative to the parent, but note we
-  // positioned the parent in Cocoa coordinates, so we need to convert.
-  gfx::Point parent_origin = gfx::ScreenRectFromNSRect(ParentRect()).origin();
-  EXPECT_EQ(gfx::Rect(150, parent_origin.y() + 50, 200, 100),
-            child->GetWindowBoundsInScreen());
+  // Only non-toplevel Widgets are positioned relative to the parent, so the
+  // bounds set above should be in screen coordinates.
+  EXPECT_EQ(child_bounds, child->GetWindowBoundsInScreen());
 
   // Removing the anchor_view from its view hierarchy is permitted. This should
   // not break the relationship between the two windows.
diff --git a/ui/webui/resources/cr_elements/cr_shared_menu/compiled_resources2.gyp b/ui/webui/resources/cr_elements/cr_shared_menu/compiled_resources2.gyp
index c401345..bcfaa7c1 100644
--- a/ui/webui/resources/cr_elements/cr_shared_menu/compiled_resources2.gyp
+++ b/ui/webui/resources/cr_elements/cr_shared_menu/compiled_resources2.gyp
@@ -6,10 +6,10 @@
     {
       'target_name': 'cr_shared_menu',
       'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
-        '<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:position_util',
+        '../../js/compiled_resources2.gyp:assert',
+        '../../js/compiled_resources2.gyp:cr',
+        '../../js/compiled_resources2.gyp:util',
+        '../../js/cr/ui/compiled_resources2.gyp:position_util',
       ],
       'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
diff --git a/ui/webui/resources/js/cr/ui/splitter.js b/ui/webui/resources/js/cr/ui/splitter.js
index aacfacee..c457e421 100644
--- a/ui/webui/resources/js/cr/ui/splitter.js
+++ b/ui/webui/resources/js/cr/ui/splitter.js
@@ -71,6 +71,15 @@
                             true);
       this.addEventListener('touchstart', this.handleTouchStart_.bind(this),
                             true);
+      this.resizeNextElement_ = false;
+    },
+
+    /**
+     * @param {boolean} resizeNext True if resize the next element.
+     *     By default, splitter resizes previous (left) element.
+     */
+    set resizeNextElement(resizeNext) {
+      this.resizeNextElement_ = resizeNext;
     },
 
     /**
@@ -129,6 +138,25 @@
     },
 
     /**
+     * @return {Element}
+     * @private
+     */
+    getResizeTarget_: function() {
+      return this.resizeNextElement_ ? this.nextElementSibling :
+                                       this.previousElementSibling;
+    },
+
+    /**
+     * Calculate width to resize target element.
+     * @param {number} deltaX horizontal drag amount
+     * @return {number}
+     * @private
+     */
+    calcDeltaX_: function(deltaX) {
+      return this.resizeNextElement_ ? -deltaX : deltaX;
+    },
+
+    /**
      * Handles the mousedown event which starts the dragging of the splitter.
      * @param {!Event} e The mouse event.
      * @private
@@ -205,10 +233,10 @@
     handleSplitterDragStart: function() {
       // Use the computed width style as the base so that we can ignore what
       // box sizing the element has.
-      var leftComponent = this.previousElementSibling;
-      var doc = leftComponent.ownerDocument;
+      var targetElement = this.getResizeTarget_();
+      var doc = targetElement.ownerDocument;
       this.startWidth_ = parseFloat(
-          doc.defaultView.getComputedStyle(leftComponent).width);
+          doc.defaultView.getComputedStyle(targetElement).width);
     },
 
     /**
@@ -217,8 +245,9 @@
      * @protected
      */
     handleSplitterDragMove: function(deltaX) {
-      var leftComponent = this.previousElementSibling;
-      leftComponent.style.width = this.startWidth_ + deltaX + 'px';
+      var targetElement = this.getResizeTarget_();
+      var newWidth = this.startWidth_ + this.calcDeltaX_(deltaX);
+      targetElement.style.width = newWidth + 'px';
     },
 
     /**
@@ -228,10 +257,10 @@
      */
     handleSplitterDragEnd: function() {
       // Check if the size changed.
-      var leftComponent = this.previousElementSibling;
-      var doc = leftComponent.ownerDocument;
+      var targetElement = this.getResizeTarget_();
+      var doc = targetElement.ownerDocument;
       var computedWidth = parseFloat(
-          doc.defaultView.getComputedStyle(leftComponent).width);
+          doc.defaultView.getComputedStyle(targetElement).width);
       if (this.startWidth_ != computedWidth)
         cr.dispatchSimpleEvent(this, 'resize');
     },